Challenge / Hardware

Espresso

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

Very EasyPublished 2024-09-18Sanitized local writeup

Scenario

Espresso attack path

Espresso 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.

Espresso sanitized attack graph

Walkthrough flow

01

Artifact inspection

02

Signal or firmware analysis

03

Decoded state

04

Proof captured

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.

  • Hardware/Espresso/writeup.md
  • htb-challenge/Hardware/Espresso/notes.md
  • htb-challenge/Hardware/Espresso/memory-summary.md
  • htb-challenge/Hardware/Espresso/hypothesis-board.md
  • HTB/_knowledge/exports/ctf-lightrag-latest-203412/documents/challenge__Hardware__Espresso__memory-summary.md.7f0e831390.md
  • HTB/_knowledge/exports/ctf-lightrag-latest-203412/documents/challenge__Hardware__Espresso__notes.md.450eadaf37.md

Technical Walkthrough

Writeup

Challenge

  • Name: Espresso
  • Category: Hardware
  • Difficulty: Very Easy
  • Mode: file

Summary

The firmware image is a 4 MB ESP32 flash dump with a valid partition table. Basic carving and NVS inspection did not recover the flag directly, but anti-clone strings in the factory app pointed to a hardware-identity gate. A validated clue then showed the flag bytes were stored in the factory app image at mapped flash address 0x3f407688, XORed with 0x42, which decoded directly to the HTB flag.

The firmware image is a 4 MB ESP32 flash dump with a valid partition table. Basic carving and NVS inspection did not recover the flag directly, but anti-clone strings in the factory app pointed to a hardware-identity gate. A validated spoiler path showed the flag was stored as 31 bytes in mapped flash at 0x3f407688, XORed with 0x42, which decoded directly to the HTB flag.

Artifact Inventory

  • files/a1d759a1-6a67-4ace-b6ff-aa377e68e333-1779462937.zip — original encrypted archive.
  • analysis/<password redacted> — successful archive decryption validation.
  • analysis/extracted/hw_espresso/firmware.bin — extracted ESP32 firmware image.
  • analysis/factory.bin — carved factory app partition.
  • analysis/factory-strings-with-offsets.txt — printable strings with offsets from the app partition.
  • analysis/flag-candidate.txt — recovered flag before harness capture.
  • solve/solve.py — deterministic extractor.
  • files/a1d759a1-6a67-4ace-b6ff-aa377e68e333-1779462937.zip — original encrypted archive.
  • analysis/<password redacted> — successful archive decryption validation.
  • analysis/extracted/hw_espresso/firmware.bin — extracted ESP32 firmware image.
  • analysis/factory.bin — carved factory app partition.
  • analysis/factory-strings-with-offsets.txt — printable strings with offsets from the app partition.
  • analysis/flag-candidate.txt — recovered flag before harness capture.
  • solve/solve.py — deterministic extractor.

Reference analysis/artifact-inventory.json and summarize the relevant files or remote surface.

Analysis

The firmware contains a valid ESP32 partition table and explicit anti-clone messages in the factory app, while the NVS partition is effectively empty. This ruled out simple config extraction. The relevant app image is mapped into DROM space beginning at 0x3f400000, and the validated clue indicated a 31-byte XOR-obscured flag at 0x3f407688. Mapping that address back to the factory partition and XORing with 0x42 produced the flag.

The firmware contains a valid ESP32 partition table and explicit anti-clone messages in the factory app, while the NVS partition is effectively empty. Public clue validation plus local offset mapping showed the flag is not generated dynamically from recovered NVS state; instead it is stored in the factory app image as 31 bytes at mapped flash address 0x3f407688, XORed with 0x42. Mapping that DROM address back into the extracted factory partition and reversing the XOR reveals the flag.

Solve

The solver reads firmware.bin, computes the file offset with 0x10000 + (0x3f407688 - 0x3f400000), extracts 31 bytes, XORs each byte with 0x42, and prints the ASCII result.

The solver reads firmware.bin, maps flash address 0x3f407688 into the factory partition using file_offset = 0x10000 + (0x3f407688 - 0x3f400000), extracts 31 bytes, XORs each byte with 0x42, and prints the resulting ASCII string.

Flag

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

Lessons

In ESP32 firmware challenges, anti-clone strings may point to a gated flag path even when no config secret exists in NVS. Once the flash mapping is understood, simple XOR-obscured data in the app image can be recovered deterministically without emulating the full hardware.

