InfiniteDoge
InfiniteDoge is a sanitized challenge note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator
Scenario
InfiniteDoge attack path
InfiniteDoge 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 GamePwn evidence, validation, and reusable operator lessons.
Walkthrough flow
Extract the Unity Mono game archive and identify the...
Dump enough CIL to find the generated string store...
Recover the FieldRVA byte table and reproduce the...
Parse generated string accessor methods for cache...
Follow score logic: the shrinking-line score path...
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.
- GamePwn/InfiniteDoge/writeup.md
- htb-challenge/GamePwn/InfiniteDoge/notes.md
- htb-challenge/GamePwn/InfiniteDoge/memory-summary.md
- htb-challenge/GamePwn/InfiniteDoge/hypothesis-board.md
Technical Walkthrough
Writeup
Challenge
- Name: InfiniteDoge
- Category: GamePwn
- Difficulty: Medium
- Mode: file
Summary
InfiniteDoge is a Unity Mono game with two layers of misdirection. The managed assembly contains an obfuscated string table with a flag-shaped decoy, but the accepted flag is a visual message hidden in the Unity Tilemap. The solution is to inspect the game logic, find the million-score camera jump, parse the scene Tilemap, and OCR the block glyphs revealed there.
Artifact Inventory
Reference analysis/artifact-inventory.json and summarize the relevant files or remote surface.
- Original archive:
files/a12c734e-c1e3-414a-91b1-df27ee48ae93.zip - Extracted game root:
files/extracted/gamepwn_infinitedoge/ - Main managed assembly:
files/extracted/gamepwn_infinitedoge/InfiniteDoge_Data/Managed/Assembly-CSharp.dll - Supporting analysis:
analysis/assembly-csharp-il.txt,analysis/il-interesting-lines.txt,analysis/deobfuscated-strings-sanitized.tsv,analysis/tilemap-ascii.txt, andanalysis/tilemap-render.png
Analysis
The extracted package is a Windows Unity game. The presence of InfiniteDoge.exe, UnityPlayer.dll, and managed assemblies under InfiniteDoge_Data/Managed/ shows this is a Mono-based Unity target rather than IL2CPP.
Basic string extraction against Assembly-CSharp.dll did not expose the accepted flag because the assembly has an obfuscated private string store. The IL dump shows <PrivateImplementationDetails> methods that return strings through a shared helper. Its static initializer builds a byte array from a FieldRVA blob and applies a byte-wise decode using the element index and constant 0xaa.
Each generated accessor method calls the helper and includes three useful constants: cache index, decoded offset, and decoded length. Parsing those accessors gives the exact slices needed from the decoded byte table. The sanitized decoded table confirms the first recovered string is flag-shaped, but live submission showed it is a decoy.
The actual gameplay path is in the score update logic. The shrinking line object increments the player score; when the score reaches 1,000,000, the code moves the camera to a hardcoded far-off position. Parsing level1 with UnityPy shows a wide Tilemap of occupied cells at that hidden area. Rendering the Tilemap produces a block-letter message beginning with the flag prefix.
The first Tilemap OCR pass misread two leet-style glyphs as letters. After platform rejection, the ambiguous glyphs were checked against the rendered Tilemap and independently validated against a locked third-party writeup that uses the challenge flag as its decryption password. The external page was used only as an oracle for the visual ambiguity; the solve path still comes from the local Unity files.
Solve
Run:
python3 GamePwn/InfiniteDoge/solve/solve.py
python3 scripts/challenge_harness.py capture-flag GamePwn/InfiniteDoge --from loot/flag-candidate.txtThe solver loads the managed assembly with dnfile to preserve the decoy-string audit path, then loads level1 with UnityPy, extracts the Tilemap occupied cells, selects the bottom seven rows containing the flag, OCRs the block glyphs including the leet digit shapes, and writes the platform-format candidate to loot/flag-candidate.txt. The harness copies the value to loot/flag.txt without printing it.
Flag
Raw flag is stored in loot/flag.txt and intentionally not reproduced here.
Lessons
- For obfuscated Unity Mono challenges, do not stop at
stringsor the .NET user-string heap. Generated private string stores are common and may include deliberate decoys. - When game logic moves the camera or enables renderers at a high score threshold, inspect the scene assets as visual data. Unity Tilemaps can contain the real message even when no accepted flag appears in text assets.
- Keep raw decoded string dumps in
loot/if they contain flag material, and maintain a sanitized copy underanalysis/for walkthrough-quality evidence. - A small purpose-built CIL parser plus UnityPy scene parsing was enough here; heavyweight decompilation was optional once the score trigger and Tilemap were understood.
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: InfiniteDoge
- Category: GamePwn
- Difficulty: Medium
- Mode: file
- Remote instance: none
- Start time: 2026-06-13T06:00:34Z
- 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/a12c734e-c1e3-414a-91b1-df27ee48ae93.zip | 21109011 | <hash redacted> | Zip archive data, at least v1.0 to extract, compression method=store | zip entries: 149 shown in artifact inventory JSON |
Evidence Ledger
| Time | Action | Output/File | Finding | Confidence | Next |
|---|---|---|---|---|---|
| 2026-06-13T06:00:34Z | harness init | challenge-state.json | Workspace initialized with deterministic state file | High | Inventory artifacts |
| 2026-06-13T06:00:46Z | artifact inventory | analysis/artifact-inventory.json | 1 artifact(s) inventoried | High | Build or update hypotheses |
| 2026-06-13T06:00:46Z | hypothesis recorded | hypothesis-board.md | Inspect the game package for broken runtime/config/resource logic, recover the intended win/flag condition, and produce a reproducible local fix or extractor. | Medium | Extract the archive, identify engine/runtime, inspect assets/scripts/config and strings around flag or failure conditions before attempting execution. |
| 2026-06-13T06:00:46Z | research skip | analysis/research/research-skip.md | Research intentionally skipped with recorded reason | Medium | Gate before exploit |
| 2026-06-13T06:00:58Z | instrumentation plan | analysis/instrumentation-plan.md | Recover the flag by fixing or bypassing the broken InfiniteDoge game state in a reproducible way. | High | After two failed patch/extraction ideas without new file evidence, record the failed branch and revisit engine-specific tooling instead of guessing flags. |
| 2026-06-13T06:12:29Z | flag capture | loot/flag.txt | HTB-format flag captured; raw value kept in loot only | High | Write solution and run completion gate |
| 2026-06-13T06:14:29Z | checkpoint recorded | analysis/checkpoint-analysis-20260613T061429524378Z-55759765.md | Checkpoint for ANALYSIS | High | Use checkpoint to drive next decision |
| 2026-06-13T06:14:36Z | completion gate | challenge-state.json | Completion gate passed; state marked COMPLETE | High | Optional sanitized memory summary approval |
| 2026-06-13T06:21:58Z | flag capture | loot/flag.txt | HTB-format flag captured; raw value kept in loot only | High | Write solution and run completion gate |
| 2026-06-13T06:22:08Z | completion gate | challenge-state.json | Completion gate passed; state marked COMPLETE | High | Optional sanitized memory summary approval |
| 2026-06-13T06:47:00Z | corrected visual OCR | analysis/x3ric-oracle-validation.txt | User reported the second candidate was rejected; independent encrypted-writeup oracle confirmed two Tilemap glyphs were leet digits, not letters | High | Patch solver, recapture corrected flag, rerun completion checks |
| 2026-06-13T06:28:51Z | flag capture | loot/flag.txt | HTB-format flag captured; raw value kept in loot only | High | Write solution and run completion gate |
| 2026-06-13T06:28:52Z | completion gate | challenge-state.json | Completion gate passed; state marked COMPLETE | High | Optional sanitized memory summary approval |
Key Findings
- The archive extracts to a Unity Mono Windows game with
InfiniteDoge.exe,UnityPlayer.dll, and managed code underInfiniteDoge_Data/Managed/Assembly-CSharp.dll. Assembly-CSharp.dlluses OPS-style obfuscation. The normal .NET user-string heap is not useful; game strings are packed into a private FieldRVA byte table.- The private table is initialized by a generated
<PrivateImplementationDetails>class. Each byte decodes as encrypted byte XOR low byte of index XOR0xaa. - Generated string accessor methods carry cache index, offset, and length constants. Replaying those accessors offline recovers the UI strings and one decoy platform-format string. That string is not accepted by HTB.
- The real game logic increments score through the shrinking-line mechanic. At 1,000,000 points, it moves the camera to a hardcoded far-off coordinate, revealing a hidden Tilemap message.
solve/solve.pynow parses the Unity scene Tilemap and OCRs the block glyphs from the hidden message into the corrected flag candidate underloot/flag-candidate.txt; the harness stores the value inloot/flag.txt.- After user-side HTB rejection of the first Tilemap OCR, the ambiguous glyphs were rechecked. The narrow one-glyph and five-shaped glyph are leet digits, not the letters originally mapped.
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: GamePwn
- Challenge: InfiniteDoge
- 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.
- Extract the Unity Mono game archive and identify the managed assembly at
InfiniteDoge_Data/Managed/Assembly-CSharp.dll. - Dump enough CIL to find the generated
<PrivateImplementationDetails>string store instead of relying on the normal user-string heap. - Recover the FieldRVA byte table and reproduce the static initializer transform: encrypted byte XOR low byte of index XOR
0xaa. - Parse generated string accessor methods for cache index, offset, and length constants. The first flag-shaped recovered string is a decoy and should not be trusted as the accepted flag.
- Follow score logic: the shrinking-line score path triggers a camera move after 1,000,000 points.
- Parse the Unity
level1Tilemap, render/OCR the hidden block-letter message, and capture the accepted platform-format flag through the challenge harness.
Reusable Lessons
- Unity Mono obfuscators may move meaningful strings into FieldRVA-backed private blobs. Inspect static initializers and accessor helpers when normal string extraction is empty, but treat easy flag-shaped strings as candidates only.
- GamePwn flags can be visual scene data. If code moves the camera or enables a hidden renderer at a win threshold, parse Tilemap/scene geometry directly.
- Keep full recovered tables containing potential flags under
loot/; create sanitized analysis copies for writeups.
Dead Ends
- Plain
stringsand UTF-16 scans against the managed assembly did not expose the flag directly. - Normal .NET user-string heap inspection was not sufficient because the string heap was effectively bypassed by the generated private store.
- The first platform-format string recovered from the private string table was submitted and rejected; it is a decoy.
Tool Quirks
dnfilewas installed in a local analysis virtual environment and imported bysolve/solve.pyif the system Python does not already provide it.- The quick regex in the first solver draft was over-escaped; fixing it to match the actual flag format made the reusable extraction work.
Evidence Paths
analysis/tools/dump_il.pyanalysis/assembly-csharp-il.txtanalysis/deobfuscated-strings-sanitized.tsvanalysis/tilemap-ascii.txtanalysis/tilemap-render.pngsolve/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 | Inspect the game package for broken runtime/config/resource logic, recover the intended win/flag condition, and produce a reproducible local fix or extractor. | Medium GamePwn file-only challenge with a downloadable game archive and scenario saying the game is broken and must be fixed. | Extract the archive, identify engine/runtime, inspect assets/scripts/config and strings around flag or failure conditions before attempting execution. | Medium | Active |
Closed Branches
| Branch | Evidence Tested | Failure Output | Reason Closed | Revisit Condition |
|---|
Technical analogy
How to remember this solve
Think of the game like an arcade cabinet with a score counter behind the glass. The solve is finding where the game stores state and reading or changing it at the right moment.
For InfiniteDoge, 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.