Challenge / Reversing

Exation

Exation is a sanitized challenge note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator

EasyPublished 2025-06-23Sanitized local writeup

Scenario

Exation attack path

Exation is a sanitized challenge note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator

Objective

Challenge walkthrough focused on Reversing evidence, validation, and reusable operator lessons.

Exation sanitized attack graph

Walkthrough flow

01

Extract the challenge archive and identify the single...

02

Detect UPX packing from the UPX! marker and high...

03

Unpack with upx -d into a separate analysis copy.

04

Use the recovered C++ symbols to inspect...

05

Identify the transform: for each input character,...

Source coverage

High source coverage

Status: complete. This article is generated from 6 sanitized Markdown sources and keeps raw flags, credentials, keys, cookies, and reusable secrets out of the rendered blog.

100% coverage
Evidence verdict

High confidence: the page is reconstructed from a primary walkthrough plus multiple supporting notes or evidence sources. Treat the chain as source-backed, while still checking the listed source files for sensitive values.

  • Reversing/Exation/writeup.md
  • htb-challenge/Reversing/Exation/notes.md
  • htb-challenge/Reversing/Exation/memory-summary.md
  • htb-challenge/Reversing/Exation/hypothesis-board.md
  • HTB/_knowledge/exports/ctf-lightrag-latest-203412/documents/challenge__Reversing__Exation__memory-summary.md.d3b95b7ca5.md
  • HTB/_knowledge/exports/ctf-lightrag-latest-203412/documents/challenge__Reversing__Exation__notes.md.3a4c8926d7.md

Technical Walkthrough

Writeup

Challenge

  • Name: Exation
  • Category: Reversing
  • Difficulty: Easy
  • Mode: file

Summary

Exation is a packed Linux reversing challenge. The provided executable is UPX-packed and stripped of section headers, which makes the original file noisy under strings and disassembly. After unpacking it with UPX, the binary exposes C++ symbols and the password check is straightforward: every input character is shifted left by four bits, converted to decimal text, and compared against a stored decimal string.

Artifact Inventory

Relevant artifacts:

  • files/a12c73b2-b72a-4f35-994b-447540ce62d6.zip: original HTB archive.
  • analysis/extracted/exatlon_v1: packed executable.
  • analysis/unpacked/exatlon_v1.unpacked: UPX-unpacked executable.
  • analysis/unpacked/exatlon-function.txt: focused disassembly of the transform routine.
  • analysis/unpacked/main-function.txt: focused disassembly of the input and compare routine.
  • solve/solve.py: reproducible flag recovery script.

Analysis

The initial file output identified a static Linux ELF with no section headers. Entropy was high and the binary header contained a UPX! marker, so the first useful step was unpacking:

bash
upx -d -o analysis/unpacked/exatlon_v1.unpacked analysis/extracted/exatlon_v1

The unpacked binary is not stripped. nm -C identifies two important symbols:

  • exatlon(std::string const&)
  • main

The exatlon() routine iterates over the supplied password string. For each character, it:

  1. loads the character,
  2. shifts its signed integer value left by four bits,
  3. converts that integer to decimal text with std::to_string,
  4. appends a single space.

In pseudocode:

python
def exatlon(password):
    out = ""
    for char in password: <redacted> += str(ord(char) << 4) + " "
    return out

main reads a password, calls exatlon(password), and compares the returned string to a decimal-number constant. Reversing the constant is therefore just tokenizing it and dividing each value by 16. The decoded password is already in HTB flag format.

Solve

Run:

bash
python3 Reversing/Exation/solve/solve.py \
  --flag-out Reversing/Exation/loot/flag-candidate.txt

Then capture it with the harness:

bash
python3 scripts/challenge_harness.py capture-flag Reversing/Exation --from loot/flag-candidate.txt

The solver reads the unpacked ELF, finds the long decimal-token constant, divides each token by 16, validates the result as an HTB-format flag, and writes the recovered value to the requested output path.

Flag

Raw flag is stored in loot/flag.txt and intentionally not reproduced here.

Lessons

  • Check for packing before spending time on noisy disassembly. The UPX! marker and high entropy were the fastest path to clarity.
  • UPX-unpacked binaries may recover symbols even when the packed input has no section headers.
  • When a password check converts input to a numeric representation, reversing the constant can be easier than running the binary.

Source-Backed Dossier

The sections below are merged from companion Markdown notes for the same case. They are rendered after sanitization so the article stays precise without publishing raw flags, credentials, or target-specific secrets.

Notes

Scope

  • Challenge: Exation
  • Category: Reversing
  • Difficulty: Easy
  • Mode: file
  • Remote instance: none
  • Start time: 2026-06-10T12:51:57Z
  • Operator: harness
  • State file: challenge-state.json

