Phoenix Pipeline
Phoenix Pipeline is a sanitized challenge note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator
Scenario
Phoenix Pipeline attack path
Phoenix Pipeline 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 SecureCoding evidence, validation, and reusable operator lessons.
Walkthrough flow
Artifact review
Hypothesis
Validated solve path
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.
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.
- SecureCoding/Phoenix-Pipeline/writeup.md
- htb-challenge/SecureCoding/Phoenix-Pipeline/notes.md
- htb-challenge/SecureCoding/Phoenix-Pipeline/memory-summary.md
- htb-challenge/SecureCoding/Phoenix-Pipeline/hypothesis-board.md
Technical Walkthrough
Writeup
Challenge
- Name: Phoenix-Pipeline
- Category: SecureCoding
- Difficulty: Medium
- Mode: remote
Summary
Phoenix Pipeline was a remote SecureCoding challenge exposed through an HTB Editor interface. The editor allowed source review through /api/directory and /api/file, and validation through /api/verify. The source and bundled exploit scripts pointed to two intended defects: session pollution during registration and a race condition in report photo uploads.
Artifact Inventory
The challenge had no downloadable artifact in this workspace. The remote editor exposed the PHP application source and two proof scripts:
files/remote-source/exploit/exploit_session_puzzling.pyfiles/remote-source/exploit/exploit_file_upload.pyfiles/remote-source/app/Controllers/AuthController.phpfiles/remote-source/app/Controllers/OperatorController.php
The API and frontend route analysis is captured in analysis/remote/api-wrapper-contexts.txt and analysis/remote/directory.json.
Analysis
exploit_session_puzzling.py registered the username admin and then reused the resulting PHP session to request /challenge/admin. The source explained why this worked: AuthController::register() wrote $_SESSION['username'] and $_SESSION['area'] before checking whether the username already existed. Admin authorization was based on $_SESSION['username'] === 'admin', so the duplicate-user path could still leave a privileged session value.
exploit_file_upload.py uploaded shell.php and raced a request to /challenge/uploads/temp_<md5>_<date>.php. The source showed that OperatorController::submitReport() moved the uploaded file into public app/uploads/ before validating MIME type and extension, giving the exploit a short window to execute a public PHP file before it was removed.
RAG output was recorded as partial advisory support only. The source audit in analysis/source-audit.md and the two bundled exploit scripts were the actual evidence.
Solve
The patch was intentionally narrow:
- In
AuthController.php, session assignment was moved until after duplicate username validation and successful user creation. - In
OperatorController.php, extension validation now happens before any move, MIME validation reads the PHP-upload temporary file directly, and only validated images are moved to the final public documentation path.
The remote editor did not overwrite existing files through /api/create-file, so the solve uses the same Socket.IO save path as the frontend. The reproducible sync script is solve/apply_securecoding_patch.py. Its remote readback proof is saved in analysis/remote/patch-sync-result.json.
After both files were saved, /api/verify returned the challenge flag. A redacted verification marker is in analysis/remote/api-verify-final-redacted.json.
Flag
Raw flag is stored in loot/flag.txt and intentionally not reproduced here.
Lessons
- For SecureCoding editor challenges, treat bundled exploit scripts as tests for the intended patch, not as the final action.
- State mutations before validation can create authorization bugs even when database writes fail.
- Never publish untrusted uploads to a web-accessible path before all validation is complete.
- Keep raw flags in
loot/only; use redacted analysis artifacts for walkthrough material.
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: Phoenix-Pipeline
- Category: SecureCoding
- Difficulty: Medium
- Mode: remote
- Remote instance: none
- Start time: 2026-06-11T12:30:19Z
- 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 |
|---|---|---|---|---|
| — | 0 | — | remote-only or no provided files | No local artifacts found under files/ |
Evidence Ledger
| Time | Action | Output/File | Finding | Confidence | Next |
|---|---|---|---|---|---|
| 2026-06-11T12:30:19Z | harness init | challenge-state.json | Workspace initialized with deterministic state file | High | Inventory artifacts |
| 2026-06-11T12:30:33Z | artifact inventory | analysis/artifact-inventory.json | 0 artifact(s) inventoried | High | Build or update hypotheses |
| 2026-06-11T12:31:00Z | hypothesis recorded | hypothesis-board.md | HTB editor exposes source files and a test/submission API for a secure-coding patch workflow | Medium | Fetch the frontend bundle, enumerate API routes, and identify file/test/submit endpoints before mutation |
| 2026-06-11T12:31:00Z | research task | analysis/research/task-20260611T123100732565Z-11d34f75.md | Research task created for advisory investigation | Medium | Record research output |
| 2026-06-11T12:32:27Z | checkpoint recorded | analysis/checkpoint-analysis-20260611T123227864556Z-aacba9dc.md | Checkpoint for ANALYSIS | High | Use checkpoint to drive next decision |
| 2026-06-11T12:35:35Z | RAG query | analysis/rag/rag-query-20260611T123520512045Z-9b8c9866.txt | RAG helper exited 0; output saved | Medium | Record retrieval tag and validation |
| 2026-06-11T12:36:20Z | instrumentation plan | analysis/instrumentation-plan.md | Patch and verify the two source-backed secure-coding vulnerabilities without broad remote probing. | High | Stop if /api/verify reports a different vulnerability, if save fails, or if syntax checks fail locally; do not attempt unrelated exploit chains. |
| 2026-06-11T12:36:20Z | source audit | analysis/source-audit.md | Source audit recorded | High | Gate before exploit |
| 2026-06-11T12:36:20Z | RAG record | analysis/rag-records.md | Retrieved memory tagged PARTIAL | Medium | Validate or reject with live evidence |
| 2026-06-11T12:37:58Z | evaluator | analysis/evaluator-20260611T123758722876Z-ec1d6621.md | Proceed | High | Apply only AuthController.php and OperatorController.php patches, then call /api/verify. |
| 2026-06-11T12:41:20Z | flag capture | loot/flag.txt | HTB-format flag captured; raw value kept in loot only | High | Write solution and run completion gate |
| 2026-06-11T12:42:22Z | completion gate | challenge-state.json | Completion gate passed; state marked COMPLETE | High | Optional sanitized memory summary approval |
Key Findings
- Port
31332served an HTB Editor frontend with/api/directory,/api/file,/api/verify, and Socket.IO save functionality. Port32223refused TCP connections during baseline. - The recovered source exposed two intended vulnerable flows and matching proof scripts under
exploit/. AuthController::register()set$_SESSION['username']before duplicate username validation. Registeringadmincould leave an admin-valued session even when the account insert did not occur.OperatorController::submitReport()moved uploaded content into publicapp/uploads/as a predictabletemp_<md5>_<date>.<ext>before MIME and extension validation, creating a race window for a public PHP upload.- Minimal fixes were applied only to
app/Controllers/AuthController.phpandapp/Controllers/OperatorController.php. - Remote patch synchronization used the editor Socket.IO save path and verified readback hashes in
analysis/remote/patch-sync-result.json. - Final
/api/verifyreturned success. The raw flag is stored only inloot/flag.txt.
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: SecureCoding
- Challenge: Phoenix-Pipeline
- 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.
| Rank | Path | Evidence | Missing Proof | Cheapest Validation | Confidence | Status |
|---|---|---|---|---|---|---|
| 1 | HTB editor exposes source files and a test/submission API for a secure-coding patch workflow | Port 31332 serves an HTB Editor Vite frontend with bundled JS assets | Fetch the frontend bundle, enumerate API routes, and identify file/test/submit endpoints before mutation | Medium | Active |
Closed Branches
| Branch | Evidence Tested | Failure Output | Reason Closed | Revisit Condition |
|---|
Technical analogy
How to remember this solve
Think of it like inspecting a building plan for missing guardrails. You follow each trust boundary and ask what happens if a user controls more input than the developer expected.
For Phoenix Pipeline, 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.