Challenge / Hardware

Wander

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

EasyPublished 2024-11-09Sanitized local writeup

Scenario

Wander attack path

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

Wander sanitized attack graph

Walkthrough flow

01

Identify the web-exposed PJL command form at /jobs.

02

Validate PJL forwarding with harmless INFO commands.

03

Enumerate the normal printer filesystem with .

04

Use PJL filesystem path traversal from 0:/../../ to...

05

List 0:/../../home/default and find readyjob.

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/Wander/writeup.md
  • htb-challenge/Hardware/Wander/notes.md
  • htb-challenge/Hardware/Wander/memory-summary.md
  • htb-challenge/Hardware/Wander/hypothesis-board.md
  • HTB/_knowledge/exports/ctf-lightrag-latest-203412/documents/challenge__Hardware__Wander__memory-summary.md.0d44ee46b8.md
  • HTB/_knowledge/exports/ctf-lightrag-latest-203412/documents/challenge__Hardware__Wander__notes.md.d675ae1359.md

Technical Walkthrough

Writeup

Challenge

  • Name: Wander
  • Category: Hardware
  • Difficulty: Easy
  • Mode: remote

Summary

The web app exposed a PJL command form at /jobs and proxied those commands to a simulated printer. Standard INFO commands confirmed the PJL interface, but the useful issue was filesystem traversal through PJL file commands. Listing 0:/../../ escaped the printer web content root and exposed /home/default/readyjob; uploading that file revealed the print job metadata containing the challenge flag.

Artifact Inventory

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

  • Remote-only challenge; no ZIP or firmware artifact was provided.
  • analysis/http-jobs-initial.txt records the /jobs form with name="pjl".
  • analysis/pjl-targeted-probe.txt records live INFO and root filesystem behavior.
  • analysis/pjl-fs-recursive.txt records the normal exposed printer filesystem.
  • analysis/pjl-path-traversal-readyjob.txt records the validated traversal path, with the raw flag redacted.

Analysis

  1. /jobs exposes a POST form to /printer with a PJL command field.
  2. @PJL INFO ID returned HTB Printer, proving the form forwards PJL to the backend.
  3. @PJL <secret redacted> NAME="0:" ENTRY=1 COUNT=50 listed printer directories such as PJL, PostScript, saveDevice, and webServer.
  4. Normal recursive listing only exposed firmware-like web content and empty key/security files.
  5. The path 0:/../../ escaped that root and listed host-like directories including home.
  6. 0:/../../home/default contained readyjob, a 457-byte file.
  7. @PJL FSUPLOAD NAME="0:/../../home/default/readyjob" OFFSET=0 SIZE=1000 returned the print job, including a PJL flag comment and a hold key.

Solve

Run:

bash
python3 Hardware/Wander/solve/solve.py --base-url http://<TARGET>:30391

The solver sends one FSUPLOAD command for 0:/../../home/default/readyjob, extracts the FLAG = "..." comment, and prints the flag for harness capture.

Flag

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

Lessons

  • PJL filesystem commands can expose a printer's virtual filesystem and, in this challenge, allowed traversal outside the normal printer web root.
  • External writeups or research should be treated as hints only; the decisive evidence here was the current-instance transcript in analysis/pjl-path-traversal-readyjob.txt.
  • Avoid stripping HTML blindly from FSUPLOAD results, because uploaded files may legitimately contain HTML-like content.

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: Wander
  • Category: Hardware
  • Difficulty: Easy
  • Mode: remote
  • Remote instance: none
  • Start time: 2026-06-10T10:01:41Z
  • 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
