neven@dimitri-dev:~$
cd ../hackultet-2026

$cat c2.mdMiscHackultet 2026

C2

A forensic image of an infected Windows machine still holds every trace needed to find the malware's command-and-control domain, except the malware binary itself, which a public hash lookup supplies instead.

  • #dfir
  • #kape
  • #timeline-analysis
  • #dns-c2

$man c2

What this one teaches:

  • Building an incident timeline from Windows event logs, prefetch files and NTFS metadata.
  • Recognising DNS-based command-and-control from the DLLs a process loaded, even without network capture.
  • Looking up a file's hash on a public malware database when the file itself was deleted before it could be collected.

Task description

An employee ran malware on their work computer. Find the domain the malware communicated with. The flag is base64-encoded in the subdomain, for example if the malware contacted Q1RGMjAyNlsxMjNd.carnet.hr, the flag is CTF2026[123].

A KAPE forensic collection (about 522 MB, 624 files) from the infected machine is provided.

Identifying the malware

Working through the collected artifacts: Amcache records a binary at C:\Users\hackultet-admin\Downloads\update.exe, a small (7 KB) 32-bit .NET PE file compiled on 2025-08-28, with a SHA1 hash available directly from Amcache and an MD5 hash available separately from a Windows Error Reporting event (ID 1001) logged when the binary crashed.

Building a timeline

Correlating event logs and NTFS metadata (all times UTC, 2026-03-18) lays out exactly what happened:

Time Event
13:54 Machine boots, Defender starts
14:23:59 Defender real-time protection disabled
14:24:19 update.exe downloaded via Edge
14:24:31 update.exe executed
14:24:46 The binary crashes (access violation)
14:25:46 A KAPE collection tool is downloaded, presumably by the investigating team
14:30:49 Defender re-enabled
~14:31 The forensic collection begins

The short window between Defender being disabled and the binary running, followed almost immediately by a crash, is a familiar shape for malware that was interrupted mid-execution, which matters for what comes next: the binary never ran long enough to be flagged and quarantined by any still-running defence, but it also means less of its own runtime behaviour was captured live.

Confirming the communication method, without a network capture

No packet capture was collected, but the decompressed Windows prefetch file for update.exe lists every DLL the process loaded before it crashed, including DNSAPI.DLL, WS2_32.DLL, MSWSOCK.DLL and IPHLPAPI.DLL. A 32-bit .NET binary loading the DNS resolution stack directly, rather than relying on a higher-level HTTP library, points specifically at DNS-based command-and-control, where instructions or exfiltrated data travel as DNS queries rather than ordinary web traffic.

Separately, Windows’ SRUM database (System Resource Usage Monitor, which tracks each application’s network usage even without a packet capture) records roughly 39 KB sent and 60 KB received for update.exe’s app ID, confirming the process did make outbound network contact before it crashed, consistent with the DNS C2 hypothesis even without seeing the traffic directly.

Finding the domain without the binary itself

The malware binary was deleted (moved to the Recycle Bin) before the forensic collection ran, and KAPE’s targeted collection only picked up the small $I metadata file the Recycle Bin keeps for a deleted item, not the actual deleted binary. The three places the domain itself might normally be found, the binary’s own code, the live DNS resolver cache, or network traffic, are all unavailable here: the binary is gone, the cache is memory that wasn’t captured, and there’s no packet capture.

With both hashes in hand from Amcache and the crash report, though, the binary’s identity is independent of whether a copy of it survived on disk. Looking the hash up on VirusTotal (a public service that aggregates analysis of previously submitted files) turns up a prior submission of the exact same binary, including a record of URLs it was observed contacting, among them:

Q1RGMjAyNlsxNTAwODE0Nzk0MjUxOTNd.carnet.hr

Decoding the flag

import base64
base64.b64decode('Q1RGMjAyNlsxNTAwODE0Nzk0MjUxOTNd' + '==')
# b'CTF2026[150081479425193]'
CTF2026[150081479425193]

What made this solvable despite the gap

The investigation never needed to recover the deleted binary directly; every step up to the domain itself (identifying the process, building the timeline, confirming the DNS-based technique) came from standard Windows forensic artifacts that persist independently of whether the file itself survives. The one piece of information genuinely missing locally, the C2 domain baked into the binary’s own code, was recovered instead by treating the binary’s hash as an identifier and checking whether anyone else had already seen and analysed the same file.

$cat flag.txt revealCTF2026[150081479425193]

Written by Neven Marić. This writeup was written with the help of Claude Code (Anthropic).