Harness Status

  • Current phase: see challenge-state.json
  • Next allowed actions: see next-action.json
  • Raw flags and sensitive material stay in loot/ only. Do not paste them here.

Artifact Inventory

FileSizeSHA256TypeNotes
files/a12c73b2-b72a-4f35-994b-447540ce62d6.zip695275<hash redacted>Zip archive data, at least v2.0 to extract, compression method=deflatezip entries: 1 shown in artifact inventory JSON

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-10T12:51:57Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-10T12:51:57Zartifact inventoryanalysis/artifact-inventory.json1 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-10T12:52:28Zhypothesis recordedhypothesis-board.mdRecover the expected password from the exatlon_v1 validation routine, then submit it to the binary to obtain the HTB flag.HighRun static triage with file/strings/objdump, inspect compare/transform constants, then build a solver that derives the password and executes the binary with that password.
2026-06-10T12:52:28Zresearch skipanalysis/research/research-skip.mdResearch intentionally skipped with recorded reasonMediumGate before exploit
2026-06-10T12:56:33Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-10T12:58:06Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

  • The archive contains one Linux x86-64 executable: exatlon_v1.
  • The original executable is UPX-packed, statically linked, and section-stripped.
  • upx -d successfully unpacked it to analysis/unpacked/exatlon_v1.unpacked.
  • The unpacked binary is statically linked but not stripped, exposing exatlon(std::string const&) and main.
  • exatlon() initializes an output string, then for each input character appends std::to_string(ord(char) << 4) followed by a space.
  • main compares that transformed input against a decimal-number string constant at the success branch.
  • Dividing each decimal token by 16 reconstructs the password, which is itself an HTB-format flag.
  • solve/solve.py extracts the numeric constant from the unpacked binary and writes the recovered flag candidate to loot/.

RAG / Advisory Memory

RAG output is advisory only. Record evaluated retrievals with:

bash
scripts/challenge_harness.py rag-record <workspace> --query "..." --tag MATCHED|PARTIAL|MISSING|<secret redacted>|GENERIC --validation "..."

Secrets/Flags

Raw flags and sensitive material stay in loot/ only. Use scripts/challenge_harness.py capture-flag to validate and record flag capture without printing the value.

Memory Summary

Metadata

  • Platform: HackTheBox Challenges
  • Category: Reversing
  • Challenge: Exation
  • Difficulty: Easy
  • Source workspace: <local workspace>

Validated Solve Chain

Concepts only. Do not include raw flags, reusable credentials, tokens, cookies, private keys, or live secrets.

  1. Extract the challenge archive and identify the single Linux x86-64 executable.
  2. Detect UPX packing from the UPX! marker and high entropy.
  3. Unpack with upx -d into a separate analysis copy.
  4. Use the recovered C++ symbols to inspect exatlon(std::string const&) and main.
  5. Identify the transform: for each input character, compute ord(char) << 4, convert to decimal, and append a space.
  6. Decode the stored decimal-token target by dividing each token by 16 and converting back to characters.
  7. The decoded password is already an HTB-format flag.

Reusable Lessons

  • For stripped/no-section ELF reversing challenges, check for UPX before treating disassembly noise as intentional obfuscation.
  • A long decimal-token compare constant often represents transformed input and can be inverted without dynamic execution.
  • Preserve the packed original and unpack into analysis/unpacked/.

Dead Ends

  • Direct strings/disassembly on the packed binary gave only noisy/interleaved prompt fragments and was not sufficient.

Tool Quirks

  • upx was installed via Homebrew during the solve.
  • The packed file had no section headers, but the UPX-unpacked copy restored useful symbols.

Evidence Paths

  • analysis/extracted/exatlon_v1
  • analysis/unpacked/exatlon_v1.unpacked
  • analysis/unpacked/upx-unpack.txt
  • analysis/unpacked/exatlon-function.txt
  • analysis/unpacked/main-function.txt
  • solve/solve.py
  • loot/flag.txt

Ingestion Decision

  • Proposed for LightRAG: yes
  • Requires user approval before ingestion: yes

Hypothesis Board

Keep no more than 3 active hypotheses on Easy/Medium and 5 on Hard unless the user explicitly asks for breadth.

RankPathEvidenceMissing ProofCheapest ValidationConfidenceStatus
1Recover the expected password from the exatlon_v1 validation routine, then submit it to the binary to obtain the HTB flag.Challenge asks to find the password; archive contains one executable named exatlon_v1.Need identify how the binary transforms or compares user input and whether successful execution prints the flag.Run static triage with file/strings/objdump, inspect compare/transform constants, then build a solver that derives the password and executes the binary with that password.HighActive

