TexSAW CTF 2026 Whats the Time?
This Pwn challenge is a classic buffer overflow with a twist: the input is obfuscated via a time-based XOR operation before being copied to the stack.
Challenge Description
I think one of the hands of my watch broke. Can you tell me what the time is?
nc chals.texsaw.org 3000
Flag format:
texsaw{flag}
Solution
1. Binary Analysis
Using checksec, we identify the binary’s
protections:
- Arch: i386-32-little
- RELRO: Partial RELRO
- Stack: No canary found
- NX: NX enabled (cannot execute shellcode on the stack)
- PIE: PIE disabled (fixed addresses for code/data)
Since PIE is disabled and there is no stack canary, the primary goal
is a Return-to-PLT attack to call
system("/bin/sh").
2. Identifying Vulnerabilities
Disassembling the binary reveals two critical functions:
main and read_user_input.
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
1 | ssize_t __cdecl read_user_input(int key) |
Key Generation: In
main, the program takes the current Unix timestamp and rounds it down to the nearest minute:time_val = (time(0) / 60) * 60. This value is then passed intoread_user_input.The XOR Loop: Inside
read_user_input, the program reads up to 160 bytes into a heap buffer. It then iterates through the input, XORing every 4-byte chunk with thetime_val. Crucially, thetime_valincrements by 1 after every 4 bytes.Buffer Overflow: After XORing, the program uses
memcpyto copy the processed buffer into a local stack buffer (ebp-0x40). Since the stack buffer is only 64 bytes butmemcpycopies up to 160 bytes, we have a stack-based buffer overflow.
3. Exploitation Strategy
Step 1: Leaking the Key The program XORs our input
and then calls write to send 40 bytes of the stack buffer
back to us. To bypass the XOR obfuscation, we first send a string of
null bytes (\x00). Because x ^ 0 = x, the
server returns the XOR key itself. This allows us to recover the exact
time_val used by the server.
Step 2: Crafting the Payload We need to overwrite
the return address at ebp + 4. The distance from the buffer
start (ebp - 0x40) to the return address is 68
bytes.
Our desired stack layout after memcpy should be:
[68 bytes of padding] + [Address of system@plt] + [4 bytes of dummy return] + [Address of "/bin/sh"]
Step 3: Pre-XORing Because the program will XOR our
input before it hits the stack, we must “pre-XOR” our payload. If the
program expects Payload ^ Key = Stack, we must send
Payload ^ Key so that when the server XORs it with
Key, the result on the stack is our desired
Payload.
4. Script
1 | from pwn import * |