Challenge / Hardware

Plug And Pray

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

MediumPublished 2024-10-10Sanitized local writeup

Scenario

Plug And Pray attack path

Plug And Pray 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.

Plug And Pray sanitized attack graph

Walkthrough flow

01

Fingerprint the exposed HTTP gateway page and...

02

Fetch /rootDesc.xml and map advertised UPnP services,...

03

Review the WANIPConnection SCPD and identify...

04

Use minimal SOAP requests to recover provisioning...

05

Use the recovered provisioning credential as the...

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/Plug-and-Pray/writeup.md
  • htb-challenge/Hardware/Plug-and-Pray/notes.md
  • htb-challenge/Hardware/Plug-and-Pray/memory-summary.md
  • htb-challenge/Hardware/Plug-and-Pray/hypothesis-board.md
  • HTB/_knowledge/exports/ctf-lightrag-latest-203412/documents/challenge__Hardware__Plug-and-Pray__memory-summary.md.bb96e224a0.md
  • HTB/_knowledge/exports/ctf-lightrag-latest-203412/documents/challenge__Hardware__Plug-and-Pray__notes.md.8b7ae10459.md

Technical Walkthrough

Writeup

Challenge

  • Name: Plug-and-Pray
  • Category: Hardware
  • Difficulty: Medium
  • Mode: remote

Summary

The target exposed a fake cable gateway administration page. The important

lead was not a normal web login route but the advertised UPnP/IGD descriptor.

The descriptor exposed a WANIPConnection SOAP service with read-only

credential actions. Those credentials unlocked a custom diagnostic SOAP

service whose own SCPD disclosed an unsanitized shell sink in TargetHost.

That chain was used to read the challenge flag from the container.

Artifact Inventory

This was a remote-only challenge, so analysis/artifact-inventory.json

contains no local artifacts. The remote surface was:

  • http://<TARGET>:31846/
  • product page: VortexLink GX3000 Cable Gateway
  • firmware: 4.2.1-RELEASE
  • server: Werkzeug/3.1.8 Python/3.12.13

Analysis

Initial HTTP collection showed the status page and a link to /rootDesc.xml

in analysis/http/get-root.txt and analysis/http/root-surface.md.

/rootDesc.xml, saved in analysis/http/get-rootDesc.xml.txt, advertised

two UPnP services:

  • WANIPConnection:1, control URL /ctl/IPConn, SCPD /WANIPCn.xml
  • DiagnosticService:1, control URL /ctl/Diag, SCPD /diag.xml

analysis/http/get-WANIPCn.xml.txt showed non-standard sensitive actions:

GetUserName and GetPassword. A gated SOAP probe confirmed both returned

values; raw SOAP responses and recovered values are stored only in loot/.

analysis/http/get-diag.xml.txt showed the custom diagnostic service requires

X-Diag-Key: <ISP provisioning password>, and its comment states TargetHost

is passed directly to shell with sanitization deferred to firmware 4.3.x.

The recovered provisioning credential successfully authenticated to GetDeviceInfo, proving

the credential chain.

The first command-injection read tried /flag.txt; that branch was closed

because the file did not exist. A bounded read-only find located

/app/flag.txt, and a final diagnostic request read that path.

Solve

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

From <local workspace>, the final solve flow is:

bash
python3 Hardware/Plug-and-Pray/solve/solve.py \
  --base-url http://<TARGET>:31846 \
  --loot-dir Hardware/Plug-and-Pray/loot \
  --analysis-dir Hardware/Plug-and-Pray/analysis \
  --diag-check

python3 Hardware/Plug-and-Pray/solve/solve.py \
  --base-url http://<TARGET>:31846 \
  --loot-dir Hardware/Plug-and-Pray/loot \
  --analysis-dir Hardware/Plug-and-Pray/analysis \
  --diag-check \
  --run-diag \
  --run-label read-app-flag \
  --target-host '<TARGET>; cat /app/flag.txt' \
  --test-type ping \
  --flag-out Hardware/Plug-and-Pray/loot/flag-candidate.txt

The harness then captured the flag with:

bash
python3 scripts/challenge_harness.py capture-flag Hardware/Plug-and-Pray --from loot/flag-candidate.txt

Flag

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

Lessons

  • For router/gateway-themed hardware challenges with HTTP, inspect UPnP

descriptors and SCPD files before fuzzing generic web paths.

  • Vendor extension comments in XML can be direct vulnerability documentation.
  • Separate recovered provisioning credentials from public analysis; keep raw

SOAP and secrets under loot/.

  • Gate command-injection attempts separately from read-only enumeration, even

