Exation
Exation is a sanitized challenge note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator
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.
Walkthrough flow
Extract the challenge archive and identify the single...
Detect UPX packing from the UPX! marker and high...
Unpack with upx -d into a separate analysis copy.
Use the recovered C++ symbols to inspect...
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.
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:
upx -d -o analysis/unpacked/exatlon_v1.unpacked analysis/extracted/exatlon_v1The 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:
- loads the character,
- shifts its signed integer value left by four bits,
- converts that integer to decimal text with
std::to_string, - appends a single space.
In pseudocode:
def exatlon(password):
out = ""
for char in password: <redacted> += str(ord(char) << 4) + " "
return outmain 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:
python3 Reversing/Exation/solve/solve.py \
--flag-out Reversing/Exation/loot/flag-candidate.txtThen capture it with the harness:
python3 scripts/challenge_harness.py capture-flag Reversing/Exation --from loot/flag-candidate.txtThe 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
| File | Size | SHA256 | Type | Notes |
|---|---|---|---|---|
files/a12c73b2-b72a-4f35-994b-447540ce62d6.zip | 695275 | <hash redacted> | Zip archive data, at least v2.0 to extract, compression method=deflate | zip entries: 1 shown in artifact inventory JSON |
Evidence Ledger
| Time | Action | Output/File | Finding | Confidence | Next |
|---|---|---|---|---|---|
| 2026-06-10T12:51:57Z | harness init | challenge-state.json | Workspace initialized with deterministic state file | High | Inventory artifacts |
| 2026-06-10T12:51:57Z | artifact inventory | analysis/artifact-inventory.json | 1 artifact(s) inventoried | High | Build or update hypotheses |
| 2026-06-10T12:52:28Z | hypothesis recorded | hypothesis-board.md | Recover the expected password from the exatlon_v1 validation routine, then submit it to the binary to obtain the HTB flag. | High | 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. |
| 2026-06-10T12:52:28Z | research skip | analysis/research/research-skip.md | Research intentionally skipped with recorded reason | Medium | Gate before exploit |
| 2026-06-10T12:56:33Z | flag capture | loot/flag.txt | HTB-format flag captured; raw value kept in loot only | High | Write solution and run completion gate |
| 2026-06-10T12:58:06Z | completion gate | challenge-state.json | Completion gate passed; state marked COMPLETE | High | Optional 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 -dsuccessfully unpacked it toanalysis/unpacked/exatlon_v1.unpacked.- The unpacked binary is statically linked but not stripped, exposing
exatlon(std::string const&)andmain. exatlon()initializes an output string, then for each input character appendsstd::to_string(ord(char) << 4)followed by a space.maincompares 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.pyextracts the numeric constant from the unpacked binary and writes the recovered flag candidate toloot/.
RAG / Advisory Memory
RAG output is advisory only. Record evaluated retrievals with:
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.
- Extract the challenge archive and identify the single Linux x86-64 executable.
- Detect UPX packing from the
UPX!marker and high entropy. - Unpack with
upx -dinto a separate analysis copy. - Use the recovered C++ symbols to inspect
exatlon(std::string const&)andmain. - Identify the transform: for each input character, compute
ord(char) << 4, convert to decimal, and append a space. - Decode the stored decimal-token target by dividing each token by 16 and converting back to characters.
- 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
upxwas 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_v1analysis/unpacked/exatlon_v1.unpackedanalysis/unpacked/upx-unpack.txtanalysis/unpacked/exatlon-function.txtanalysis/unpacked/main-function.txtsolve/solve.pyloot/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.
| Rank | Path | Evidence | Missing Proof | Cheapest Validation | Confidence | Status |
|---|---|---|---|---|---|---|
| 1 | Recover 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. | High | Active |
Closed Branches
| Branch | Evidence Tested | Failure Output | Reason Closed | Revisit 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.
- Extract the challenge archive and identify the single Linux x86-64 executable.
- Detect UPX packing from the
UPX!marker and high entropy. - Unpack with
upx -dinto a separate analysis copy. - Use the recovered C++ symbols to inspect
exatlon(std::string const&)andmain. - Identify the transform: for each input character, compute
ord(char) << 4, convert to decimal, and append a space. - Decode the stored decimal-token target by dividing each token by 16 and converting back to characters.
- 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
upxwas 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_v1analysis/unpacked/exatlon_v1.unpackedanalysis/unpacked/upx-unpack.txtanalysis/unpacked/exatlon-function.txtanalysis/unpacked/main-function.txtsolve/solve.pyloot/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
| File | Size | SHA256 | Type | Notes |
|---|---|---|---|---|
files/a12c73b2-b72a-4f35-994b-447540ce62d6.zip | 695275 | <hash redacted> | Zip archive data, at least v2.0 to extract, compression method=deflate | zip entries: 1 shown in artifact inventory JSON |
Evidence Ledger
| Time | Action | Output/File | Finding | Confidence | Next |
|---|---|---|---|---|---|
| 2026-06-10T12:51:57Z | harness init | challenge-state.json | Workspace initialized with deterministic state file | High | Inventory artifacts |
| 2026-06-10T12:51:57Z | artifact inventory | analysis/artifact-inventory.json | 1 artifact(s) inventoried | High | Build or update hypotheses |
| 2026-06-10T12: <REDACTED>, then submit it to the binary to obtain the HTB flag. | High | 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. | |||
| 2026-06-10T12:52:28Z | research skip | analysis/research/research-skip.md | Research intentionally skipped with recorded reason | Medium | Gate before exploit |
| 2026-06-10T12: <REDACTED> | |||||
| 2026-06-10T12:58:06Z | completion gate | challenge-state.json | Completion gate passed; state marked COMPLETE | High | Optional 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 -dsuccessfully unpacked it toanalysis/unpacked/exatlon_v1.unpacked.- The unpacked binary is statically linked but not stripped, exposing
exatlon(std::string const&)andmain. exatlon()initializes an output string, then for each input character appendsstd::to_string(ord(char) << 4)followed by a space.maincompares 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.pyextracts the numeric constant from the unpacked binary and writes the recovered flag candidate toloot/.
RAG / Advisory Memory
RAG output is advisory only. Record evaluated retrievals with:
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.