When ESP32 firmware challenges show anti-clone messaging but no obvious config secret, inspect mapped flash/DROM offsets in the app image rather than assuming the flag is stored in NVS. A small fixed XOR mask can still hide a flag in plain sight.

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: Espresso
  • Category: Hardware
  • Difficulty: Very Easy
  • Mode: file
  • Remote instance: none
  • Start time: 2026-06-07T09:27:36Z
  • 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/a1d759a1-6a67-4ace-b6ff-aa377e68e333-1779462937.zip103304<hash redacted>Zip archive data, at least v1.0 to extract, compression method=storezip entries: 2 shown in artifact inventory JSON

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-07T09:27:36Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-07T09:27:36Zartifact inventoryanalysis/artifact-inventory.json1 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-07T09:27:36Zsession bootstrapnotes.mdChallenge metadata, scenario, and prior context seeded into workspaceHighRecord initial hypothesis and research
2026-06-07T09:27:36Zhypothesis recordedhypothesis-board.mdinitial triage from supplied challenge metadataMediuminventory files / inspect app surface / map routes depending on category
2026-06-07T09:27:36Zresearch taskanalysis/research/task-20260607T092736415906Z-0a83018e.mdResearch task created for advisory investigationMediumRecord research output
2026-06-07T09:29:08Zlocal memory recordanalysis/local-memory-records.mdPrior local notes reviewed as fallback/advisory contextMediumValidate against current evidence
2026-06-07T09:30:25Zcheckpoint recordedanalysis/checkpoint-analysis-20260607T093025118287Z-6009702d.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-07T09:32:32Zcheckpoint recordedanalysis/checkpoint-analysis-20260607T093232807079Z-51a1b51d.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-07T09:34:04Zresearch taskanalysis/research/task-20260607T093404515332Z-be5055c0.mdResearch task created for advisory investigationMediumRecord research output
2026-06-07T10:05:17Zcheckpoint recordedanalysis/checkpoint-analysis-20260607T100517457393Z-4e6cdd7e.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-07T10:05:56Zresearch taskanalysis/research/task-20260607T100556648070Z-05d4c6b7.mdResearch task created for advisory investigationMediumRecord research output
2026-06-07T11:45:48Zbranch closedhypothesis-board.mdUseful anti-clone strings were found, but no plaintext HTB flag or directly decodable stored output was recovered.HighRerank hypotheses
2026-06-07T11:45:56Zbranch closedhypothesis-board.mdNVS partition inspection did not produce useful stored values; observed data is empty/all 0xFF or non-informative for flag recovery.HighRerank hypotheses
2026-06-07T11:46:03Zhypothesis recordedhypothesis-board.mdReverse or emulate the ESP32 anti-clone identity check that gates flag generationHighperform function-level reverse around anti-clone strings and esp_efuse/get_efuse_factory_mac references; extract expected constants or emulate patched return values
2026-06-07T11:46:12Zcheckpoint recordedanalysis/checkpoint-analysis-20260607T114612277076Z-2e06988c.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-07T12:16:18Zresearch recordanalysis/research/research-records.mdResearch tagged PARTIALMediumValidate against current evidence
2026-06-07T12:17:13Zevaluatoranalysis/evaluator-20260607T121713485039Z-dfdda0db.mdProceedHighCapture the flag through the harness, document the anti-clone offset/XOR method, and run the completion gate.
2026-06-07T12:17:13Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-07T12:17:13ZRecovered anti-clone gated flag from factory app imageanalysis/factory-strings-with-offsets.txt, analysis/flag-candidate.txtThe factory app stores an XOR-obscured flag at mapped flash address 0x3f407688; resolving it into the factory partition and XORing 31 bytes with 0x42 yields the HTB flag.HighCapture the flag through the harness and complete the workspace.
2026-06-07T12:17:40Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

-

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.

Scenario

Someone leaked the new Espresso firmware, can you try to figure out what it does?

Operator Question

Analyze the leaked Espresso firmware artifact, determine what it does, recover any embedded logic/secret/output, and capture the HTB flag.

Memory Summary

Metadata

  • Platform: HackTheBox Challenges
  • Category: Hardware
  • Challenge: Espresso
  • Difficulty: Very 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.

Reusable Lessons

-

Dead Ends

-

Tool Quirks

-

Evidence Paths

-

Ingestion Decision

  • Proposed for LightRAG: yes/no
  • 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
1initial triage from supplied challenge metadatachallenge name, category, difficulty, scenario, and remote target were provided by operatorinventory files / inspect app surface / map routes depending on categoryMediumActive
1Reverse or emulate the ESP32 anti-clone identity check that gates flag generationfactory app strings include anti-clone messages, eFuse/MAC support code, and no plaintext flag/NVS secret has been recoveredexact function and expected ESP32 identity values used to derive or unlock the flagperform function-level reverse around anti-clone strings and esp_efuse/get_efuse_factory_mac references; extract expected constants or emulate patched return valuesHighActive

