remoose
remoose
Platform: Tjctf | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: NA | Author: D3v0o0Nu11 | Date: 2026-05-15 | Status: Solved Techniques: elf_header_repair, null_byte_restoration, static_disassembly_character_extraction
Summary
Task: a broken binary that won't run — 'one little thing' was changed. Solution: discover all 0x00 bytes were replaced with 0x20 (space) and ELF magic corrupted; restore nulls and fix header, then extract flag from putchar calls via static analysis.
Recon
Port scan
nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
| Port | Service | Version | Notes |
|---|---|---|---|
| <PORT> | <SVC> | <VER> | <notes> |
Enumeration highlights
- Event:
tjctf| ID:20260515_tjctf_remoose - Tags: static_analysis, elf, x86_64, binary_corruption, null_byte_replacement, putchar
- Indicators: file command reports 'data' instead of ELF, ELF magic bytes corrupted (0x4b instead of 0x46), binary contains zero null bytes and excessive 0x20 bytes, challenge hints at a single small change breaking the binary, functions named flag/flag1-4 calling putchar with immediate character values
- Source:
20260515_tjctf_remoose.md
Foothold
Vulnerability / Misconfiguration
- Elf_header_repair
- Null_byte_restoration
- Static_disassembly_character_extraction
<command>
Exploitation
- See original writeup content for detailed exploitation.
Privilege Escalation
Enumeration
sudo -l find / -perm -4000 2>/dev/null getcap -r / 2>/dev/null cat /etc/crontab ps aux
Exploitation
- N/A for challenge-type writeup; see exploitation above.
- Flag obtained via challenge solve.
<command>
Flags
| Flag | Location | Value |
|---|---|---|
| flag | REDACTED |
Key Takeaways / Lessons
- elf_header_repair
- null_byte_restoration
- static_disassembly_character_extraction
- Tags: static_analysis, elf, x86_64, binary_corruption, null_byte_replacement, putchar
Original Writeup
<details><summary>Click to expand original content</summary>Description
I changed just one little thing and my racing moose won't run anymore!
A single binary file chall (16808 bytes) is provided. The file command identifies it as "data" — not a valid executable. The goal is to figure out what was changed, fix the binary, and recover the flag.
Analysis
Initial Recon
The binary is not recognized as an ELF:
$ file chall
chall: data
Hex inspection of the first 16 bytes reveals the corruption:
$ xxd chall | head -1
00000000: 7f45 4c4b 0201 0120 2020 2020 2020 2020 .ELK...
The ELF magic should be 7f 45 4c 46 (.ELF) but byte 3 is 0x4b (.ELK) instead of 0x46. More importantly, the padding bytes that should be 0x00 are all 0x20 (space).
Identifying the Transformation
Counting byte occurrences confirms the pattern:
- Zero
0x00bytes in the entire file — impossible for a valid ELF which uses nulls extensively for padding, string terminators, and zero-valued header fields - 14106
0x20(space) bytes — far too many for a 16KB binary
The "one little thing" that was changed: all 0x00 null bytes were replaced with 0x20 (space). The ELF magic F (0x46) → K (0x4b) change is a +5 shift that's also consistent with the corruption pattern (though the primary transformation is the null-to-space replacement).
Solution
Step 1: Restore the Binary
Replace all 0x20 bytes back to 0x00 and fix the ELF magic byte:
#!/usr/bin/env python3
data = open('chall', 'rb').read()
fixed = bytearray(data)
# Restore all 0x20 (space) -> 0x00 (null)
for i in range(len(fixed)):
if fixed[i] == 0x20:
fixed[i] = 0x00
# Fix ELF magic: byte 3 should be 0x46 ('F'), not 0x4b ('K')
fixed[3] = 0x46
open('chall_fixed', 'wb').write(bytes(fixed))
After fixing:
$ file chall_fixed
chall_fixed: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV),
dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, not stripped
Note: This also zeroes out legitimate 0x20 bytes in string data (spaces become nulls), but the executable code and ELF structure are correctly restored since code bytes rarely contain 0x20.
Step 2: Static Analysis
The binary is not stripped and contains meaningful symbols: main, flag, flag1, flag2, flag3, flag4, plus imports for putchar and printf. The source file was chall.c.
Using radare2 for disassembly, the program logic is straightforward:
maincallsflag(),flag1(),flag2(),flag3(),flag4()in sequence- Each function makes a series of
putchar()calls with immediate character values as arguments - The characters spell out the flag when concatenated in order
Step 3: Extract the Flag
By reading the immediate values passed to putchar across all five functions:
| Function | Characters |
|---|---|
flag | t, j, c, t |
flag1 | f, {, 5, m |
flag2 | a, 1, 1, _ |
flag3 | m, 0, 0, s |
flag4 | 3, } |
Concatenated: tjctf{REDACTED}
This decodes as "small moose" in leetspeak (5→s, 1→l, 0→o, 3→e), fitting the "racing moose" theme perfectly.
</details>Auto-tracked: saved to WriteUps; run
/xesor-reviseto fold lessons into XESXor_Methodology.md.
signed by XESXOR