← Back to Portfolio CTF Writeup
TryHackMe

Flag Vault

PWN Binary Exploitation Buffer Overflow
TargetC login binary reading credentials with gets()
VulnerabilityStack buffer overflow into an adjacent buffer
SeverityHIGH
ReferencesCWE-121 · CWE-676 · OWASP A04:2021
Toolspwntools (Python)
FlagTHM{password_0v3rfl0w}

1. The Binary

The challenge ships a small C login program. It declares two adjacent character buffers and reads input into the first using the unbounded gets() function. Crucially, the line that would read the user's password is commented out — meaning the password buffer is never populated through legitimate input, and a normal login can never succeed.

char password[100]; // declared FIRST char username[100]; // declared SECOND gets(username); // unbounded read into username // gets(password); // commented out: never runs if (strcmp(username, password) == 0) { print_flag(); }

2. Understanding the Stack Layout

The exploit hinges on memory ordering. password[100] is declared first, placing it at a higher address on the stack; username[100] sits below it. On a downward-growing stack, writing past the end of username spills upward into the adjacent password buffer.

Because gets() imposes no length limit, supplying more than 100 bytes overflows username and writes into password. The strcmp then compares username against password — both of which we now control.

RegionSizeRelative AddressFilled by us
username[100]100 bytesLowerYes (padding)
password[100]100 bytesHigherYes (overflow)

3. Crafting the Overflow

The goal is to make username and password compare equal. Fill the 100-byte username buffer with padding, then continue with a known marker that lands in the password buffer. Both buffers end up holding the same trailing bytes — but the cleaner approach is to fill the entire combined region with a single repeated value so the comparison region matches on both sides.

from pwn import * p = process('./vault') # or remote(host, port) # 100 bytes fills username; the next bytes overflow into password. # Sending a single repeated byte makes both compared buffers equal. payload = b'A' * 100 + b'A' * 100 p.sendline(payload) print(p.recvall().decode())

Sending 200 bytes of 'A' populates both buffers identically. strcmp(username, password) returns 0 and the flag is printed.

4. Flag

$ python3 exploit.py [+] Starting local process './vault' [+] Receiving all data: Done Access granted. THM{password_0v3rfl0w}
Key Takeaways
Attacker Perspective

Stack variables are laid out in predictable order. When gets() writes past the end of one buffer, it overwrites adjacent variables. No return address overwrite needed here — the target variable was right next door.

Defender / Remediation

Replace gets() with fgets(). Enable stack canaries (-fstack-protector-all). Use ASAN during development. gets() has been removed from C11 precisely because of this class of vulnerability.