zwesty
Write-ups / Day 11 / Metadata
Day 11 · Sun, Oct 11 · Metadata

What's My Name Again?

Prey slaughtered

PE resource directory, VS_VERSIONINFO parsing (OriginalFilename), spotting a renamed binary, strict field matching in a compounding solver

STTMClaude Homebase Both

Flags are shortened to their first 8 and last 4 characters because they're unique per team.

Challenge ID
metadata-forensics-day-11-whats-my-name-again (+ /time_trial, /mastery)
Solved
2026-10-11: Single Solve, Time Trial, and Mastery all CORRECT on the first submit; all three by 09:14:23 ET, 14 min 18 s after our automated morning solver (a scheduled script on our Kali VM) started the Single Solve (about 6 min of that was spent waiting out a rate limit)
Player
Zwesty (solo), with Claude Code (Opus 5.5)

The challenge

"Filenames have been randomized, but Windows version resources remember what the binaries called themselves. Recover the original identities and expose the impersonator."

One question about telemetry-agent-001.exe inside metadata-day-11-evidence.zip.

answer_id Question Format
d09-pe-001-pe-version-original-filename "Determine pe.version_original_filename for telemetry-agent-001.exe." exact_text: the artifact's own text, punctuation kept, no explanation; trimmed

Reading the prompt: what it said we'd need

Clue What it pointed to What I did about it
"Filenames have been randomized" The name in the zip is worthless as an answer Checked what the existing solver would send: the zip name. Day 1's matcher reads any question ID ending in -filename as "the member's name". So the new field had to be matched exactly and checked first
"Windows version resources" The PE's RT_VERSION resource (VS_VERSIONINFO), whose string table holds OriginalFilename Walked the resource directory to it, rather than searching the file for the text
"what the binaries called themselves" The OriginalFilename string, exactly as stored Answered it with no changes
"expose the impersonator" A file whose name on disk doesn't match its recorded identity Every file here was one: telemetry-agent-00N.exe on disk, pe-base-<arch>.exe inside. No separate question asked about it

Safety

  • The artifacts are Windows executables (the Single Solve file is a Go build). Everything was static: the solver reads bytes with struct and never runs or loads a challenge file. pefile was used once as a read-only cross-check.
  • The artifacts stayed on our Kali VM; none were copied to a Windows machine.

What was in the files

  • Single Solve: telemetry-agent-001.exe, a 1.26 MB PE32 (Intel i386) Go binary. Its one version string table (language 040904b0, US English, Unicode) holds CompanyName Huntress Labs, FileVersion 1.0.0.0, OriginalFilename pe-base-386.exe, ProductName Huntress Metadata Forensics, and ProductVersion 2026.10.1.0.
  • Time Trial: the same template with telemetry-agent-002.exe (1.33 MB), whose OriginalFilename was pe-base-amd64.exe.
  • Mastery: an outer zip holding metadata-day-11-evidence-01.zip and -02.zip, one executable each. Their OriginalFilenames were pe-base-arm64.exe and pe-base-386.exe.

The original names follow Go's architecture names (386, amd64, arm64), so this looks like one program built for several targets and then renamed.

Single Solve

The morning solver's prep was wrong. It started the Single Solve, downloaded it, and reported that the latest Metadata solver "answers 1/1 questions". Running that solver on the material showed it would have sent telemetry-agent-001.exe, the randomized name. That's a trap we first met on Day 2: an older day's loose field matcher answers a new question with confidence.

Our solver wraps Day 10's, which wraps Days 1–9. It adds: - a resource-directory walk: data directory 2 → the RT_VERSION (type 16) entry → every name and language → each leaf's data, mapped from RVA to file offset through the section table; - a generic reader for VS_VERSIONINFO nodes (length, value length, type, UTF-16 key, 32-bit alignment, children), which returns one dictionary per string table; - an exact check for question IDs ending in pe-version-original-filename, placed before the older days' matchers. No version resource gives none, the same convention as Days 9–10 for non-PEs (not tested on this field). Two string tables that disagree stop the run instead of guessing; - handling for Mastery questions labelled delivery N: <zip> -> <member>, which this lane hasn't used yet.

The first send of pe-base-386.exe hit HTTP 429. The morning solver had made about 25 requests in 10 seconds and the limit counts every request. One more try two minutes later also got 429. After the limit cleared: CORRECT (a7df8224…b3dd).

Its tests (7, all pass): - a PE with no resources gives no answer, and so does a fake OriginalFilename UTF-16 string outside the resource section (in a PE and in a script); - the real Single Solve answers exactly pe-base-386.exe, and the whole string table reads correctly; - a plain -filename question still means the member's name (Day 1 isn't broken); - a delivery 1: label finds its download, and a mismatched delivery stops; - Day 10's real question still answers 0x00065bd0.

Time Trial

CORRECT on the first attempt. The first start asked for a ranked clock and got 409 timed_intent_not_available: this route doesn't take the opt-in, and nothing started. A plain start was already timed (deadline 7 s after started_at, ranked, 1 unique attempt remaining).

started_at  2026-10-11T13:14:14.761Z
deadline    2026-10-11T13:14:21.761Z   (7 s)
answers     1   pe-base-amd64.exe
start       483 ms
artifact    397 ms
solve         6 ms
submit      645 ms
TOTAL      1.53 s
result      CORRECT   flag 2e64aa5a…88ec

Mastery

CORRECT on the first attempt (2 sets, deadline 7 s, 1 unique attempt remaining).

started_at  2026-10-11T13:14:22.545Z
deadline    2026-10-11T13:14:29.545Z   (7 s)
answers     2   pe-base-arm64.exe, pe-base-386.exe
start       459 ms
artifact    304 ms
solve        11 ms
submit      875 ms
TOTAL      1.65 s
result      CORRECT   flag 8eb3f79c…28fb

Time to solve

The morning solver started and downloaded the Single Solve at 13:00:05 UTC; two manual sends hit HTTP 429, and once the limit cleared the Single Solve went CORRECT at 13:13:49. The ranked Time Trial (1.53 s) and the Mastery (1.65 s) each went CORRECT on the first submit, the Mastery at 13:14:23, 14 min 18 s after the first start.

Takeaways

  • A version resource keeps the name the developer gave the file. Renaming the file on disk doesn't change OriginalFilename, so comparing the two exposes the disguise.
  • Parse the structure; don't search for the string. Walking the resource directory means a decoy OriginalFilename elsewhere in the file can't answer. A test pins this.
  • "The solver already knows this" needs checking. The prep's count was based on a loose match that would have sent a wrong answer with confidence. The new field's check now goes first and matches exactly.
  • The rate limit counts every request. A burst from the morning solver blocked our manual sends for about 7 minutes, the biggest part of today's finish time.