← Back to Writeups
HTBN/AReversing

remoose

XESXOR8/23/20264 min read
#reversing#htb#n/a

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
PortServiceVersionNotes
<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

  1. Elf_header_repair
  2. Null_byte_restoration
  3. 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

  1. N/A for challenge-type writeup; see exploitation above.
  2. Flag obtained via challenge solve.
<command>

Flags

FlagLocationValue
flagREDACTED

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 0x00 bytes 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:

  1. main calls flag(), flag1(), flag2(), flag3(), flag4() in sequence
  2. Each function makes a series of putchar() calls with immediate character values as arguments
  3. 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:

FunctionCharacters
flagt, j, c, t
flag1f, {, 5, m
flag2a, 1, 1, _
flag3m, 0, 0, s
flag43, }

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-revise to fold lessons into XESXor_Methodology.md.

signed by XESXOR