HTB: OpTinselTrace-5 Writeup
OpTinselTrace-5 - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | OpTinselTrace-5 |
| Category | Digital Forensics & Incident Response (HTB Sherlock) |
| OS | Windows Server (Domain Controller — offline KAPE triage image) |
| Difficulty | Hard |
| Points | N/A |
| Release Date | N/A |
| IP Address | N/A (static forensic artifact bundle, no live host) |
| Author | d3vn0mi |
Machine Rating
⭐⭐⭐⭐☆ (4/5)
Difficulty Assessment:
- Enumeration: ⭐⭐⭐⭐☆
- Real-world: ⭐⭐⭐⭐⭐
- CVE: ⭐⭐⭐☆☆
- CTF-like: ⭐⭐⭐☆☆
Summary
OpTinselTrace-5 (HTB Sherlock #582) is a DFIR case built around a KAPE triage collection from DC01.northpole.local — a domain controller purchased second-hand from an MSSP whose previous tenant was forela.local. The scenario tasks the investigator with proving that Christmas is, in fact, doomed: attackers popped the DC via Zerologon (CVE-2020-1472), planted a literally-named vulnerable_to_zerologon service, pivoted through a compromised bytesparkle account to install a VNC backdoor as a scheduled task, and finished by deploying a NotPetya-flavored XOR “ransomware” DLL (splunk_svc.dll) sideloaded via rundll32.exe. The case is deliberately noisy: a legitimate Domain Admins addition and two leftover scheduled tasks from the server’s previous forela.local life are planted as decoys that have to be manually ruled out. The hardest question — identifying the actual encrypting process — can’t be answered from Sysmon or 4688 (neither covers the relevant window), forcing a pivot into the rarely-used Microsoft-Windows-UAC-FileVirtualization/Operational log to recover the PID from tagged file-write events.
TL;DR: Zerologon (CVE-2020-1472) resets the DC01$ machine account password from an anonymous session → attacker authenticates and installs a rogue service (hAvbdksT.exe) → bytesparkle account is used to register a VNC-backdoor scheduled task (svc_vnc) → a XOR-based ransomware DLL (splunk_svc.dll, key EncryptingC4Fun!) is loaded via rundll32.exe (PID 5828) and encrypts files to .xmax → decrypting OperationStarLightJourney.pdf.xmax reveals the sleigh is pulled by enchanted unicorns.
Reconnaissance
Case Intake & Artifact Recovery
The Sherlock’s bundled evidence file, DC01.northpole.local-KAPE.zip, was delivered as a 0-byte file — a broken download rather than a puzzle. Rather than treat this as unsolvable, I went straight to the HTB v4 API to re-pull the real artifact bundle for Sherlock ID 582:
# Pull sherlock metadata/tasks and the real download link directly from the HTB APIimport lib.htb_api as hc = h.HTBClient()info = c.sherlock_info(582)tasks = c.sherlock_tasks(582)dl = c.sherlock_download_link(582)['url']
# Stream the real (non-zero-byte) archive downr = c.session.get(dl, stream=True, timeout=900)with open('dl.zip', 'wb') as f: for chunk in r.iter_content(1 << 20): f.write(chunk)The archive is protected with two layers of password:
# Outer archive password7z x -y -phacktheblue -oex dl.zipcat ex/DANGER.txt # reveals the inner malware-zip password# -> ZPD8LhraU1hx
# Inner "handle with care" zip holding the suspicious binary7z x -y -pZPD8LhraU1hx -osus ex/encrypted_files_suspicious_file.zipExtraction produced two evidence sets:
kape/DC01.northpole.local-KAPE/uploads/auto/C%3A/...— a full KAPE triage collection off the domain controller, includingWindows/System32/winevt/Logs(all.evtxfiles) andWindows/System32/Tasks(scheduled task XML definitions).sus/encrypted_files_suspicious_file/— the “suspicious file” package:splunk_svc.dll, aREADME.txtransom note, and a set of.xmax-extension files that were the ransomware’s encrypted output, plus the DANGER.txt-referenced malware sample.
Service Enumeration
Parsing the .evtx files required a Python-native EVTX reader since no live host was available to query:
# Minimal EVTX -> (timestamp, event_id, data_dict) extraction helperfrom evtx import PyEvtxParserimport re, json
def recs(path, eids=None): parser = PyEvtxParser(path) for r in parser.records_json(): data = json.loads(r['data']) eid = data['Event']['System']['EventID'] if eids and eid not in eids: continue yield r['timestamp'], eid, dataI ran this against System.evtx and Security.evtx, filtering for the event IDs most relevant to a domain-controller compromise: 7045 (service installed), 4742 (computer account changed), 4624/4625 (logon/failed logon), 4648 (explicit credentials), 4724/4728/4737/4738 (account/group management), and 4688 (process creation, where present).
Vulnerability Assessment
Two findings stood out immediately from System.evtx:
- A service install (EID 7045) literally named
vulnerable_to_zerologon, with an image path of%systemroot%\hAvbdksT.exe— an unmissable, deliberately obvious IOC. - The corresponding
Security.evtxEID 4742** entry showing the **DC01$** machine account's password attribute changed by **ANONYMOUS LOGON`, sourced from an internal jump-host IP — the textbook fingerprint of a Netlogon (Zerologon) machine-account password reset.
This confirmed the initial access vector as CVE-2020-1472 (Zerologon) before any further timeline work was done.
Initial Foothold
Exploitation Path — Zerologon (CVE-2020-1472)
Zerologon abuses a flaw in Microsoft’s implementation of AES-CFB8 within the Netlogon Remote Protocol (MS-NRPC): the IV used to encrypt the NetrServerAuthenticate3 credential exchange is always a fixed all-zero block instead of a random value. Because AES-CFB8 with an all-zero IV and an all-zero plaintext has roughly a 1-in-256 chance of producing an all-zero ciphertext, an attacker can brute-force a valid “authenticated” Netlogon session against a domain controller in a few thousand attempts — with zero credentials — and then use that session to reset the DC’s own machine account (DC01$) password to an empty string via NetrServerPasswordSet2. Once the DC’s own AD computer account is compromised, the attacker effectively has domain-admin-equivalent access via DCSync or by relaying that trust further.
I reconstructed the timeline directly from the two event log artifacts:
# Cross-reference System.evtx (service install) against Security.evtx (4742 password reset)# on the same UTC timestamp window to nail down the exploit timefor ts, eid, d in sorted(system_records): if eid == 7045: print(ts, d['Event']['EventData']) # -> ServiceName: vulnerable_to_zerologon # -> ImagePath: %systemroot%\hAvbdksT.exeResults:
| Evidence | Timestamp (UTC) | Source |
|---|---|---|
Zerologon exploit / DC01$ account password reset (EID 4742, actor ANONYMOUS LOGON) | 2023-12-13 09:24:23 | Security.evtx |
Malicious service vulnerable_to_zerologon → hAvbdksT.exe installed (EID 7045) | 2023-12-13 09:24:24 | System.evtx |
The one-second gap between the account-password reset and the rogue service installation is exactly what you’d expect from an automated Zerologon exploit chain (e.g., the classic zerologon_tester.py → DCSync/secretsdump → service-based command execution workflow): reset the trust, immediately abuse it to push a service.
Post-Exploitation — Persistence & Lateral Activity
With the DC’s machine trust broken, the accounts observed being used across the timeline were Administrator and Bytesparkle. The bytesparkle account was used to register a scheduled task at:
\Microsoft\svc_vncAction: C:\Users\bytesparkle\Downloads\svc\svchost.exeThis is a classic masquerading trick — naming a dropped binary svchost.exe and burying it under a user’s Downloads folder to blend into process-listing noise, while the task path (\Microsoft\svc_vnc) hides among legitimate-looking Microsoft task folders. Functionally, this is a VNC-based remote-access backdoor persistence mechanism.
# Inspecting the Tasks folder pulled by KAPET="kape/DC01.northpole.local-KAPE/uploads/auto/C%3A/Windows/System32/Tasks"for f in "$T/Microsoft/svc_vnc" "$T/lamod.exe" "$T/npcapwatchdog"; do echo "=== $f"; ls -la "$f"doneThat same command surfaced two decoys: scheduled tasks named lamod.exe and npcapwatchdog sitting outside the Microsoft folder tree. Cross-referencing their creation timestamps and registering SIDs against the account-management events showed they predated the Zerologon compromise entirely — leftover artifacts from the server’s prior life on forela.local before it was sold second-hand to Northpole. A second potential decoy — Snowdrop being added to Domain Admins at 09:19:52 — also checked out as legitimate: it traced back to bytesparkle’s own interactive console session from the evening before the attack, not to attacker activity.
Privilege Escalation
Note: as a DFIR Sherlock rather than a live-exploitation box, there is no traditional “privesc” step post-Zerologon — the attacker already holds domain-controller-equivalent trust from the initial foothold. The work here is reconstructing impact (ransomware deployment) and recovering the executing process despite missing telemetry.
Ransomware Analysis — splunk_svc.dll
The splunk_svc.dll sample pulled from the “suspicious file” package strongly resembles a NotPetya-style loader:
strings -n 6 splunk_svc.dll | head -80The strings dump revealed a very telling PDB debug path — Not_Petya_XOR_Dll — immediately flagging this as a XOR-based file-encryption payload rather than a real cryptographic ransomware. Critically, the same strings pass also leaked the plaintext repeating-key XOR key:
EncryptingC4Fun!Sloppy operational security by the “Grinch” threat actor — no key management, no obfuscation, key sitting in cleartext inside the DLL. I wrote a small decryptor and ran it against every .xmax file recovered from the evidence package:
# Repeating-key XOR decryption of the ransomware's .xmax output filesk = b'EncryptingC4Fun!'import glob, os
os.makedirs('/tmp/dec', exist_ok=True)for f in glob.glob('*.xmax'): data = open(f, 'rb').read() out = bytes(b ^ k[i % len(k)] for i, b in enumerate(data)) open(f'/tmp/dec/{os.path.basename(f)[:-5]}', 'wb').write(out) # strips the trailing .xmax extension the ransomware appendedOne of the recovered documents, OperationStarLightJourney.pdf, decrypted cleanly:
pip install pdfminer.sixpython3 -c "from pdfminer.high_level import extract_textprint(extract_text('OperationStarLightJourney.pdf'))"The recovered text described the Celestial Carriage as being “powered by a team of enchanted unicorns” — answering the case’s lore/flavor question about the sleigh creature.
Recovering the Encrypting Process — PID 5828
The hardest question in the case is identifying which running process actually performed the file encryption. Standard telemetry didn’t help:
- No Sysmon was installed/collected on this host.
- Windows Security auditing’s 4688 (process creation) events only covered the boot window, well before the ransomware ran.
Rather than give up, I searched the full KAPE bundle for any other operational log that might tag process execution against file activity, and found Microsoft-Windows-UAC-FileVirtualization/Operational — a log most investigators skip, normally used to track legacy UAC file-virtualization redirects (writes into protected directories by non-elevated processes getting silently redirected to a per-user virtual store):
find . -iname '*UAC-FileVirtualization*'Parsing that log for events tied to the .xmax extension surfaced 46 file-write events, every single one tagged with the same execution metadata:
System/Execution/@ProcessID = 5828Image = rundll32.exeBecause splunk_svc.dll is a DLL (not a standalone EXE), the attacker executed it via rundll32.exe splunk_svc.dll,<entrypoint> — a classic LOLBin technique to run arbitrary DLL code under a trusted Microsoft binary’s process name, evading naive process-name allowlisting. The UAC-FileVirtualization log incidentally captured this because the encryption routine’s file writes into what the OS treated as a UAC-virtualized path were logged with the originating process ID attached — giving up the PID that no other available log source could provide.
Attack Chain Summary
0-byte provided KAPE.zip → re-pulled real bundle via HTB v4 API (7z: hacktheblue → ZPD8LhraU1hx) ↓Zerologon (CVE-2020-1472): DC01$ machine account password reset by ANONYMOUS LOGON [2023-12-13 09:24:23] ↓Rogue service "vulnerable_to_zerologon" → hAvbdksT.exe installed on DC01 [2023-12-13 09:24:24] ↓Attacker operates as Administrator / bytesparkle ↓Persistence: scheduled task \Microsoft\svc_vnc → svc\svchost.exe (VNC backdoor) ↓Ransomware deployment: rundll32.exe (PID 5828) loads splunk_svc.dll ("Not_Petya_XOR_Dll") ↓Files XOR-encrypted with key "EncryptingC4Fun!" → .xmax extension ↓Decryption reveals lore doc: sleigh powered by enchanted Unicorns ↓(Decoys ruled out: legitimate Snowdrop DA addition; leftover forela.local tasks lamod.exe / npcapwatchdog)Tools Used
| Tool | Purpose |
|---|---|
| Custom HTB v4 API client (Python) | Re-downloading the corrupted 0-byte evidence bundle directly from HTB |
7z | Extracting the double-password-protected evidence archives |
evtx (PyEvtxParser, Python) | Parsing System.evtx / Security.evtx into structured JSON records |
strings | Recovering the malware’s PDB debug path and plaintext XOR key from splunk_svc.dll |
| Custom Python XOR decryptor | Reversing the ransomware’s repeating-key XOR encryption on .xmax files |
pdfminer.six / pdftotext | Extracting text from the decrypted OperationStarLightJourney.pdf |
Manual .evtx/Tasks folder review | Ruling out decoys (leftover forela.local scheduled tasks, legitimate DA addition) |
Microsoft-Windows-UAC-FileVirtualization/Operational log | Recovering the encrypting process’s PID (5828) when Sysmon/4688 were unavailable |
Key Learnings
Techniques Practiced
- Reconstructing a Zerologon (CVE-2020-1472) compromise timeline purely from
System.evtx(EID 7045) andSecurity.evtx(EID 4742) artifacts, without a live network capture. - Recovering a ransomware payload’s XOR key via static
stringsanalysis before attempting any deeper reverse engineering. - Writing a minimal, self-contained decryptor to reverse a repeating-key XOR “ransomware” and recover victim documents.
- Identifying LOLBin abuse (
rundll32.exesideloading a malicious DLL) from indirect evidence when direct process-creation telemetry (Sysmon, 4688) is unavailable. - Using an unconventional Windows operational log (
UAC-FileVirtualization) as a substitute source of process-tagged file activity. - Distinguishing genuine decoy/noise artifacts (legacy scheduled tasks from a previous domain tenant, legitimate administrative actions) from real attacker TTPs in a deliberately noisy case.
Lessons Learned
- A DC’s own machine account (
<hostname>$) having its password reset byANONYMOUS LOGON(EID 4742) is one of the highest-confidence single indicators of Zerologon exploitation — it should be an automatic, non-negotiable hunt query on any DC. - Malware authors frequently leave debug artifacts — PDB paths, and in this case the entire symmetric key — sitting in plaintext inside the binary. Running
stringsbefore any disassembly or dynamic analysis can shortcut hours of reverse engineering. - When primary process-creation telemetry (Sysmon, 4688) doesn’t cover the incident window, secondary/operational logs that happen to tag
ProcessIDagainst unrelated activity (here, legacy UAC file virtualization) can still recover attribution — it’s worth enumerating every.evtxin a KAPE bundle, not just the “usual suspects.” - Second-hand/repurposed infrastructure (this DC was previously on
forela.localbefore being sold to Northpole) can carry forward stale artifacts — old scheduled tasks, leftover binaries — that look suspicious but predate the actual incident and must be timeline-correlated out rather than assumed malicious. - If a provided evidence bundle is corrupted (e.g., a 0-byte zip), don’t treat that as a dead end — go back to the platform’s API to re-pull the artifact before concluding the case is unsolvable.
Proof of Ownership
Sherlock: OpTinselTrace-5 (#582)Tasks Completed: 9/9 (100%)Final Flag: <redacted>