0remote-only or no provided filesNo local artifacts found under files/

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-10T10:01:41Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-10T10:01:41Zartifact inventoryanalysis/artifact-inventory.json0 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-10T10:02:44Zhypothesis recordedhypothesis-board.mdUse the web-exposed PJL interface to enumerate printer identity, variables, configuration, and filesystem content until the PIN/flag is disclosed.MediumPOST harmless PJL INFO commands first, then enumerate only response-backed PJL filesystem or variable surfaces.
2026-06-10T10:02:44Zresearch recordanalysis/research/research-records.mdResearch tagged MATCHEDMediumValidate against current evidence
2026-06-10T10:02:45Zcheckpoint recordedanalysis/checkpoint-hypothesis_ready-20260610T100245020450Z-177d1749.mdCheckpoint for <secret redacted>HighUse checkpoint to drive next decision
2026-06-10T10:02:45Zlocal memory recordanalysis/local-memory-records.mdPrior local notes reviewed as fallback/advisory contextMediumValidate against current evidence
2026-06-10T10:02:45Zevaluatoranalysis/evaluator-20260610T100245121028Z-558b8d78.mdProceedHighPOST PJL INFO commands, record responses, and derive the next bounded PJL command set.
2026-06-10T10:10:45Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-10T10:11:54Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-10T10:12:45Zresearch recordanalysis/research/research-records.mdResearch tagged MATCHEDMediumValidate against current evidence
2026-06-10T10:12:47Zcheckpoint recordedanalysis/checkpoint-analysis-20260610T101247930992Z-43f67866.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-10T10:13:59Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

  • /jobs exposes a PJL command form that posts to /printer.
  • @PJL INFO ID returns HTB Printer, confirming live PJL forwarding.
  • Normal PJL filesystem enumeration exposes PJL, PostScript, saveDevice, and webServer.
  • PJL path traversal using 0:/../../ escapes the normal printer content root.
  • 0:/../../home/default/readyjob is readable via FSUPLOAD and contains the challenge flag marker.
  • Repro solver: solve/solve.py.
  • Raw flag is stored only in loot/flag.txt.

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: Hardware
  • Challenge: Wander
  • 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.

  1. Identify the web-exposed PJL command form at /jobs.
  2. Validate PJL forwarding with harmless INFO commands.
  3. Enumerate the normal printer filesystem with <secret redacted>.
  4. Use PJL filesystem path traversal from 0:/../../ to escape the printer content root.
  5. List 0:/../../home/default and find readyjob.
  6. Read readyjob with FSUPLOAD; the print job metadata contains the flag marker and a printer hold key.

Reusable Lessons

  • For printer/PJL challenges, test INFO ID and INFO STATUS first to prove transport, then move to <secret redacted>, FSQUERY, and FSUPLOAD.
  • Path traversal may work inside PJL filesystem names even when normal HTTP routes are not useful.
  • Preserve raw FSUPLOAD content carefully; generic HTML stripping can hide useful file contents.
  • Treat public challenge research as advisory and require live validation before accepting it.

Dead Ends

  • Direct HTTP paths such as /pin, /unlock, /flag, and ChaiServer dispatcher routes returned 404.
  • Broad INFO <secret redacted>, INFO CONFIG, and direct INQUIRE PIN/PASSWORD style commands did not disclose useful state.
  • Normal webServer files exposed firmware-like content but no flag until traversal into /home/default/readyjob.

Tool Quirks

  • The web app embeds PJL responses inside the HTML page under the printer form.
  • 0:/path works as a PJL filesystem syntax; 0:path and 0:\path failed in this instance.
  • FSUPLOAD output can include HTML or PJL control markers, so extraction should slice from @PJL FSUPLOAD and stop at the page wrapper.

Evidence Paths

  • analysis/http-jobs-initial.txt
  • analysis/pjl-targeted-probe.txt
  • analysis/pjl-fs-recursive.txt
  • analysis/pjl-path-traversal-readyjob.txt
  • solve/solve.py
  • loot/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.

RankPathEvidenceMissing ProofCheapest ValidationConfidenceStatus
1Use the web-exposed PJL interface to enumerate printer identity, variables, configuration, and filesystem content until the PIN/flag is disclosed./jobs contains a form posting pjl to /printer with placeholder @PJL INFO ID.POST harmless PJL INFO commands first, then enumerate only response-backed PJL filesystem or variable surfaces.MediumActive

Closed Branches

BranchEvidence TestedFailure OutputReason ClosedRevisit Condition

Memory Summary

approval_required: true

Sanitized Memory Summary

