Gameloader
Gameloader is a sanitized challenge note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator
Scenario
Gameloader attack path
Gameloader 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.
Walkthrough flow
Identify Godot Windows export plus encrypted PCK.
Resolve the embedded Godot script encryption key...
Decrypt the PCK directory and validate it against the...
Recover the Godot project with GDRE Tools using the...
Inspect the recovered player script; it acts as a...
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.
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/Gameloader/writeup.md
- htb-challenge/Reversing/Gameloader/notes.md
- htb-challenge/Reversing/Gameloader/memory-summary.md
- htb-challenge/Reversing/Gameloader/hypothesis-board.md
- HTB/_knowledge/exports/ctf-lightrag-latest-203412/documents/challenge__Reversing__Gameloader__memory-summary.md.77782e6e5e.md
- HTB/_knowledge/exports/ctf-lightrag-latest-203412/documents/challenge__Reversing__Gameloader__notes.md.a1767d9867.md
Technical Walkthrough
Writeup
Challenge
- Name: Gameloader
- Category: Reversing
- Difficulty: Medium
- Mode: hybrid
Summary
Gameloader is a Godot game export that doubles as a loader. The main work was recovering the encrypted PCK, decompiling the GDScript, decoding its obfuscated HTTP protocol, and replaying that protocol safely. The remote response supplied one flag fragment in a header, while the recovered GDScript supplied the closing suffix.
Artifact Inventory
files/a1504f42-6805-4572-8dbe-e8a19085701e.zip: original challenge archive.analysis/extracted/rev_gameloader/Platformer 2D.exe: Godot 4.1.1 Windows export executable.analysis/extracted/rev_gameloader/Platformer 2D.pck: encrypted Godot pack file.- Remote service:
<TARGET>:31361.
Analysis
The PCK header showed an encrypted directory. The embedded Godot export was inspected for the script encryption key path, and the key pointer was resolved from the executable. The recovered key decrypted the PCK directory and matched the expected MD5, which proved the key was correct.
Evidence:
analysis/pck-encrypted-dir-layout.txtanalysis/key-pointer-resolution.txtanalysis/test-direct-key.txt
GDRE Tools then recovered the Godot project. The relevant recovered script is analysis/gdre-recover-keyed/player/player.gd.
The loader behavior in player.gd is:
- build obfuscated base64 strings in
_ready() - POST system metadata to
/enumon a decoded host - GET a decoded payload route with a cookie
- save the response as
new_level_mod.exe - execute the payload with an MD5 argument derived from another decoded string
Decoded values are stored in:
analysis/decoded-loader-values-preview.jsonanalysis/remote/decoded-loader-values.json
The cookie construction is intentionally different from the other decoded strings. The URL, route, and MD5 input use char(x) before base64 decoding, but the cookie uses direct join semantics. The live service proved the decimal-joined interpretation because that request returned the payload, while the Latin-1 and suffix-only controls returned 403.
Evidence:
analysis/remote/download-decimal_join-meta.jsonanalysis/remote/download-latin1_hex-meta.jsonanalysis/remote/download-suffix_b64_text-meta.json
Solve
Use the reproducible solver:
cd <local workspace>
python3 Reversing/Gameloader/solve/solve.py \
--base-url http://<TARGET>:31361 \
--output-dir Reversing/Gameloader/analysis/remote \
--flag-output Reversing/Gameloader/loot/flag-candidate.txt
python3 scripts/challenge_harness.py capture-flag Reversing/Gameloader --from loot/flag-candidate.txtThe solver does not execute the downloaded Windows payload. It treats the payload as data, stores remote responses in analysis/remote/, redacts the flag fragment from analysis metadata, and writes the full candidate to loot/ only.
Flag
Raw flag is stored in loot/flag.txt and intentionally not reproduced here.
Lessons
- For Godot exports, the PCK may be encrypted with the embedded script encryption key rather than plainly extractable.
- Validate decrypted PCK directories with the pack MD5 before trusting recovered assets.
- Preserve semantic differences in obfuscated code. Here,
char(x)decoding and direct integer joining produced different candidate cookies; only one matched the live service. - Treat downloaded challenge payloads as untrusted binaries. Static analysis and protocol replay were enough for this solve.
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: Gameloader
- Category: Reversing
- Difficulty: Medium
- Mode: hybrid
- Remote instance: <TARGET>:31361
- Start time: 2026-06-10T22:17:44Z
- 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 |
|---|---|---|---|---|
files/a1504f42-6805-4572-8dbe-e8a19085701e.zip | 18031112 | <hash redacted> | Zip archive data, at least v1.0 to extract, compression method=store | zip entries: 3 shown in artifact inventory JSON |
Evidence Ledger
| Time | Action | Output/File | Finding | Confidence | Next |
|---|---|---|---|---|---|
| 2026-06-10T22:17:44Z | harness init | challenge-state.json | Workspace initialized with deterministic state file | High | Inventory artifacts |
| 2026-06-10T22:18:24Z | artifact inventory | analysis/artifact-inventory.json | 1 artifact(s) inventoried | High | Build or update hypotheses |
| 2026-06-10T22:19:43Z | hypothesis recorded | hypothesis-board.md | Recover the Godot 4 project from the PCK/EXE, inspect scripts/assets for the game-loader compromise path, and combine the local artifact flag part with the live remote behavior if required. | Medium | Extract/recover PCK with a Godot-aware tool, inspect recovered GDScript/resources, then test the remote service only after the local trigger/protocol is understood. |
| 2026-06-10T22:19:43Z | checkpoint recorded | analysis/checkpoint-triage-20260610T221943972430Z-5cb8a717.md | Checkpoint for TRIAGE | High | Use checkpoint to drive next decision |
| 2026-06-10T22:20:38Z | RAG query | analysis/rag/rag-query-20260610T222026264173Z-659c3c05.txt | RAG helper exited 0; output saved | Medium | Record retrieval tag and validation |
| 2026-06-10T22:20:39Z | local memory search | analysis/research/local-memory-search-20260610T222039159715Z-a62e6f97.md | Found 8 safe prior-note result(s) | Medium | Record useful result or skip |
| 2026-06-10T22:21:48Z | RAG record | analysis/rag-records.md | Retrieved memory tagged GENERIC | Medium | Validate or reject with live evidence |
| 2026-06-10T22:22:22Z | local memory record | analysis/local-memory-records.md | Prior local notes reviewed as fallback/advisory context | Medium | Validate against current evidence |
| 2026-06-10T22:32:12Z | source audit | analysis/source-audit.md | Source audit recorded | High | Gate before exploit |
| 2026-06-10T22:32:22Z | evaluator | analysis/evaluator-20260610T223222350851Z-da4e3425.md | Proceed | High | gate_before_remote_then_run_solver |
| 2026-06-10T22:33:42Z | flag capture | loot/flag.txt | HTB-format flag captured; raw value kept in loot only | High | Write solution and run completion gate |
| 2026-06-10T22:34:36Z | flag capture | loot/flag.txt | HTB-format flag captured; raw value kept in loot only | High | Write solution and run completion gate |
| 2026-06-10T22:35:36Z | completion gate | challenge-state.json | Completion gate passed; state marked COMPLETE | High | Optional sanitized memory summary approval |
Key Findings
- The archive contains a Godot 4.1.1 Windows export:
Platformer 2D.exeplus encryptedPlatformer 2D.pck. - The PCK directory is encrypted. Static analysis of the embedded Godot export resolved the 32-byte script encryption key pointer, and <secret redacted> validation matched the PCK directory MD5. Evidence:
analysis/key-pointer-resolution.txt,analysis/test-direct-key.txt,analysis/pck-encrypted-dir-layout.txt. - GDRE Tools recovered the project successfully. Evidence:
analysis/gdre-recover-keyed.log, recovered source underanalysis/gdre-recover-keyed/. player/player.gdis the loader. It posts system metadata to a decoded host, downloads a payload from a decoded route with an obfuscated cookie, saves it asnew_level_mod.exe, then executes it with the MD5 of a decoded suffix as an argument.- Offline decode output is preserved in
analysis/decoded-loader-values-preview.jsonandanalysis/remote/decoded-loader-values.json. These files intentionally omit the final raw flag. - The live service accepted only the decimal-joined cookie interpretation and returned a PE payload plus a redacted partial-flag response header. Evidence:
analysis/remote/download-decimal_join-meta.json; rejected controls:analysis/remote/download-latin1_hex-meta.json,analysis/remote/download-suffix_b64_text-meta.json. - The final flag was composed from the live response header fragment plus the statically recovered decoded suffix and captured through the harness. Raw flag value is stored only in
loot/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: Reversing
- Challenge: Gameloader
- 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.
- Identify Godot Windows export plus encrypted PCK.
- Resolve the embedded Godot script encryption key pointer from the executable.
- Decrypt the PCK directory and validate it against the directory MD5.
- Recover the Godot project with GDRE Tools using the recovered key.
- Inspect the recovered player script; it acts as a loader that posts host metadata, downloads a payload, and executes it with a decoded MD5 argument.
- Decode the obfuscated host/path/cookie/suffix values.
- Replay the loader protocol safely without executing the downloaded payload.
- Combine the live response header fragment with the statically decoded suffix; store the raw result only in
loot/.
Reusable Lessons
- Godot encrypted PCK challenges may require recovering
script_encryption_keyfrom the export executable before GDRE Tools can recover scripts. - Validate candidate Godot PCK keys with the encrypted directory MD5 before attempting full recovery.
- When recovered GDScript mixes
char(x)conversion and directjoin()semantics, preserve the distinction; it can affect the live protocol. - Challenge malware/loaders should be replayed and inspected as data where possible. Avoid executing downloaded binaries when the protocol and static artifacts are sufficient.
Dead Ends
- Treating the PCK as a normal unencrypted pack was insufficient.
- Treating every integer array as
char(x)output produced the wrong cookie interpretation. - Searching recovered payload strings for a full embedded flag was not sufficient; the decisive fragment was delivered by response metadata.
Tool Quirks
- GDRE Tools macOS CLI required
--headless --recover=<pck> --key=<hex> --output=<dir>for this artifact. - Private CTF RAG returned no useful challenge-specific match; local artifact evidence drove the solve.
- The solver redacts flag-like response headers in
analysis/and stores the raw final value only inloot/.
Evidence Paths
analysis/pck-encrypted-dir-layout.txtanalysis/key-pointer-resolution.txtanalysis/test-direct-key.txtanalysis/gdre-recover-keyed.loganalysis/gdre-recover-keyed/player/player.gdanalysis/decoded-loader-values-preview.jsonanalysis/remote/download-decimal_join-meta.jsonsolve/solve.pyloot/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.
| Rank | Path | Evidence | Missing Proof | Cheapest Validation | Confidence | Status |
|---|---|---|---|---|---|---|
| 1 | Recover the Godot 4 project from the PCK/EXE, inspect scripts/assets for the game-loader compromise path, and combine the local artifact flag part with the live remote behavior if required. | Archive contains a Godot Windows executable and PCK; PCK strings expose GDScript resources, game scenes, and multiple flag-related strings but no direct HTB flag. | Extract/recover PCK with a Godot-aware tool, inspect recovered GDScript/resources, then test the remote service only after the local trigger/protocol is understood. | Medium | Active |
Closed Branches
| Branch | Evidence Tested | Failure Output | Reason Closed | Revisit Condition |
|---|
Memory Summary
approval_required: true
Sanitized Memory Summary
Metadata
- Platform: HackTheBox Challenges
- Category: Reversing
- Challenge: Gameloader
- 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.
- Identify Godot Windows export plus encrypted PCK.
- Resolve the embedded Godot script encryption key pointer from the executable.
- Decrypt the PCK directory and validate it against the directory MD5.
- Recover the Godot project with GDRE Tools using the recovered key.
- Inspect the recovered player script; it acts as a loader that posts host metadata, downloads a payload, and executes it with a decoded MD5 argument.
- Decode the obfuscated host/path/cookie/suffix values.
- Replay the loader protocol safely without executing the downloaded payload.
- Combine the live response header fragment with the statically decoded suffix; store the raw result only in
loot/.
Reusable Lessons
- Godot encrypted PCK challenges may require recovering
script_encryption_keyfrom the export executable before GDRE Tools can recover scripts. - Validate candidate Godot PCK keys with the encrypted directory MD5 before attempting full recovery.
- When recovered GDScript mixes
char(x)conversion and directjoin()semantics, preserve the distinction; it can affect the live protocol. - Challenge malware/loaders should be replayed and inspected as data where possible. Avoid executing downloaded binaries when the protocol and static artifacts are sufficient.
Dead Ends
- Treating the PCK as a normal unencrypted pack was insufficient.
- Treating every integer array as
char(x)output produced the wrong cookie interpretation. - Searching recovered payload strings for a full embedded flag was not sufficient; the decisive fragment was delivered by response metadata.
Tool Quirks
- GDRE Tools macOS CLI required
--headless --recover=<pck> --key=<hex> --output=<dir>for this artifact. - Private CTF RAG returned no useful challenge-specific match; local artifact evidence drove the solve.
- The solver redacts flag-like response headers in
analysis/and stores the raw final value only inloot/.
Evidence Paths
analysis/pck-encrypted-dir-layout.txtanalysis/key-pointer-resolution.txtanalysis/test-direct-key.txtanalysis/gdre-recover-keyed.loganalysis/gdre-recover-keyed/player/player.gdanalysis/decoded-loader-values-preview.jsonanalysis/remote/download-decimal_join-meta.jsonsolve/solve.pyloot/flag.txt
Ingestion Decision
- Proposed for LightRAG: yes
- Requires user approval before ingestion: yes
Notes
Notes
Scope
- Challenge: Gameloader
- Category: Reversing
- Difficulty: Medium
- Mode: hybrid
- Remote instance: <TARGET>:31361
- Start time: 2026-06-10T22:17:44Z
- 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 |
|---|---|---|---|---|
files/a1504f42-6805-4572-8dbe-e8a19085701e.zip | 18031112 | <hash redacted> | Zip archive data, at least v1.0 to extract, compression method=store | zip entries: 3 shown in artifact inventory JSON |
Evidence Ledger
| Time | Action | Output/File | Finding | Confidence | Next |
|---|---|---|---|---|---|
| 2026-06-10T22:17:44Z | harness init | challenge-state.json | Workspace initialized with deterministic state file | High | Inventory artifacts |
| 2026-06-10T22:18:24Z | artifact inventory | analysis/artifact-inventory.json | 1 artifact(s) inventoried | High | Build or update hypotheses |
| 2026-06-10T22: <REDACTED>, inspect scripts/assets for the game-loader compromise path, and combine the local artifact flag part with the live remote behavior if required. | Medium | Extract/recover PCK with a Godot-aware tool, inspect recovered GDScript/resources, then test the remote service only after the local trigger/protocol is understood. | |||
| 2026-06-10T22:19:43Z | checkpoint recorded | analysis/checkpoint-triage-20260610T221943972430Z-5cb8a717.md | Checkpoint for TRIAGE | High | Use checkpoint to drive next decision |
| 2026-06-10T22:20:38Z | RAG query | analysis/rag/rag-query-20260610T222026264173Z-659c3c05.txt | RAG helper exited 0; output saved | Medium | Record retrieval tag and validation |
| 2026-06-10T22:20:39Z | local memory search | analysis/research/local-memory-search-20260610T222039159715Z-a62e6f97.md | Found 8 safe prior-note result(s) | Medium | Record useful result or skip |
| 2026-06-10T22:21:48Z | RAG record | analysis/rag-records.md | Retrieved memory tagged GENERIC | Medium | Validate or reject with live evidence |
| 2026-06-10T22:22:22Z | local memory record | analysis/local-memory-records.md | Prior local notes reviewed as fallback/advisory context | Medium | Validate against current evidence |
| 2026-06-10T22:32:12Z | source audit | analysis/source-audit.md | Source audit recorded | High | Gate before exploit |
| 2026-06-10T22:32:22Z | evaluator | analysis/evaluator-20260610T223222350851Z-da4e3425.md | Proceed | High | gate_before_remote_then_run_solver |
| 2026-06-10T22: <REDACTED> | |||||
| 2026-06-10T22: <REDACTED> | |||||
| 2026-06-10T22:35:36Z | completion gate | challenge-state.json | Completion gate passed; state marked COMPLETE | High | Optional sanitized memory summary approval |
Key Findings
- The archive contains a Godot 4.1.1 Windows export:
Platformer 2D.exeplus encryptedPlatformer 2D.pck. - The PCK directory is encrypted. Static analysis of the embedded Godot export resolved the 32-byte script encryption key pointer, and <secret redacted> validation matched the PCK directory MD5. Evidence:
analysis/key-pointer-resolution.txt,analysis/test-direct-key.txt,analysis/pck-encrypted-dir-layout.txt. - GDRE Tools recovered the project successfully. Evidence:
analysis/gdre-recover-keyed.log, recovered source underanalysis/gdre-recover-keyed/. player/player.gdis the loader. It posts system metadata to a decoded host, downloads a payload from a decoded route with an obfuscated cookie, saves it asnew_level_mod.exe, then executes it with the MD5 of a decoded suffix as an argument.- Offline decode output is preserved in
analysis/decoded-loader-values-preview.jsonandanalysis/remote/decoded-loader-values.json. These files intentionally omit the final raw flag. - The live service accepted only the decimal-joined cookie interpretation and returned a PE payload plus a redacted partial-flag response header. Evidence: <REDACTED>,
analysis/remote/download-suffix_b64_text-meta.json. - The final flag was composed from the live response header fragment plus the statically recovered decoded suffix and captured through the harness. Raw flag value is stored only in
loot/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.
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 Gameloader, 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.