Challenge / Reversing

Maze

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

MediumPublished 2025-07-12Sanitized local writeup

Scenario

Maze attack path

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

Maze sanitized attack graph

Walkthrough flow

01

Binary triage

02

Control-flow recovery

03

Key logic reconstruction

04

Proof captured

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.

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/Maze/writeup.md
  • htb-challenge/Reversing/Maze/notes.md
  • htb-challenge/Reversing/Maze/memory-summary.md
  • htb-challenge/Reversing/Maze/hypothesis-board.md

Technical Walkthrough

Writeup

Challenge

  • Name: Maze
  • Category: Reversing
  • Difficulty: Medium
  • Mode: file

Summary

maze.exe is a Windows PyInstaller bundle that hides a multi-stage reversing

chain. The visible executable asks for a route, decrypts an AES ZIP, repairs a

second-stage Linux ELF using a PRNG key derived from maze.png, and the ELF

then validates the final HTB-format answer through sliding 3-byte sums.

The solve path was:

  1. Extract the PyInstaller CArchive.
  2. Disassemble the main Python 3.8 bytecode.
  3. Decode the nested obf_path module to recover the PNG-derived PRNG seed.
  4. Decrypt and repair the second-stage ELF.
  5. Parse the ELF’s sum table and solve the linear constraints.

Artifact Inventory

  • files/a12c733f-ef44-47e3-941d-19d83b135774.zip: original challenge archive.
  • files/extracted/rev_maze/maze.exe: Windows x64 PyInstaller bundle.
  • files/extracted/rev_maze/maze.png: image used by the obfuscated helper to

derive a PRNG seed.

  • files/extracted/rev_maze/enc_maze.zip: AES-encrypted ZIP containing the

second-stage file maze.

  • analysis/source-audit.md: local audit of the PyInstaller bundle, nested

module, seed derivation, ELF repair, and table solve.

Analysis

The PyInstaller cookie and table of contents were parsed from maze.exe. The

main script entry is named maze, and the embedded PYZ contains a module named

obf_path.

The main Python 3.8 bytecode was disassembled in Docker. It accepts only one

route string, calls obf_path.obfuscate_route(), decrypts enc_maze.zip, then

modifies every tenth byte of the extracted maze file.

The imported obf_path module contains nested marshal, LZMA, and zlib layers.

Decoding those layers without executing them shows that it reads four bytes

from maze.png at offsets 4817, 2624, 2640, and 2720; their sum is the

PRNG seed 493. The module also prints a clue to generate 300 random integers

with randint(32, 125).

Using that random stream as the XOR key after the main script’s +80 mod 256

step repairs the encrypted ZIP’s extracted maze file into a valid Linux

x86-64 ELF. The repaired ELF then checks the final answer:

  • It requires the input to begin with HTB.
  • It has a 36-dword table at .rodata offset 0x2060.
  • Each table entry is the sum of a 3-character sliding window.
  • A 36-entry table means the final answer is 38 bytes.

With the fixed HTB prefix, each next character is determined by:

text
next = table[i] - previous - current

RAG returned only generic reversing guidance, so it was recorded as advisory.

All decisive evidence comes from the current local artifacts.

Solve

The reproducible solver is [solve.py](<local workspace>).

It performs the complete chain:

  1. Reads maze.png and derives seed 493.
  2. Uses 7z with the recovered AES ZIP password to extract the second-stage

maze.

  1. Repairs every tenth byte using the seed-derived random key.
  2. Reads the dword table from the repaired ELF.
  3. Solves the sliding-sum equations.
  4. Writes the generated HTB-format candidate to the requested output path.

The repaired ELF was then validated with the generated candidate. The redacted

success transcript is stored at

analysis/decoded-elf-validation-redacted.txt.

Harness capture used:

bash
python3 scripts/challenge_exec.py Reversing/Maze -- \
  python3 Reversing/Maze/solve/solve.py \
  --workspace Reversing/Maze \
  --output Reversing/Maze/analysis/flag-candidate.txt \
  --decoded-elf analysis/decoded/solved_dec_maze \
  --transcript analysis/solve-transcript.txt

python3 scripts/challenge_harness.py capture-flag Reversing/Maze \
  --from analysis/flag-candidate.txt

