Challenge / Reversing

Gameloader

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

MediumPublished 2025-07-10Sanitized local writeup

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.

Gameloader sanitized attack graph

Walkthrough flow

01

Identify Godot Windows export plus encrypted PCK.

02

Resolve the embedded Godot script encryption key...

03

Decrypt the PCK directory and validate it against the...

04

Recover the Godot project with GDRE Tools using the...

05

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.

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.

  • 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.txt
  • analysis/key-pointer-resolution.txt
  • analysis/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 /enum on 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.json
  • analysis/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.json
  • analysis/remote/download-latin1_hex-meta.json
  • analysis/remote/download-suffix_b64_text-meta.json

Solve

Use the reproducible solver:

bash
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.txt

The 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

FileSizeSHA256TypeNotes
files/a1504f42-6805-4572-8dbe-e8a19085701e.zip18031112<hash redacted>Zip archive data, at least v1.0 to extract, compression method=storezip entries: 3 shown in artifact inventory JSON

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-10T22:17:44Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-10T22:18:24Zartifact inventoryanalysis/artifact-inventory.json1 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-10T22:19:43Zhypothesis recordedhypothesis-board.mdRecover 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.MediumExtract/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:43Zcheckpoint recordedanalysis/checkpoint-triage-20260610T221943972430Z-5cb8a717.mdCheckpoint for TRIAGEHighUse checkpoint to drive next decision
2026-06-10T22:20:38ZRAG queryanalysis/rag/rag-query-20260610T222026264173Z-659c3c05.txtRAG helper exited 0; output savedMediumRecord retrieval tag and validation
2026-06-10T22:20:39Zlocal memory searchanalysis/research/local-memory-search-20260610T222039159715Z-a62e6f97.mdFound 8 safe prior-note result(s)MediumRecord useful result or skip
2026-06-10T22:21:48ZRAG recordanalysis/rag-records.mdRetrieved memory tagged GENERICMediumValidate or reject with live evidence
2026-06-10T22:22:22Zlocal memory recordanalysis/local-memory-records.mdPrior local notes reviewed as fallback/advisory contextMediumValidate against current evidence
2026-06-10T22:32:12Zsource auditanalysis/source-audit.mdSource audit recordedHighGate before exploit
2026-06-10T22:32:22Zevaluatoranalysis/evaluator-20260610T223222350851Z-da4e3425.mdProceedHighgate_before_remote_then_run_solver
2026-06-10T22:33:42Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-10T22:34:36Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-10T22:35:36Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

  • The archive contains a Godot 4.1.1 Windows export: Platformer 2D.exe plus encrypted Platformer 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 under analysis/gdre-recover-keyed/.
  • player/player.gd is the loader. It posts system metadata to a decoded host, downloads a payload from a decoded route with an obfuscated cookie, saves it as new_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.json and analysis/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:

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

  1. Identify Godot Windows export plus encrypted PCK.
  2. Resolve the embedded Godot script encryption key pointer from the executable.
  3. Decrypt the PCK directory and validate it against the directory MD5.
  4. Recover the Godot project with GDRE Tools using the recovered key.
  5. 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.
  6. Decode the obfuscated host/path/cookie/suffix values.
  7. Replay the loader protocol safely without executing the downloaded payload.
  8. 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_key from 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 direct join() 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 in loot/.

Evidence Paths

  • analysis/pck-encrypted-dir-layout.txt
  • analysis/key-pointer-resolution.txt
  • analysis/test-direct-key.txt
  • analysis/gdre-recover-keyed.log
  • analysis/gdre-recover-keyed/player/player.gd
  • analysis/decoded-loader-values-preview.json
  • analysis/remote/download-decimal_join-meta.json
  • 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
1Recover 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.MediumActive

Closed Branches

BranchEvidence TestedFailure OutputReason ClosedRevisit 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.

  1. Identify Godot Windows export plus encrypted PCK.
  2. Resolve the embedded Godot script encryption key pointer from the executable.
  3. Decrypt the PCK directory and validate it against the directory MD5.
  4. Recover the Godot project with GDRE Tools using the recovered key.
  5. 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.
  6. Decode the obfuscated host/path/cookie/suffix values.
  7. Replay the loader protocol safely without executing the downloaded payload.
  8. 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_key from 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 direct join() 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 in loot/.

Evidence Paths

  • analysis/pck-encrypted-dir-layout.txt
  • analysis/key-pointer-resolution.txt
  • analysis/test-direct-key.txt
  • analysis/gdre-recover-keyed.log
  • analysis/gdre-recover-keyed/player/player.gd
  • analysis/decoded-loader-values-preview.json
  • analysis/remote/download-decimal_join-meta.json
  • solve/solve.py
  • loot/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

FileSizeSHA256TypeNotes
files/a1504f42-6805-4572-8dbe-e8a19085701e.zip18031112<hash redacted>Zip archive data, at least v1.0 to extract, compression method=storezip entries: 3 shown in artifact inventory JSON

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-10T22:17:44Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-10T22:18:24Zartifact inventoryanalysis/artifact-inventory.json1 artifact(s) inventoriedHighBuild 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.MediumExtract/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:43Zcheckpoint recordedanalysis/checkpoint-triage-20260610T221943972430Z-5cb8a717.mdCheckpoint for TRIAGEHighUse checkpoint to drive next decision
2026-06-10T22:20:38ZRAG queryanalysis/rag/rag-query-20260610T222026264173Z-659c3c05.txtRAG helper exited 0; output savedMediumRecord retrieval tag and validation
2026-06-10T22:20:39Zlocal memory searchanalysis/research/local-memory-search-20260610T222039159715Z-a62e6f97.mdFound 8 safe prior-note result(s)MediumRecord useful result or skip
2026-06-10T22:21:48ZRAG recordanalysis/rag-records.mdRetrieved memory tagged GENERICMediumValidate or reject with live evidence
2026-06-10T22:22:22Zlocal memory recordanalysis/local-memory-records.mdPrior local notes reviewed as fallback/advisory contextMediumValidate against current evidence
2026-06-10T22:32:12Zsource auditanalysis/source-audit.mdSource audit recordedHighGate before exploit
2026-06-10T22:32:22Zevaluatoranalysis/evaluator-20260610T223222350851Z-da4e3425.mdProceedHighgate_before_remote_then_run_solver
2026-06-10T22: <REDACTED>
2026-06-10T22: <REDACTED>
2026-06-10T22:35:36Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

  • The archive contains a Godot 4.1.1 Windows export: Platformer 2D.exe plus encrypted Platformer 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 under analysis/gdre-recover-keyed/.
  • player/player.gd is the loader. It posts system metadata to a decoded host, downloads a payload from a decoded route with an obfuscated cookie, saves it as new_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.json and analysis/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:

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