when both are reachable through the same SOAP service.

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: Plug-and-Pray
  • Category: Hardware
  • Difficulty: Medium
  • Mode: remote
  • Remote instance: <TARGET>:31846
  • Start time: 2026-06-10T20:41:37Z
  • 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-10T20:41:37Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-10T20:41:46Zartifact inventoryanalysis/artifact-inventory.json0 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-10T20:42:20Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-10T20:42:20Zhypothesis recordedhypothesis-board.mdBlack-box HTTP gateway enumeration: identify GX3000 web routes, static assets, API endpoints, leaked configs, backups, or diagnostics exposing sensitive data.MediumUse curl/httpx-style low-impact requests for headers, redirects, robots, source, JS, common gateway paths, and route discovery before any mutation.
2026-06-10T20:42:20Zresearch taskanalysis/research/task-20260610T204220288660Z-3a79364e.mdResearch task created for advisory investigationMediumRecord research output
2026-06-10T20:42:32Zartifact inventoryanalysis/artifact-inventory.json0 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-10T20:42:32Zcheckpoint recordedanalysis/checkpoint-triage-20260610T204232359130Z-f12abcc6.mdCheckpoint for TRIAGEHighUse checkpoint to drive next decision
2026-06-10T20:43:11ZRAG queryanalysis/rag/rag-query-20260610T204247383885Z-ff39e234.txtRAG helper exited 0; output savedMediumRecord retrieval tag and validation
2026-06-10T20:44:34ZRAG recordanalysis/rag-records.mdRetrieved memory tagged GENERICMediumValidate or reject with live evidence
2026-06-10T20:42:50ZHTTP fingerprintanalysis/http/get-root.txtRoot page is a VortexLink GX3000 gateway status page on Werkzeug/Python, firmware 4.2.1-RELEASE; it links to /rootDesc.xmlHighFetch UPnP descriptor
2026-06-10T20:43:45ZUPnP descriptoranalysis/http/get-rootDesc.xml.txt/rootDesc.xml exposes WANIPConnection at /ctl/IPConn and custom DiagnosticService at /ctl/DiagHighFetch SCPD files
2026-06-10T20:44:19ZSCPD reviewanalysis/http/get-WANIPCn.xml.txt, analysis/http/get-diag.xml.txtWANIPConnection exposes GetUserName and GetPassword; DiagnosticService requires X-Diag-Key: <ISP provisioning password> and warns TargetHost reaches shell unsanitizedHighGate before SOAP retrieval
2026-06-10T20:45:51Zlocal memory recordanalysis/local-memory-records.mdPrior local notes reviewed as fallback/advisory contextMediumValidate against current evidence
2026-06-10T20:46:00Zevaluatoranalysis/evaluator-20260610T204600994304Z-e5d56b44.mdProceedHighRun gated SOAP retrieval against /ctl/IPConn, then evaluate whether returned password unlocks /ctl/Diag.
2026-06-10T20:48:07Zevaluatoranalysis/evaluator-20260610T204807529660Z-8fce91ae.mdProceedHighExecute solve.py --run-diag with a single read-only cat /flag.txt payload, then capture the flag if an HTB value is returned.
2026-06-10T20:49:06Zbranch closedhypothesis-board.mdCommand injection worked, but cat /flag.txt returned file-not-found.HighRerank hypotheses
2026-06-10T20:49:56Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-10T20:51:29Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

  • Remote-only target: http://<TARGET>:31846.
  • Product fingerprint: VortexLink GX3000 Cable Gateway, firmware 4.2.1-RELEASE.
  • HTTP server: Werkzeug/3.1.8 Python/3.12.13.
  • The root status page exposes /rootDesc.xml.
  • /rootDesc.xml advertises:

- WANIPConnection:1 with control URL /ctl/IPConn and SCPD /WANIPCn.xml;

- DiagnosticService:1 with control URL /ctl/Diag and SCPD /diag.xml.

  • /WANIPCn.xml documents read-only GetUserName and GetPassword actions. This directly matches the scenario's sensitive-data-exposure theme.
  • /diag.xml documents a custom diagnostic action requiring X-Diag-Key: <ISP provisioning password> and states TargetHost is passed directly to shell, with sanitization deferred to firmware 4.3.x.
  • SOAP calls to /ctl/IPConn returned a provisioning username and password; raw values are stored only in loot/.
  • The recovered provisioning credential unlocked /ctl/Diag via X-Diag-Key, confirmed by GetDeviceInfo.
  • RunNetworkTest command injection worked through TargetHost.
  • /flag.txt was not present, but bounded file discovery found /app/flag.txt.
  • Reading /app/flag.txt through the diagnostic injection returned the HTB flag, captured to 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: Plug-and-Pray
  • 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. Fingerprint the exposed HTTP gateway page and identify the UPnP descriptor link.
  2. Fetch /rootDesc.xml and map advertised UPnP services, control URLs, and SCPD URLs.
  3. Review the WANIPConnection SCPD and identify non-standard sensitive read actions.
  4. Use minimal SOAP requests to recover provisioning values; keep raw responses and secrets in loot/.
  5. Use the recovered provisioning password as the custom diagnostic service key.
  6. Review the diagnostic SCPD comment documenting an unsanitized TargetHost shell sink.
  7. Use a gated RunNetworkTest payload to locate the flag path, then read the flag file.