Flag

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

Lessons

  • PyInstaller bundles can be solved cleanly by parsing the CArchive and PYZ

structures instead of treating the PE as native code.

  • Obfuscated helper modules may carry dynamic repair clues; nested marshal and

compressed payloads should be decoded but not blindly executed.

  • A sliding-sum table becomes a deterministic linear solve when the prefix is

known.

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: Maze
  • Category: Reversing
  • Difficulty: Medium
  • Mode: file
  • Remote instance: none
  • Start time: 2026-06-12T15:55:46Z
  • 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/a12c733f-ef44-47e3-941d-19d83b135774.zip5266198<hash redacted>Zip archive data, at least v1.0 to extract, compression method=storezip entries: 4 shown in artifact inventory JSON
files/extracted/rev_maze/enc_maze.zip2500<hash redacted>Zip archive data, at least v6.3 to extract, compression method=AES Encryptedzip entries: 1 shown in artifact inventory JSON
files/extracted/rev_maze/maze.exe4983877<hash redacted>PE32+ executable (console) x86-64, for MS Windows
files/extracted/rev_maze/maze.png433995<hash redacted>PNG image data, 512 x 512, 8-bit/color RGBA, non-interlaced

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-12T15:55:46Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-12T15:55:46Zartifact inventoryanalysis/artifact-inventory.json1 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-12T15:55:57Zartifact inventoryanalysis/artifact-inventory.json4 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-12T15:58:57Zhypothesis recordedhypothesis-board.mdExtract the PyInstaller Python payload, recover the accepted maze input and AES ZIP password from the Python 3.8 bytecode constants, decrypt enc_maze.zip, patch every 10th byte of the extracted maze file as the bytecode does, then inspect the decoded artifact for the flag.MediumRun a local solve script that extracts the archive using the recovered password, applies the byte transform, then validates the decoded file type and captures any HTB-format output.
2026-06-12T16:03:32Zsource auditanalysis/source-audit.mdSource audit recordedHighGate before exploit
2026-06-12T16:03:44Zresearch recordanalysis/research/research-records.mdResearch tagged MATCHEDMediumValidate against current evidence
2026-06-12T16:03:45Zcheckpoint recordedanalysis/checkpoint-analysis-20260612T160345037536Z-62b91e54.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-12T16:03:57ZRAG queryanalysis/rag/rag-query-20260612T160345100744Z-a0fa068c.txtRAG helper exited 0; output savedMediumRecord retrieval tag and validation
2026-06-12T16:04:19ZRAG recordanalysis/rag-records.mdRetrieved memory tagged GENERICMediumValidate or reject with live evidence
2026-06-12T16:04:19Zinstrumentation plananalysis/instrumentation-plan.mdGenerate and capture the HTB-format answer by reproducing the recovered PyInstaller, PNG-seed, AES ZIP, ELF repair, and sliding-sum solve chain.HighStop if 7z extraction fails, repaired ELF is not valid, sliding-sum validation fails, or the decoded ELF rejects the generated candidate.
2026-06-12T16:04:19Zevaluatoranalysis/evaluator-20260612T160419585198Z-96d5b958.mdProceedHighRun harness-gated solve.py and capture the generated candidate.
2026-06-12T16:04:40Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-12T16:05:24Zlocal memory recordanalysis/local-memory-records.mdPrior local notes reviewed as fallback/advisory contextMediumValidate against current evidence
2026-06-12T16:06:10Zcompletion 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.

Memory Summary

Metadata

  • Platform: HackTheBox Challenges
  • Category: Reversing
  • Challenge: Maze
  • 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.

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
1Extract the PyInstaller Python payload, recover the accepted maze input and AES ZIP password from the Python 3.8 bytecode constants, decrypt enc_maze.zip, patch every 10th byte of the extracted maze file as the bytecode does, then inspect the decoded artifact for the flag.The PyInstaller TOC contains a main script named maze; Python 3.8 disassembly shows the accepted input string, the AES ZIP password string, and the post-extraction byte transformation.Run a local solve script that extracts the archive using the recovered password, applies the byte transform, then validates the decoded file type and captures any HTB-format output.MediumActive

Closed Branches

BranchEvidence TestedFailure OutputReason ClosedRevisit Condition

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