PfSense Vulnerabilities Part 1: XSS

Introduction

For those of you who don't know, PfSense is an open-source network firewall distribution based on FreeBSD operating system used by many companies worldwide to protect their infrastructure.

Up until now, it has been more than a year since we've reported a number of security vulnerabilities existing in PfSense to the PfSense security team. At this point, we've given the companies and individuals using PfSense enough time to protect their assets by patching to the latest version of PfSense. Since enough time has passed, we though we might share the vulnerabilities with the world in order for security researchers to gain from the shared knowledge.

In this article we'll present the CVE-2014-4687 vulnerability existing in pfSense version <= 2.1.3. In later versions of pfSense, the vulnerabilities have been successfully remediated and are no longer present.

Stored XSS in Schedules

If we click on Schedules, we're presented with a web interface shown below.

xss1 Figure 1: Schedules web interface

Then we can add a schedule by pressing the + button. When doing so, we can change the starttime0 POST parameter into "0:00'><script>alert(1);</script><" as highlighted on the picture below.

xss2 Figure 2: A request with malicious JavaScript sent to the server

The inputted JavaScript is then written in response without proper encapsulation of special characters. We can see the response on the picture below.

xss3 Figure 3: A malicious JavaScript contained in response

Once the request is shown in a web browser, it's evident that XSS is possible, because the JavaScript is executed as presented below.

xss4 Figure 4: The included JavaScript executed in the browser

The vulnerability can be used to execute arbitrary JavaScript in the user's web browser, therefore stealing the user's session cookie.

Stored XSS in rss.widget.php

A php script widgets/widgets/rss.widget.php contains a stored vulnerability, more precisely in the POST parameter rssfeed. The vulnerable code can be seen below, where the source code lines following the vulnerability have been properly highlighted.

  <?php
  if($POST[rssfeed]) {
  $config[widgets][rssfeed] = str_replace(n, ,, $POST[rssfeed]);
  $config[widgets][rssmaxitems] = str_replace(n, ,,
POST[rssmaxitems]);
  $config[widgets][rsswidgetheight] = $POST[rsswidgetheight];
  $config[widgets][rsswidgettextlength] = $POST[rsswidgettextlength];
  writeconfig(Saved RSS Widget feed via Dashboard);
  Header(Location: /);
  }
  if($config[widgets][rssfeed])
  $textareatxt = strreplace(,, n, $config[widgets][rssfeed]);
  else
  $textareatxt = "";
  ?>
  <textarea name="rssfeed" class="formfld unknown" id="rssfeed"
ols="40" rows="3">
  <?=$textareatxt;?>
  </textarea>

The following request was sent to the web server passing the malicious JavaScript in the rssfeed POST parameter.

image051 Figure 5: including a malicious JavaScript in rssfeed POST parameter

The returned response contains the following code, where the special characters have not been properly encoded.

image052 Figure 6: Previously sent malicious JavaScript code is directly included into the returned web page

The following POST parameters are also vulnerable, which are located in the same script:

  • rssmaxitems
  • rsswidgetheight
  • rsswidgettextlength
  • rsswidgettextlength

An attacker can send malicious JavaScript to the web application where it's stored and served to other users as well.

Reflected XSS in services_status.widget.php