Reusable Lessons

  • Router/gateway web challenges may hide the real attack surface in UPnP descriptors rather than visible navigation.
  • SCPD files are both endpoint maps and action schemas; review actions, state variables, and vendor comments closely.
  • Read-only SOAP actions can leak credentials that chain into more privileged diagnostic interfaces.
  • Preserve raw SOAP responses and recovered credentials in loot/; write only redacted summaries to analysis/.

Dead Ends

  • Reading /flag.txt through the confirmed diagnostic command injection failed; bounded path discovery found the real flag path under the application directory.

Tool Quirks

  • The root page includes a very large inline base64 image; avoid treating all src= values as useful routes.
  • challenge_exec.py runs from the project root, so solve script paths and output directories need explicit workspace prefixes.
  • Generic RAG output was only useful as a checklist; live SCPD evidence drove the solve.

Evidence Paths

  • analysis/http/get-root.txt
  • analysis/http/root-surface.md
  • analysis/http/get-rootDesc.xml.txt
  • analysis/http/get-WANIPCn.xml.txt
  • analysis/http/get-diag.xml.txt
  • analysis/wanip-soap-redacted.md
  • analysis/diag-getdeviceinfo-redacted.md
  • analysis/diag-runnetworktest-find-flag-path-redacted.md
  • analysis/diag-runnetworktest-read-app-flag-redacted.md
  • 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
1Black-box HTTP gateway enumeration: identify GX3000 web routes, static assets, API endpoints, leaked configs, backups, or diagnostics exposing sensitive data.Scenario explicitly says a cable gateway exposes HTTP and vendor claims nothing sensitive is exposed; remote target is <TARGET>:31846.Need live HTTP fingerprint, route map, and evidence of a sensitive exposed endpoint or artifact.Use curl/httpx-style low-impact requests for headers, redirects, robots, source, JS, common gateway paths, and route discovery before any mutation.MediumActive

Closed Branches

BranchEvidence TestedFailure OutputReason ClosedRevisit Condition
Assume flag at /flag.txtanalysis/diag-runnetworktest-redacted.mdCommand injection worked, but cat /flag.txt returned file-not-found.Only revisit if later evidence points to /flag.txt or container root changes.

Memory Summary

approval_required: true

Sanitized Memory Summary

Metadata

  • Platform: HackTheBox Challenges
  • Category: Hardware
  • Challenge: Plug-and-Pray
  • 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. Fingerprint the exposed HTTP gateway page and identify the UPnP descriptor link.
  2. Fetch /rootDesc.xml and map advertised UPnP services, control URLs, and SCPD URLs.
  3. Review the WANIPConnection SCPD and identify non-standard sensitive read actions.
  4. Use minimal SOAP requests to recover provisioning values; keep raw responses and secrets in loot/.
  5. Use the recovered provisioning password as the custom diagnostic service key.
  6. Review the diagnostic SCPD comment documenting an unsanitized TargetHost shell sink.
  7. Use a gated RunNetworkTest payload to locate the flag path, then read the flag file.

Reusable Lessons

  • Router/gateway web challenges may hide the real attack surface in UPnP descriptors rather than visible navigation.
  • SCPD files are both endpoint maps and action schemas; review actions, state variables, and vendor comments closely.
  • Read-only SOAP actions can leak credentials that chain into more privileged diagnostic interfaces.
  • Preserve raw SOAP responses and recovered credentials in loot/; write only redacted summaries to analysis/.

Dead Ends

  • Reading /flag.txt through the confirmed diagnostic command injection failed; bounded path discovery found the real flag path under the application directory.

Tool Quirks

  • The root page includes a very large inline base64 image; avoid treating all src= values as useful routes.
  • challenge_exec.py runs from the project root, so solve script paths and output directories need explicit workspace prefixes.
  • Generic RAG output was only useful as a checklist; live SCPD evidence drove the solve.

