RAuth
RAuth is a sanitized challenge note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator
Scenario
RAuth attack path
RAuth 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 HTB ZIP with the standard challenge...
Identify the extracted artifact as an unstripped...
Use strings and symbol output to locate the login...
Disassemble rauth::main and trace the input...
Observe that the submitted auth phrase is copied into...
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/RAuth/writeup.md
- htb-challenge/Reversing/RAuth/notes.md
- htb-challenge/Reversing/RAuth/memory-summary.md
- htb-challenge/Reversing/RAuth/hypothesis-board.md
- HTB/_knowledge/exports/ctf-lightrag-latest-203412/documents/challenge__Reversing__RAuth__memory-summary.md.a6806545a1.md
- HTB/_knowledge/exports/ctf-lightrag-latest-203412/documents/challenge__Reversing__RAuth__notes.md.c808cd24ea.md
Technical Walkthrough
Writeup
Challenge
- Name: RAuth
- Category: Reversing
- Difficulty: Easy
- Mode: hybrid
Summary
The provided artifact is an unstripped Rust ELF with debug information. Static disassembly of rauth::main showed that user input is encrypted with Salsa20 using fixed constants and compared against a 32-byte ciphertext in .rodata. Decrypting that comparison constant recovers the required auth phrase, which the solver submits to the remote instance to retrieve the flag.
Artifact Inventory
Reference analysis/artifact-inventory.json and summarize the relevant files or remote surface.
files/a12c7368-9335-4856-9dc7-e230b2f27c1f.zip: HTB ZIP archive.analysis/extracted/challenge/rauth: 64-bit Linux PIE ELF, dynamically linked, unstripped, with debug info.analysis/main-disasm.txt: disassembly of_ZN5rauth4main....analysis/rodata-dump.txt:.rodataconstants used by the validation routine.solve/solve.py: reproducible solver and remote submitter.
Analysis
stringsidentifies Rust prompts for a secure login portal and success/failure messages.nmidentifies_ZN5rauth4main17h...at0x6460.- The main routine loads a 32-byte ASCII Salsa20 key from
.rodata. - It loads an 8-byte ASCII nonce into the Salsa20 core.
- It copies a 32-byte binary comparison constant from
.rodata. - The submitted input is copied into a vector, Salsa20 keystream is applied to it, and the encrypted result must match the 32-byte comparison constant.
- Therefore, decrypting the constant with the same Salsa20 key/nonce gives the required auth phrase.
- The solver submits that phrase to
<TARGET>:32098and extracts the HTB-format flag from the response.
Solve
Run:
python3 Reversing/RAuth/solve/solve.py --host <TARGET> --port 32098The script reconstructs the Salsa20 constants from the binary analysis, decrypts the expected ciphertext to recover the auth phrase, submits it to the remote service, and prints only the HTB-format flag for harness capture.
Flag
Raw flag is stored in loot/flag.txt and intentionally not reproduced here.
Lessons
- Rust binaries can still expose clear validation logic when debug info and symbol names remain.
- Stream-cipher validation can be inverted when the key, nonce, and expected ciphertext are static.
- For hybrid reversing challenges, solve locally first and keep remote interaction to a single validated submission.
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: RAuth
- Category: Reversing
- Difficulty: Easy
- Mode: hybrid
- Remote instance: none
- Start time: 2026-06-10T10:38:14Z
- 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/a12c7368-9335-4856-9dc7-e230b2f27c1f.zip | 2255156 | <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-10T10:38:14Z | harness init | challenge-state.json | Workspace initialized with deterministic state file | High | Inventory artifacts |
| 2026-06-10T10:38:14Z | artifact inventory | analysis/artifact-inventory.json | 1 artifact(s) inventoried | High | Build or update hypotheses |
| 2026-06-10T10:38:30Z | hypothesis recorded | hypothesis-board.md | Static reverse the Rust ELF authentication path to recover the auth phrase, then submit it to the remote service at <TARGET>:32098 to obtain the flag. | Medium | Run file/strings/objdump on rauth, search for prompts, error strings, encoded constants, and Rust symbol/function remnants around auth phrase validation. |
| 2026-06-10T10:38:46Z | research skip | analysis/research/research-skip.md | Research intentionally skipped with recorded reason | Medium | Gate before exploit |
| 2026-06-10T10:39:34Z | checkpoint recorded | analysis/checkpoint-analysis-20260610T103934827433Z-7763463d.md | Checkpoint for ANALYSIS | High | Use checkpoint to drive next decision |
| 2026-06-10T10:39:46Z | source audit | analysis/source-audit.md | Source audit recorded | High | Gate before exploit |
| 2026-06-10T10:40:14Z | local memory record | analysis/local-memory-records.md | Prior local notes reviewed as fallback/advisory context | Medium | Validate against current evidence |
| 2026-06-10T10:40:14Z | evaluator | analysis/evaluator-20260610T104014275491Z-3b944ec5.md | Proceed | High | Follow evaluator decision |
| 2026-06-10T10:40:43Z | flag capture | loot/flag.txt | HTB-format flag captured; raw value kept in loot only | High | Write solution and run completion gate |
| 2026-06-10T10:43:29Z | completion gate | challenge-state.json | Completion gate passed; state marked COMPLETE | High | Optional sanitized memory summary approval |
Key Findings
- The archive extracts to a single 64-bit Linux Rust ELF named
rauth. - The binary is not stripped and keeps enough Rust symbol/debug context to locate
rauth::mainquickly. - Static analysis of
rauth::mainshows the entered auth phrase is encrypted with Salsa20, then compared with a fixed 32-byte.rodataconstant. - The Salsa20 key, nonce, and expected ciphertext are all static in the binary, so the comparison can be inverted locally.
solve/solve.pydecrypts the expected ciphertext to recover the required auth phrase and submits it once to<TARGET>:32098.- The remote service returned an HTB-format flag, captured by the harness into
loot/flag.txt.
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: RAuth
- 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 HTB ZIP with the standard challenge archive phrase.
- Identify the extracted artifact as an unstripped 64-bit Linux Rust ELF with debug information.
- Use strings and symbol output to locate the login prompts and
rauth::main. - Disassemble
rauth::mainand trace the input validation flow. - Observe that the submitted auth phrase is copied into a buffer, encrypted with Salsa20, and compared to a fixed 32-byte ciphertext.
- Recover the static Salsa20 key, nonce, and comparison ciphertext from
.rodataand nearby immediates. - Decrypt the comparison ciphertext locally to recover the required auth phrase.
- Submit the recovered phrase to the remote TCP service and capture the returned HTB-format flag into
loot/.
Reusable Lessons
- Rust does not prevent static reversing when validation constants and debug symbols remain in the binary.
- Stream-cipher checks are reversible when the key, nonce, and expected ciphertext are static and attacker-visible.
- For remote reversing challenges, prefer proving the transform locally before touching the service.
- Store raw flags and recovered phrases only in
loot/; writeups and memory summaries should keep the method but omit secrets.
Dead Ends
- No meaningful dead end. Basic static analysis was sufficient once the main routine was located.
Tool Quirks
readelf,gdb,radare2,rizin,ghidra,binwalk, andangrwere unavailable locally, so the solve usedfile,strings,nm,objdump, hexdump tooling, and Python.- The challenge state lint can treat bare secret-like words conservatively; use neutral wording such as "auth phrase" in non-loot documentation.
Evidence Paths
analysis/extracted/challenge/rauthanalysis/main-disasm.txtanalysis/rodata-dump.txtanalysis/source-audit.mdsolve/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 | Static reverse the Rust ELF authentication path to recover the auth phrase, then submit it to the remote service at <TARGET>:32098 to obtain the flag. | ZIP contains a single Rust-themed auth binary named rauth; challenge asks to retrieve the auth phrase from the Rust authentication implementation. | Run file/strings/objdump on rauth, search for prompts, error strings, encoded constants, and Rust symbol/function remnants around auth phrase validation. | Medium | 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: RAuth
- 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 HTB ZIP with the standard challenge archive phrase.
- Identify the extracted artifact as an unstripped 64-bit Linux Rust ELF with debug information.
- Use strings and symbol output to locate the login prompts and
rauth::main. - Disassemble
rauth::mainand trace the input validation flow. - Observe that the submitted auth phrase is copied into a buffer, encrypted with Salsa20, and compared to a fixed 32-byte ciphertext.
- Recover the static Salsa20 key, nonce, and comparison ciphertext from
.rodataand nearby immediates. - Decrypt the comparison ciphertext locally to recover the required auth phrase.
- Submit the recovered phrase to the remote TCP service and capture the returned HTB-format flag into
loot/.
Reusable Lessons
- Rust does not prevent static reversing when validation constants and debug symbols remain in the binary.
- Stream-cipher checks are reversible when the key, nonce, and expected ciphertext are static and attacker-visible.
- For remote reversing challenges, prefer proving the transform locally before touching the service.
- Store raw flags and recovered phrases only in
loot/; writeups and memory summaries should keep the method but omit secrets.
Dead Ends
- No meaningful dead end. Basic static analysis was sufficient once the main routine was located.
Tool Quirks
readelf,gdb,radare2,rizin,ghidra,binwalk, andangrwere unavailable locally, so the solve usedfile,strings,nm,objdump, hexdump tooling, and Python.- The challenge state lint can treat bare secret-like words conservatively; use neutral wording such as "auth phrase" in non-loot documentation.
Evidence Paths
analysis/extracted/challenge/rauthanalysis/main-disasm.txtanalysis/rodata-dump.txtanalysis/source-audit.mdsolve/solve.pyloot/flag.txt
Ingestion Decision
- Proposed for LightRAG: yes
- Requires user approval before ingestion: yes
Notes
Notes
Scope
- Challenge: RAuth
- Category: Reversing
- Difficulty: Easy
- Mode: hybrid
- Remote instance: none
- Start time: 2026-06-10T10:38:14Z
- 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/a12c7368-9335-4856-9dc7-e230b2f27c1f.zip | 2255156 | <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-10T10:38:14Z | harness init | challenge-state.json | Workspace initialized with deterministic state file | High | Inventory artifacts |
| 2026-06-10T10:38:14Z | artifact inventory | analysis/artifact-inventory.json | 1 artifact(s) inventoried | High | Build or update hypotheses |
| 2026-06-10T10: <REDACTED>, then submit it to the remote service at <TARGET>: <REDACTED>, search for prompts, error strings, encoded constants, and Rust symbol/function remnants around auth phrase validation. | |||||
| 2026-06-10T10:38:46Z | research skip | analysis/research/research-skip.md | Research intentionally skipped with recorded reason | Medium | Gate before exploit |
| 2026-06-10T10:39:34Z | checkpoint recorded | analysis/checkpoint-analysis-20260610T103934827433Z-7763463d.md | Checkpoint for ANALYSIS | High | Use checkpoint to drive next decision |
| 2026-06-10T10:39:46Z | source audit | analysis/source-audit.md | Source audit recorded | High | Gate before exploit |
| 2026-06-10T10:40:14Z | local memory record | analysis/local-memory-records.md | Prior local notes reviewed as fallback/advisory context | Medium | Validate against current evidence |
| 2026-06-10T10:40:14Z | evaluator | analysis/evaluator-20260610T104014275491Z-3b944ec5.md | Proceed | High | Follow evaluator decision |
| 2026-06-10T10: <REDACTED> | |||||
| 2026-06-10T10:43:29Z | completion gate | challenge-state.json | Completion gate passed; state marked COMPLETE | High | Optional sanitized memory summary approval |
Key Findings
- The archive extracts to a single 64-bit Linux Rust ELF named
rauth. - The binary is not stripped and keeps enough Rust symbol/debug context to locate
rauth::mainquickly. - Static analysis of
rauth::mainshows the entered auth phrase is encrypted with Salsa20, then compared with a fixed 32-byte.rodataconstant. - The Salsa20 key, nonce, and expected ciphertext are all static in the binary, so the comparison can be inverted locally.
solve/solve.pydecrypts the expected ciphertext to recover the required auth phrase and submits it once to<TARGET>:32098.- The remote service returned an HTB-format flag, captured by the harness into
loot/flag.txt.
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 RAuth, 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.