Challenge / Web

Interstellar

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

MediumPublished 2025-09-14Sanitized local writeup

Scenario

Interstellar attack path

Interstellar 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 Web evidence, validation, and reusable operator lessons.

Interstellar sanitized attack graph

Walkthrough flow

01

Source and route audit

02

Trust boundary flaw

03

Exploit request chain

04

Admin or proof proof

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.

  • Web/Interstellar/writeup.md
  • htb-challenge/Web/Interstellar/notes.md
  • htb-challenge/Web/Interstellar/memory-summary.md
  • htb-challenge/Web/Interstellar/hypothesis-board.md

Technical Walkthrough

Writeup

Challenge

  • Name: Interstellar
  • Category: Web
  • Difficulty: Medium
  • Mode: hybrid

Summary

Interstellar is a PHP/Smarty web challenge where the intended chain combines an

old URL parser differential with a second-order SQL injection.

The working chain is:

  1. Register and log in as a normal user.
  2. Use communicate.php as an internal POST gadget with a PHP/cURL parser

differential URL.

  1. Abuse that internal request to bypass the <secret redacted> == <TARGET> check on

the name-edit action.

  1. Store a SQL injection payload as the current user's name.
  2. Trigger /, which calls the vulnerable searchUser stored procedure and

evaluates the stored name inside dynamic SQL.

  1. Use SELECT ... INTO OUTFILE to write a small PHP command runner into the

webroot.

  1. Read the randomized root-level flag path with a shell glob.

Artifact Inventory

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

  • files/a12c733c-03de-4b2c-9290-59ba1ef202ea.zip: original HTB archive.
  • files/extracted/challenge/src/: PHP/Smarty application source.
  • files/extracted/challenge/init.sql: database schema and stored procedures.
  • files/extracted/challenge/Dockerfile: deployment detail showing the flag is

moved to a randomized root-level *_flag.txt path.

  • analysis/url-parser-probe-pipe.txt: live validation of the parser

differential URL shape.

  • analysis/ssrf-edit-probe.txt: live validation that SSRF can mutate the

localhost-only edit path.

  • solve/solve.py: final reproducible solver.

Analysis

The source audit found three relevant facts:

  • communicate.php validates a user-supplied URL with <secret redacted>,

parses it with parse_url, requires the parsed host to match

/motherland\.com$/, and then calls cURL using only $parsedUrl['host'].

  • index.php?action=edit is protected by a direct localhost check using

$_SERVER['<secret redacted>'] != '<TARGET>', but accepts new_name without

sanitization when reached locally.

  • init.sql defines searchUser(name) with dynamic SQL:

CONCAT('SELECT * FROM users WHERE name = \'', name, '\'').

The URL payload below passed the PHP-side suffix check but reached localhost

through cURL:

text
1232://user:pass@<TARGET>:80|motherland.com:80/

That was validated non-destructively in analysis/ssrf-edit-probe.txt by

changing a logged-in user's name through the localhost-only edit branch.

The final exploit stores a second-order SQLi payload as the user's name. A later

request to / calls searchUser($_SESSION['name']), which evaluates the

payload in the stored procedure. The payload writes a small PHP command runner

to a random filename in /var/www/html/, then the solver requests it to run