Closed Branches

BranchEvidence TestedFailure OutputReason ClosedRevisit Condition

Memory Summary

approval_required: true

Sanitized Memory Summary

Metadata

  • Platform: HackTheBox Challenges
  • Category: Reversing
  • Challenge: Exation
  • Difficulty: Easy
  • Source workspace: <local workspace>

Validated Solve Chain

Concepts only. Do not include raw flags, reusable credentials, tokens, cookies, private keys, or live secrets.

  1. Extract the challenge archive and identify the single Linux x86-64 executable.
  2. Detect UPX packing from the UPX! marker and high entropy.
  3. Unpack with upx -d into a separate analysis copy.
  4. Use the recovered C++ symbols to inspect exatlon(std::string const&) and main.
  5. Identify the transform: for each input character, compute ord(char) << 4, convert to decimal, and append a space.
  6. Decode the stored decimal-token target by dividing each token by 16 and converting back to characters.
  7. The decoded password is already an HTB-format flag.

Reusable Lessons

  • For stripped/no-section ELF reversing challenges, check for UPX before treating disassembly noise as intentional obfuscation.
  • A long decimal-token compare constant often represents transformed input and can be inverted without dynamic execution.
  • Preserve the packed original and unpack into analysis/unpacked/.

Dead Ends

  • Direct strings/disassembly on the packed binary gave only noisy/interleaved prompt fragments and was not sufficient.

Tool Quirks

  • upx was installed via Homebrew during the solve.
  • The packed file had no section headers, but the UPX-unpacked copy restored useful symbols.

Evidence Paths

  • analysis/extracted/exatlon_v1
  • analysis/unpacked/exatlon_v1.unpacked
  • analysis/unpacked/upx-unpack.txt
  • analysis/unpacked/exatlon-function.txt
  • analysis/unpacked/main-function.txt
  • solve/solve.py
  • loot/flag.txt

Ingestion Decision

  • Proposed for LightRAG: yes
  • Requires user approval before ingestion: yes

Notes

Notes

Scope

  • Challenge: Exation
  • Category: Reversing
  • Difficulty: Easy
  • Mode: file
  • Remote instance: none
  • Start time: 2026-06-10T12:51:57Z
  • Operator: harness
  • State file: challenge-state.json

Harness Status

  • Current phase: see challenge-state.json
  • Next allowed actions: see next-action.json
  • Raw flags and sensitive material stay in loot/ only. Do not paste them here.

Artifact Inventory

FileSizeSHA256TypeNotes
files/a12c73b2-b72a-4f35-994b-447540ce62d6.zip695275<hash redacted>Zip archive data, at least v2.0 to extract, compression method=deflatezip entries: 1 shown in artifact inventory JSON

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-10T12:51:57Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-10T12:51:57Zartifact inventoryanalysis/artifact-inventory.json1 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-10T12: <REDACTED>, then submit it to the binary to obtain the HTB flag.HighRun static triage with file/strings/objdump, inspect compare/transform constants, then build a solver that derives the password and executes the binary with that password.
2026-06-10T12:52:28Zresearch skipanalysis/research/research-skip.mdResearch intentionally skipped with recorded reasonMediumGate before exploit
2026-06-10T12: <REDACTED>
2026-06-10T12:58:06Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

  • The archive contains one Linux x86-64 executable: exatlon_v1.
  • The original executable is UPX-packed, statically linked, and section-stripped.
  • upx -d successfully unpacked it to analysis/unpacked/exatlon_v1.unpacked.
  • The unpacked binary is statically linked but not stripped, exposing exatlon(std::string const&) and main.
  • exatlon() initializes an output string, then for each input character appends std::to_string(ord(char) << 4) followed by a space.
  • main compares that transformed input against a decimal-number string constant at the success branch.
  • Dividing each decimal token by 16 reconstructs the password, which is itself an HTB-format flag.
  • solve/solve.py extracts the numeric constant from the unpacked binary and writes the recovered flag candidate to loot/.

RAG / Advisory Memory

RAG output is advisory only. Record evaluated retrievals with:

bash
scripts/challenge_harness.py rag-record <workspace> --query "..." --tag MATCHED|PARTIAL|MISSING|<secret redacted>|GENERIC --validation "..."

Secrets/Flags

Raw flags and sensitive material stay in loot/ only. Use scripts/challenge_harness.py capture-flag to validate and record flag capture without printing the value.

Technical analogy

How to remember this solve

Think of it like taking apart a small appliance on a workbench. You do not need every screw at once; you trace the control path and rebuild just enough logic to make it reveal the answer.

For Exation, keep the mental model simple: identify the trusted assumption, prove it with the smallest safe test, then automate or repeat only the part that directly leads to the flag.