remoose
remoose
Platform: CUSTOM | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: elf_header_repair, null_byte_restoration, static_disassembly_character_extraction
Summary
Walkthrough of the CUSTOM Reversing remoose. 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 ext
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:
python read-only • copy allowed#!/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.
Key Takeaways / Lessons
- Mastering elf_header_repair, null_byte_restoration, static_disassembly_character_extraction was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2026-05-15 • CUSTOM • remoose • Difficulty: Easy