cat /*_flag.txt.

Solve

Run:

bash
cd <local workspace>
python3 scripts/challenge_exec.py Web/Interstellar --phase exploit --output analysis/flag-candidate.txt -- python3 Web/Interstellar/solve/solve.py --base-url http://<TARGET>:32196 --output Web/Interstellar/analysis/flag-candidate.txt --debug-output Web/Interstellar/analysis/exploit-debug.txt
python3 scripts/challenge_harness.py capture-flag Web/Interstellar --from analysis/flag-candidate.txt

The solver creates a fresh account, performs the internal edit through

communicate.php, triggers the SQLi/webshell write, reads the flag, and writes

only the candidate output file for harness capture.

Flag

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

Lessons

  • Parser-differential bugs must be validated against the exact runtime pair.

Here the PHP URL parser and cURL disagreed in a useful way.

  • The SSRF was not the end goal; it was a local-origin primitive that unlocked a

second-order SQL injection.

  • The randomized flag filename made INTO OUTFILE more useful than direct SQL

file reading, because a PHP shell could use filesystem globbing.

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: Interstellar
  • Category: Web
  • Difficulty: Medium
  • Mode: hybrid
  • Remote instance: none
  • Start time: 2026-06-11T22:55:06Z
  • 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/a12c733c-03de-4b2c-9290-59ba1ef202ea.zip166240<hash redacted>Zip archive data, at least v1.0 to extract, compression method=storezip entries: 25 shown in artifact inventory JSON

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-11T22:55:06Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-11T22:55:06Zartifact inventoryanalysis/artifact-inventory.json1 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-11T22:56:26Zhypothesis recordedhypothesis-board.mdRegister/login, then use communicate.php as an SSRF/internal POST gadget: submit URL with host allowed by /motherland\.com$/ and data[action]=edit,data[new_name]=SQLi payload. The internal request carries the <secret redacted> and bypasses <secret redacted> == <TARGET>, storing a malicious session name that later reaches searchUser's dynamic SQL.MediumRegister/login on remote and post data[action]=edit through communicate.php; verify the index name changes or SQL error appears on subsequent /.
2026-06-11T22:56:26Zhypothesis recordedhypothesis-board.mdExploit Smarty/server-side template injection through a name or response rendering path if SQLi only gives errors.MediumSearch templates/PHP for display of user-controlled values and validate escaping locally/from rendered remote output.
2026-06-11T23:01:26Zcheckpoint recordedanalysis/checkpoint-analysis-20260611T230126004068Z-3150fb9b.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-11T23:01:55Zresearch recordanalysis/research/research-records.mdResearch tagged MATCHEDMediumValidate against current evidence
2026-06-11T23:01:55Zsource auditanalysis/source-audit.mdSource audit recordedHighGate before exploit
2026-06-11T23:01:55Zinstrumentation plananalysis/instrumentation-plan.mdExploit Interstellar reproducibly and capture the remote flag without printing it.HighStop after two webshell write attempts without a new SQL error or file-existence signal; record failure and rerank hypotheses.
2026-06-11T23:02:07Zlocal memory recordanalysis/local-memory-records.mdPrior local notes reviewed as fallback/advisory contextMediumValidate against current evidence
2026-06-11T23:02:07Zevaluatoranalysis/evaluator-20260611T230207486374Z-ca8db40f.mdProceedHighRun solve/solve.py through challenge_exec and capture the flag candidate.
2026-06-11T23:03:05Zexploitanalysis/flag-candidate.txtSolver used parser-differential SSRF, second-order SQLi, and INTO OUTFILE webshell write to read the randomized flag pathHighCapture flag through harness
2026-06-11T23:03:11Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-11T23:03:57Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

  • communicate.php validates the parsed host suffix but passes only parse_url($url)['host'] to cURL.
  • The nonstandard URL 1232://user:pass@<TARGET>:80|motherland.com:80/ reaches localhost on the live service.
  • The localhost-only edit branch can store an unsanitized new_name in the active session and database row.
  • searchUser concatenates the stored name into dynamic SQL, creating a second-order SQL injection.
  • The final exploit writes a small PHP command runner with SELECT ... INTO OUTFILE and reads the randomized root-level flag path using a shell glob.

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: Web
  • Challenge: Interstellar
  • 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
1Register/login, then use communicate.php as an SSRF/internal POST gadget: submit URL with host allowed by /motherland\.com$/ and data[action]=edit,data[new_name]=SQLi payload. The internal request carries the <secret redacted> and bypasses <secret redacted> == <TARGET>, storing a malicious session name that later reaches searchUser's dynamic SQL.communicate.php validates url host suffix then cURLs parsed host with http_build_query(data); index.php edit action is localhost-only; init.sql searchUser builds SQL with CONCAT on name.Register/login on remote and post data[action]=edit through communicate.php; verify the index name changes or SQL error appears on subsequent /.MediumActive
2Exploit Smarty/server-side template injection through a name or response rendering path if SQLi only gives errors.Smarty templates render assigned variables, but default escaping/assignment path needs validation; challenge hint says old bug with twist likely SSRF-to-SQLi rather than direct SSTI.Search templates/PHP for display of user-controlled values and validate escaping locally/from rendered remote output.MediumActive

Closed Branches

BranchEvidence TestedFailure OutputReason ClosedRevisit Condition

Technical analogy

How to remember this solve

Think of the web app like a building with signs on every door. The solve usually comes from reading the map carefully, finding the door the app forgot to hide, then sending the exact request that proves you understand the route.

For Interstellar, 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.