The script widgets/widgets/services_status.widget.php doesn't properly encapsulate the user-supplied data. The code below presents part, where we're assigning the value of the POST variable servicestatusfilter to $config[widgets'][servicestatusfilter]' directly without prior sanitation. Then we're displaying that value in the HTML code.

  <?php
  if(isset($_POST['servicestatusfilter'])) {
  $config['widgets']['servicestatusfilter'] =
_POST['servicestatusfilter'];
  write_config("Saved Service Status Filter via Dashboard");
  header("Location: ../../index.php");
  }
  ?>
  <input type="text" size="30" name="servicestatusfilter"
lass="formfld unknown" id="servicestatusfilter" value="<?=
config['widgets']['servicestatusfilter'] ?>" />

The request below contains a POST parameter servicestatusfilter, which contains the value of ""/><script>alert(1);</script><"".

image073 Figure 7: A malicious JavaScript included into the servicestatusfilter POST parameter

The response contains the exact same value as shown on the picture below.

image074 Figure 8: A malicious JavaScript included into the rssfeed POST parameter

Note that the JavaScript doesn't execute in the web browser, because a Location header is also given, so a redirection is made before JavaScript has a chance to execute. Nevertheless this is a vulnerability that needs to be fixed.

An attacker can cause arbitrary JavaScript to be executed in the user's web browser.

XSS in Referer HTTP Header in log.widget.php

A vulnerability exists in widgets/widgets/log.widget.php in the following code. The Referer HTTP header is read into the $filename variable, which is later included into the response without properly encoding the special characters.

$filename = $_SERVER['HTTP_REFERER'];
if(headers_sent($file, $line)){
echo '<script type="text/javascript">';
echo '//<![CDATA[';
echo 'window.location.href="'.$filename.'";';
echo '//]]>';
echo '</script>';
echo '<noscript>';
echo '<meta http-equiv="refresh" content="0;url='.$filename.'" />';
echo '</noscript>';
}

If we send a "<script>" string in a Referer HTTP header, we'll receive the following response, which states that a problem was identified, because the string specified in the Referer HTTP header is not the same as the one specified in the system settings.

image075 Figure 9: A response upon sending "<script>" in referer HTTP header

This happens because Pfsense implements HTTP_REFERER redirection detection, which is blocked by default: this can be controlled in an System – Advanced – Admin settings as defined below.

image076 Figure 10: The pfsense settings regarding referer HTTP header

We need to disable the HTTP_REFERER enforcement check and save the settings. After that we can send the ""/></noscript><script>alert(1);</script><noscript><"" string in the Referer HTTP header as shown in the request below.

image077 Figure 11: A request containing a malicious JavaScipt in Referer HTTP header

The value stored in the Referer HTTP header is presented twice to the user as shown in the response below.

image078 Figure 12: A malicious JavaScript code included into the returned web page

Since we've properly escaped the <noscript> and other HTML elements, the injected JavaScript should execute on the user's browser, which is shown below.

image079 Figure 13: The execution of malicious JavaScript code

Because of the default HTTP_REFERER enforcement check in the Pfsense settings, which is enabled by default, this bug is harder to exploit, but the vulnerability is still present, so it must be mitigated. There is also a number of POST parameters that are being included in the response without proper sanitation, which makes the attack probable. The vulnerable POST parameters are:

  • filterlogentries
  • actpass
  • actblock
  • actreject
  • filterlogentriesinterfaces

An attacker can inject JavaScript in Referer HTTP header, which is executed in the user's web browser.

JavaScript injection in exec.php

The Diagnostics: Execute command functionality allows an attacker to upload a file to the server, which is shown below.

image054 Figure 40: The file upload functionality

In order for the user to be able to access this functionality, he must have the Diagnostics: Command privileges as presented below.

image055 Figure 14: The required privileges

When uploading a file, an attacker has a chance to inject arbitrary JavaScript in the txtRecallBuffer parameter. On the picture below, we can see that we inputted the "bbb'); var arrRecalBuffer = new Array('aaa" string in the txtRecallBuffer parameter.

image056 Figure 15: A malicious input data sent to the server

The above request results in the response presented below, where it's evident that arbitrary JavaScript code injection is possible.

image057 Figure 16: Previously sent input data included directly into the JavaScript code block

Note that we can't exploit the vulnerability, because the whole JavaScript block is enclosed in the comments with <!-- --> characters. Normally, we can break out of the commented section by first injecting the ending > characters, and then including arbitrary code, but we can't do that in the case above, since special characters < and > are properly encoded.

JavaScript can be injected into the web page, which might allow attackers to execute arbitrary JavaScript in user's browser.

Conclusion

If you find this post interesting, you can follow our blog: RSS.

Comments