Metadata

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

  1. Identify the web-exposed PJL command form at /jobs.
  2. Validate PJL forwarding with harmless INFO commands.
  3. Enumerate the normal printer filesystem with <secret redacted>.
  4. Use PJL filesystem path traversal from 0:/../../ to escape the printer content root.
  5. List 0:/../../home/default and find readyjob.
  6. Read readyjob with FSUPLOAD; the print job metadata contains the flag marker and a printer hold key.

Reusable Lessons

  • For printer/PJL challenges, test INFO ID and INFO STATUS first to prove transport, then move to <secret redacted>, FSQUERY, and FSUPLOAD.
  • Path traversal may work inside PJL filesystem names even when normal HTTP routes are not useful.
  • Preserve raw FSUPLOAD content carefully; generic HTML stripping can hide useful file contents.
  • Treat public challenge research as advisory and require live validation before accepting it.

Dead Ends

  • Direct HTTP paths such as /pin, /unlock, /flag, and ChaiServer dispatcher routes returned 404.
  • Broad INFO <secret redacted>, INFO CONFIG, and direct INQUIRE PIN/PASSWORD style commands did not disclose useful state.
  • Normal webServer files exposed firmware-like content but no flag until traversal into /home/default/readyjob.

Tool Quirks

  • The web app embeds PJL responses inside the HTML page under the printer form.
  • 0:/path works as a PJL filesystem syntax; 0:path and 0:\path failed in this instance.
  • FSUPLOAD output can include HTML or PJL control markers, so extraction should slice from @PJL FSUPLOAD and stop at the page wrapper.

Evidence Paths

  • analysis/http-jobs-initial.txt
  • analysis/pjl-targeted-probe.txt
  • analysis/pjl-fs-recursive.txt
  • analysis/pjl-path-traversal-readyjob.txt
  • solve/solve.py
  • loot/flag.txt

Ingestion Decision

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

Notes

Notes

Scope

  • Challenge: Wander
  • Category: Hardware
  • Difficulty: Easy
  • Mode: remote
  • Remote instance: none
  • Start time: 2026-06-10T10:01:41Z
  • 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
0remote-only or no provided filesNo local artifacts found under files/

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-10T10:01:41Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-10T10:01:41Zartifact inventoryanalysis/artifact-inventory.json0 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-10T10: <REDACTED>, variables, configuration, and filesystem content until the PIN/flag is disclosed.MediumPOST harmless PJL INFO commands first, then enumerate only response-backed PJL filesystem or variable surfaces.
2026-06-10T10:02:44Zresearch recordanalysis/research/research-records.mdResearch tagged MATCHEDMediumValidate against current evidence
2026-06-10T10:02:45Zcheckpoint recordedanalysis/checkpoint-hypothesis_ready-20260610T100245020450Z-177d1749.mdCheckpoint for <secret redacted>HighUse checkpoint to drive next decision
2026-06-10T10:02:45Zlocal memory recordanalysis/local-memory-records.mdPrior local notes reviewed as fallback/advisory contextMediumValidate against current evidence
2026-06-10T10:02:45Zevaluatoranalysis/evaluator-20260610T100245121028Z-558b8d78.mdProceedHighPOST PJL INFO commands, record responses, and derive the next bounded PJL command set.
2026-06-10T10: <REDACTED>
2026-06-10T10: <REDACTED>
2026-06-10T10:12:45Zresearch recordanalysis/research/research-records.mdResearch tagged MATCHEDMediumValidate against current evidence
2026-06-10T10:12:47Zcheckpoint recordedanalysis/checkpoint-analysis-20260610T101247930992Z-43f67866.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-10T10:13:59Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

  • /jobs exposes a PJL command form that posts to /printer.
  • @PJL INFO ID returns HTB Printer, confirming live PJL forwarding.
  • Normal PJL filesystem enumeration exposes PJL, PostScript, saveDevice, and webServer.
  • PJL path traversal using 0:/../../ escapes the normal printer content root.
  • `0: <REDACTED>
  • Repro solver: solve/solve.py.
  • Raw flag is stored only in loot/flag.txt.

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.

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