Evidence Paths

  • analysis/http/get-root.txt
  • analysis/http/root-surface.md
  • analysis/http/get-rootDesc.xml.txt
  • analysis/http/get-WANIPCn.xml.txt
  • analysis/http/get-diag.xml.txt
  • analysis/wanip-soap-redacted.md
  • analysis/diag-getdeviceinfo-redacted.md
  • analysis/diag-runnetworktest-find-flag-path-redacted.md
  • analysis/diag-runnetworktest-read-app-flag-redacted.md
  • solve/solve.py
  • loot/flag.txt

Ingestion Decision

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

Notes

Notes

Scope

  • Challenge: Plug-and-Pray
  • Category: Hardware
  • Difficulty: Medium
  • Mode: remote
  • Remote instance: <TARGET>:31846
  • Start time: 2026-06-10T20:41:37Z
  • 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-10T20:41:37Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-10T20:41:46Zartifact inventoryanalysis/artifact-inventory.json0 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-10T20:42:20Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-10T20:42:20Zhypothesis recordedhypothesis-board.mdBlack-box HTTP gateway enumeration: identify GX3000 web routes, static assets, API endpoints, leaked configs, backups, or diagnostics exposing sensitive data.MediumUse curl/httpx-style low-impact requests for headers, redirects, robots, source, JS, common gateway paths, and route discovery before any mutation.
2026-06-10T20:42:20Zresearch taskanalysis/research/task-20260610T204220288660Z-3a79364e.mdResearch task created for advisory investigationMediumRecord research output
2026-06-10T20:42:32Zartifact inventoryanalysis/artifact-inventory.json0 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-10T20:42:32Zcheckpoint recordedanalysis/checkpoint-triage-20260610T204232359130Z-f12abcc6.mdCheckpoint for TRIAGEHighUse checkpoint to drive next decision
2026-06-10T20:43:11ZRAG queryanalysis/rag/rag-query-20260610T204247383885Z-ff39e234.txtRAG helper exited 0; output savedMediumRecord retrieval tag and validation
2026-06-10T20:44:34ZRAG recordanalysis/rag-records.mdRetrieved memory tagged GENERICMediumValidate or reject with live evidence
2026-06-10T20:42:50ZHTTP fingerprintanalysis/http/get-root.txtRoot page is a VortexLink GX3000 gateway status page on Werkzeug/Python, firmware 4.2.1-RELEASE; it links to /rootDesc.xmlHighFetch UPnP descriptor
2026-06-10T20:43:45ZUPnP descriptoranalysis/http/get-rootDesc.xml.txt/rootDesc.xml exposes WANIPConnection at /ctl/IPConn and custom DiagnosticService at /ctl/DiagHighFetch SCPD files
2026-06-10T20: <REDACTED>, analysis/http/get-diag.xml.txtWANIPConnection exposes GetUserName and GetPassword; DiagnosticService requires `X-Diag-Key: <REDACTED>
2026-06-10T20:45:51Zlocal memory recordanalysis/local-memory-records.mdPrior local notes reviewed as fallback/advisory contextMediumValidate against current evidence
2026-06-10T20: <REDACTED>, then evaluate whether returned password unlocks /ctl/Diag.
2026-06-10T20: <REDACTED>, then capture the flag if an HTB value is returned.
2026-06-10T20: <REDACTED>, but cat /flag.txt returned file-not-found.HighRerank hypotheses
2026-06-10T20: <REDACTED>
2026-06-10T20:51:29Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

  • Remote-only target: http://<TARGET>:31846.
  • Product fingerprint: VortexLink GX3000 Cable Gateway, firmware 4.2.1-RELEASE.
  • HTTP server: Werkzeug/3.1.8 Python/3.12.13.
  • The root status page exposes /rootDesc.xml.
  • /rootDesc.xml advertises:

- WANIPConnection:1 with control URL /ctl/IPConn and SCPD /WANIPCn.xml;

- DiagnosticService:1 with control URL /ctl/Diag and SCPD /diag.xml.

  • /WANIPCn.xml documents read-only GetUserName and GetPassword actions. This directly matches the scenario's sensitive-data-exposure theme.
  • /diag.xml documents a custom diagnostic action requiring X-Diag-Key: <REDACTED>, with sanitization deferred to firmware 4.3.x`.
  • SOAP calls to /ctl/IPConn returned a provisioning username and password; raw values are stored only in loot/.
  • The recovered provisioning credential unlocked /ctl/Diag via X-Diag-Key, confirmed by GetDeviceInfo.
  • RunNetworkTest command injection worked through TargetHost.
  • /flag.txt was not present, but bounded file discovery found /app/flag.txt.
  • Reading /app/flag.txt through the diagnostic injection returned the HTB flag, captured to 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 Plug And Pray, 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.