Secret Treasures
Secret Treasures is a sanitized challenge note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator
Scenario
Secret Treasures attack path
Secret Treasures 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 Hardware evidence, validation, and reusable operator lessons.
Walkthrough flow
Extracted the challenge archive and identified an ARM...
Reversed the firmware serial path: /dev/ttyS0, 38400...
Reversed the firmware PRNG and flash addressing path:
Recovered the decimal seed with a local C brute-force...
Source coverage
High source coverage
Status: complete. This article is generated from 4 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.
- Hardware/Secret-Treasures/writeup.md
- htb-challenge/Hardware/Secret-Treasures/notes.md
- htb-challenge/Hardware/Secret-Treasures/memory-summary.md
- htb-challenge/Hardware/Secret-Treasures/hypothesis-board.md
Technical Walkthrough
Writeup
Challenge
- Name: Secret-Treasures
- Category: Hardware
- Difficulty: Medium
- Mode: file
Summary
The challenge provides an ARM firmware binary, a W25Q128 flash dump, and a Saleae input trace. The firmware showed that the input channel is an 8-byte decimal passcode used as a PRNG seed. The PRNG output is then converted into flash addresses, one byte at a time, to print the flag.
I validated the firmware logic locally, recovered the decimal seed, and reproduced the 49-byte flag extraction from the flash dump with solve/solve.py. The raw flag is kept only in loot/flag.txt.
Artifact Inventory
files/a12c7357-88da-4145-a579-1bb343be1776.zip: original challenge archive.analysis/extracted/hw_secret/embedded_software: 32-bit ARM ELF.analysis/extracted/hw_secret/flash_memory_dump.bin: 16 MiB flash image.analysis/extracted/hw_secret/input_channel_trace.sal: Saleae capture archive; extracted metadata confirms a Logic 8 capture with digital sampling at 50 MHz.- Full hashes and file types are in
analysis/artifact-inventory.json,analysis/file-types.txt, andanalysis/sha256sums.txt.
Analysis
Static analysis was enough to avoid full hardware emulation:
analysis/embedded-strings.txtidentified wiringPi serial/SPI usage,/dev/ttyS0,serialGetchar,strtoul,W25Q128_init,get_UniqieID,get_secret, andrandom_generator.analysis/objdump-disasm.txtshowedmainopening/dev/ttyS0at 38400 baud, reading 8 serial bytes, echoing them, and parsing the input as a base-10 integer viastrtoul.- The same disassembly showed the parsed integer is stored as the global PRNG state.
random_generatorupdates the state asstate = state * 0x41c64e6d + 0x0008042amodulo 2^32, then returnsstate % 0x00ffffff.maincalls the PRNG three times per output byte. It takes the high byte from the first result, the middle byte from the second result, and the low byte from the third result to build a 24-bit flash address.- The output loop runs while the byte counter is less than or equal to 48, so it emits 49 bytes.
get_secretsends SPI command0x03plus the 24-bit address and copies the returned flash byte.
Public research was used only as a sanity check. Saleae documentation confirmed the <SALEAE> binary header conventions, while sigrok documentation explained why direct .sal import is often unsupported. The HTB forum discussion also matched the observed failure mode: wrong integer/export handling causes random-looking flash output. Those notes are recorded in analysis/research/saleae-and-secret-treasures-research.md.
Solve
The solve has two parts:
solve/bruteforce_seed.csearches the 8-digit decimal seed space using the exact firmware PRNG/address logic and validates candidates against theHTB{prefix.solve/solve.pyuses the recovered seed73261522to reproduce the final extraction fromanalysis/extracted/hw_secret/flash_memory_dump.bin.
Re-run:
cd <local workspace>
./solve/solve.py --output loot/flag-candidate.txtThe harness capture step copied the validated flag to loot/flag.txt.
Flag
Raw flag is stored in loot/flag.txt and intentionally not reproduced here.
Lessons
- In hardware challenges with firmware plus flash, reverse the device-side address generation before trying broad carving.
.salfiles may require vendor tooling or custom parsing; firmware-derived validation can be cheaper when the passcode is only a PRNG seed.- Preserve C helpers for expensive seed searches, but keep a clean Python script for final reproducibility.
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: Secret-Treasures
- Category: Hardware
- Difficulty: Medium
- Mode: file
- Remote instance: none
- Start time: 2026-06-13T12:45:03Z
- 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/a12c7357-88da-4145-a579-1bb343be1776.zip | 16815481 | <hash redacted> | Zip archive data, at least v1.0 to extract, compression method=store | zip entries: 4 shown in artifact inventory JSON |
Evidence Ledger
| Time | Action | Output/File | Finding | Confidence | Next |
|---|---|---|---|---|---|
| 2026-06-13T12:45:03Z | harness init | challenge-state.json | Workspace initialized with deterministic state file | High | Inventory artifacts |
| 2026-06-13T12:45:03Z | artifact inventory | analysis/artifact-inventory.json | 1 artifact(s) inventoried | High | Build or update hypotheses |
| 2026-06-13T12:45:55Z | hypothesis recorded | hypothesis-board.md | Reverse the ARM embedded_software to identify the passcode verification and flash lookup logic, decode input_channel_trace.sal to recover the entered passcode, then use the passcode against flash_memory_dump.bin to extract the HTB flag. | Medium | Extract the .sal capture into CSV/metadata, inspect ELF strings/disassembly for protocol constants and flash offsets, then write solve/solve.py to reproduce passcode decoding and flash extraction. |
| 2026-06-13T12:51:47Z | research task | analysis/research/task-20260613T125147012693Z-206f638b.md | Research task created for advisory investigation | Medium | Record research output |
| 2026-06-13T12:52:33Z | research record | analysis/research/research-records.md | Research tagged MATCHED | Medium | Validate against current evidence |
| 2026-06-13T12:52:54Z | checkpoint recorded | analysis/checkpoint-analysis-20260613T125253998893Z-5f455c77.md | Checkpoint for ANALYSIS | High | Use checkpoint to drive next decision |
| 2026-06-13T12:52:54Z | instrumentation plan | analysis/instrumentation-plan.md | Prove the offline flag extraction path from firmware PRNG to W25Q128 flash bytes. | High | Stop if no HTB{ prefix appears under the exact firmware PRNG logic, or if solve.py output fails HTB flag format validation. |
| 2026-06-13T12:52:54Z | evaluator | analysis/evaluator-20260613T125254120114Z-dbd337d3.md | Proceed | High | Run gate before exploit, execute solve.py to loot/flag-candidate.txt, then capture-flag. |
| 2026-06-13T12:53:00Z | flag capture | loot/flag.txt | HTB-format flag captured; raw value kept in loot only | High | Write solution and run completion gate |
| 2026-06-13T12:54:05Z | completion gate | challenge-state.json | Completion gate passed; state marked COMPLETE | High | Optional sanitized memory summary approval |
Key Findings
- Archive extracted with the standard HTB archive password into
analysis/extracted/. embedded_softwareis a 32-bit ARM ELF using wiringPi serial and SPI functions.- The firmware opens
/dev/ttyS0at 38400 baud, reads exactly 8 bytes, and parses them withstrtoul(..., base=10). - The firmware checks a W25Q128 unique ID against the
.rodatabytes at0x10f40. - The PRNG is an LCG:
state = state * 0x41c64e6d + 0x0008042amodulo 2^32, returningstate % 0x00ffffff. - Each emitted byte is read from the flash dump at an address built from three PRNG calls.
- The firmware emits 49 bytes after successful identification.
- Local seed search recovered decimal seed
73261522, andsolve/solve.pyreproduces the flag extraction from the flash dump.
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: Hardware
- Challenge: Secret-Treasures
- Difficulty: Medium
- Source workspace:
<local workspace>
Validated Solve Chain
Concepts only. Do not include raw flags, reusable credentials, tokens, cookies, private keys, or live secrets.
- Extracted the challenge archive and identified an ARM ELF, a W25Q128 flash dump, and a Saleae input trace.
- Reversed the firmware serial path:
/dev/ttyS0, 38400 baud, 8 bytes,strtoul(..., base=10). - Reversed the firmware PRNG and flash addressing path:
- LCG state update with multiplier 0x41c64e6d and increment 0x0008042a.
- PRNG return value is modulo 0x00ffffff.
- Three PRNG calls build each 24-bit flash address.
- Recovered the decimal seed with a local C brute-force helper and reproduced the final extraction with Python.
Reusable Lessons
- For firmware plus flash challenges, recover the firmware's exact integer semantics before reading flash bytes; minor type/modulo mistakes produce plausible but wrong random output.
- Use C for bounded high-volume seed search and Python for the final clean solve artifact.
- Treat
.salparsing as optional when the firmware model provides a deterministic extraction route.
Dead Ends
- Direct
sigrok-cliimport of the.salarchive was not viable in this local environment. - Direct string search of the flash dump did not reveal the flag.
Tool Quirks
binwalk,ghidra,openocd,avrdude,minipro,rtl_433, andurhwere missing locally, but were not blockers.objdumpwas sufficient for the ARM ELF even thoughreadelfwas unavailable.- Saleae
.salcontainers can hold internal binary data that does not import cleanly through sigrok.
Evidence Paths
analysis/objdump-disasm.txtanalysis/objdump-symbols.txtanalysis/objdump-rodata.txtanalysis/research/saleae-and-secret-treasures-research.mdanalysis/seed-candidates-7.txtsolve/bruteforce_seed.csolve/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 | Reverse the ARM embedded_software to identify the passcode verification and flash lookup logic, decode input_channel_trace.sal to recover the entered passcode, then use the passcode against flash_memory_dump.bin to extract the HTB flag. | Artifacts include embedded_software ARM ELF, flash_memory_dump.bin, and input_channel_trace.sal matching the scenario's embedded software, flash dump, and passcode input channel capture. | Extract the .sal capture into CSV/metadata, inspect ELF strings/disassembly for protocol constants and flash offsets, then write solve/solve.py to reproduce passcode decoding and flash extraction. | Medium | Active |
Closed Branches
| Branch | Evidence Tested | Failure Output | Reason Closed | Revisit Condition |
|---|
Technical analogy
How to remember this solve
Think of the hardware challenge like following copper tracks on a circuit board. The useful clue is usually where signals enter, where they are transformed, and which debug or storage path exposes hidden state.
For Secret Treasures, 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.