Challenge / GamePwn

InfiniteDoge

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

MediumPublished 2024-08-07Sanitized local writeup

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.

InfiniteDoge sanitized attack graph

Walkthrough flow

01

Extract the Unity Mono game archive and identify the...

02

Dump enough CIL to find the generated string store...

03

Recover the FieldRVA byte table and reproduce the...

04

Parse generated string accessor methods for cache...

05

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.

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.

  • 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, and analysis/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:

bash
python3 GamePwn/InfiniteDoge/solve/solve.py
python3 scripts/challenge_harness.py capture-flag GamePwn/InfiniteDoge --from loot/flag-candidate.txt

The 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 strings or 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 under analysis/ 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

FileSizeSHA256TypeNotes
files/a12c734e-c1e3-414a-91b1-df27ee48ae93.zip21109011<hash redacted>Zip archive data, at least v1.0 to extract, compression method=storezip entries: 149 shown in artifact inventory JSON

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-13T06:00:34Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-13T06:00:46Zartifact inventoryanalysis/artifact-inventory.json1 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-13T06:00:46Zhypothesis recordedhypothesis-board.mdInspect the game package for broken runtime/config/resource logic, recover the intended win/flag condition, and produce a reproducible local fix or extractor.MediumExtract the archive, identify engine/runtime, inspect assets/scripts/config and strings around flag or failure conditions before attempting execution.
2026-06-13T06:00:46Zresearch skipanalysis/research/research-skip.mdResearch intentionally skipped with recorded reasonMediumGate before exploit
2026-06-13T06:00:58Zinstrumentation plananalysis/instrumentation-plan.mdRecover the flag by fixing or bypassing the broken InfiniteDoge game state in a reproducible way.HighAfter 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:29Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-13T06:14:29Zcheckpoint recordedanalysis/checkpoint-analysis-20260613T061429524378Z-55759765.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-13T06:14:36Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval
2026-06-13T06:21:58Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-13T06:22:08Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval
2026-06-13T06:47:00Zcorrected visual OCRanalysis/x3ric-oracle-validation.txtUser reported the second candidate was rejected; independent encrypted-writeup oracle confirmed two Tilemap glyphs were leet digits, not lettersHighPatch solver, recapture corrected flag, rerun completion checks
2026-06-13T06:28:51Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-13T06:28:52Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

  • The archive extracts to a Unity Mono Windows game with InfiniteDoge.exe, UnityPlayer.dll, and managed code under InfiniteDoge_Data/Managed/Assembly-CSharp.dll.
  • Assembly-CSharp.dll uses 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 XOR 0xaa.
  • 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.py now parses the Unity scene Tilemap and OCRs the block glyphs from the hidden message into the corrected flag candidate under loot/flag-candidate.txt; the harness stores the value in loot/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:

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

  1. Extract the Unity Mono game archive and identify the managed assembly at InfiniteDoge_Data/Managed/Assembly-CSharp.dll.
  2. Dump enough CIL to find the generated <PrivateImplementationDetails> string store instead of relying on the normal user-string heap.
  3. Recover the FieldRVA byte table and reproduce the static initializer transform: encrypted byte XOR low byte of index XOR 0xaa.
  4. 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.
  5. Follow score logic: the shrinking-line score path triggers a camera move after 1,000,000 points.
  6. Parse the Unity level1 Tilemap, 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 strings and 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

  • dnfile was installed in a local analysis virtual environment and imported by solve/solve.py if 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.py
  • analysis/assembly-csharp-il.txt
  • analysis/deobfuscated-strings-sanitized.tsv
  • analysis/tilemap-ascii.txt
  • analysis/tilemap-render.png
  • 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
1Inspect 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.MediumActive

Closed Branches

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