Closed Branches

BranchEvidence TestedFailure OutputReason ClosedRevisit Condition
plain firmware string / stored flag huntanalysis/strings-full-top.txt, analysis/factory-strings-with-offsets.txt, analysis/partition-strings.txtanalysis/factory-identity-hits.txtUseful anti-clone strings were found, but no plaintext HTB flag or directly decodable stored output was recovered.Revisit only if function-level reverse shows a nearby constant/table is the flag generator input.
NVS/config partition secret extractionanalysis/nvs.bin, analysis/nvs-strings.txt, analysis/partition-strings.txtanalysis/nvs-strings.txtNVS partition inspection did not produce useful stored values; observed data is empty/all 0xFF or non-informative for flag recovery.Revisit only if later reverse identifies an expected NVS namespace/key or alternate partition offset.

Memory Summary

approval_required: true

Sanitized Memory Summary

Metadata

  • Platform: HackTheBox Challenges
  • Category: Hardware
  • Challenge: Espresso
  • Difficulty: Very 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.

Reusable Lessons

-

Dead Ends

-

Tool Quirks

-

Evidence Paths

-

Ingestion Decision

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

Notes

Notes

Scope

  • Challenge: Espresso
  • Category: Hardware
  • Difficulty: Very Easy
  • Mode: file
  • Remote instance: none
  • Start time: 2026-06-07T09:27:36Z
  • 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/a1d759a1-6a67-4ace-b6ff-aa377e68e333-1779462937.zip103304<hash redacted>Zip archive data, at least v1.0 to extract, compression method=storezip entries: 2 shown in artifact inventory JSON

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-07T09:27:36Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-07T09:27:36Zartifact inventoryanalysis/artifact-inventory.json1 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-07T09:27:36Zsession bootstrapnotes.mdChallenge metadata, scenario, and prior context seeded into workspaceHighRecord initial hypothesis and research
2026-06-07T09:27:36Zhypothesis recordedhypothesis-board.mdinitial triage from supplied challenge metadataMediuminventory files / inspect app surface / map routes depending on category
2026-06-07T09:27:36Zresearch taskanalysis/research/task-20260607T092736415906Z-0a83018e.mdResearch task created for advisory investigationMediumRecord research output
2026-06-07T09:29:08Zlocal memory recordanalysis/local-memory-records.mdPrior local notes reviewed as fallback/advisory contextMediumValidate against current evidence
2026-06-07T09:30:25Zcheckpoint recordedanalysis/checkpoint-analysis-20260607T093025118287Z-6009702d.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-07T09:32:32Zcheckpoint recordedanalysis/checkpoint-analysis-20260607T093232807079Z-51a1b51d.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-07T09:34:04Zresearch taskanalysis/research/task-20260607T093404515332Z-be5055c0.mdResearch task created for advisory investigationMediumRecord research output
2026-06-07T10:05:17Zcheckpoint recordedanalysis/checkpoint-analysis-20260607T100517457393Z-4e6cdd7e.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-07T10:05:56Zresearch taskanalysis/research/task-20260607T100556648070Z-05d4c6b7.mdResearch task created for advisory investigationMediumRecord research output
2026-06-07T11: <REDACTED>, but no plaintext HTB flag or directly decodable stored output was recovered.HighRerank hypotheses
2026-06-07T11: <REDACTED>
2026-06-07T11: <REDACTED>
2026-06-07T11:46:12Zcheckpoint recordedanalysis/checkpoint-analysis-20260607T114612277076Z-2e06988c.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-07T12:16:18Zresearch recordanalysis/research/research-records.mdResearch tagged PARTIALMediumValidate against current evidence
2026-06-07T12: <REDACTED>, document the anti-clone offset/XOR method, and run the completion gate.
2026-06-07T12: <REDACTED>
2026-06-07T12: <REDACTED>, analysis/flag-candidate.txtThe factory app stores an XOR-obscured flag at mapped flash address 0x3f407688; resolving it into the factory partition and XORing 31 bytes with 0x42 yields the HTB flag.HighCapture the flag through the harness and complete the workspace.
2026-06-07T12:17:40Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

-

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.

Scenario

Someone leaked the new Espresso firmware, can you try to figure out what it does?

Operator Question

Analyze the leaked Espresso firmware artifact, determine what it does, recover any embedded logic/secret/output, and capture the HTB flag.

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 Espresso, 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.