Openwall GNU/*/Linux - a small security-enhanced Linux distro for servers
[<prev] [next>] [day] [month] [year] [list]
Date: Wed, 22 Nov 2017 18:40:21 +0100
From: "Securify B.V." <>
Subject: Clickjacking vulnerability in CSRF error page pfSense

Clickjacking vulnerability in CSRF error page pfSense
Yorick Koster, November 2017

pfSense is a free and open source firewall and router. It was found that
the pfSense WebGUI is vulnerable to Clickjacking. By tricking an
authenticated admin into interacting with a specially crafted webpage it
is possible for an attacker to execute arbitrary code in the WebGUI.
Since the WebGUI runs as the root user, this will result in a full
compromise of the pfSense instance.

Tested versions
This issue was successfully tested on pfSense version 2.4.1.

pfSense 2.4.2-RELEASE [2] was released that addresses the Clickjacking

pfSense [3] is a free and open source firewall and router. It was found
that the pfSense WebGUI is vulnerable to Clickjacking. This
vulnerability allows an attacker to execute arbitrary code with root

The pfSense WebGUI uses the csrf-magic [4] library to protect against
Cross-Site Request Forgery (CSRF) attacks. This library contains a user
friendly error page that is implemented in the csrf_callback() function.
This error page is shown whenever the users submits an incorrect (or
missing) CSRF token. The error page contains a 'Try again' button that
allows the user to re-submit the requested action; the invalid token is
replaced with a valid token. The default callback function is listed
below, which is also used by pfSense.

function csrf_callback($tokens) {
	// (yes, $tokens is safe to echo without escaping)
	header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
	$data = '';
	foreach (csrf_flattenpost($_POST) as $key => $value) {
		if ($key == $GLOBALS['csrf']['input-name']) continue;
		$data .= '<input type="hidden" name="'.htmlspecialchars($key).'"
value="'.htmlspecialchars($value).'" />';
	echo "<html><head><title>CSRF check failed</title></head>
		<p>CSRF check failed. Your form session may have expired, or you may
not have
		cookies enabled.</p>
		<form method='post' action=''>$data<input type='submit' value='Try
again' /></form>
		<p>Debug: $tokens</p></body></html>

The use of this error page introduces a risk as in case of a CSRF
attempt, the victim will only be shown this error page. The victim may
be enticed to click the 'Try again' button, thus executing the
attacker's specially crafted action. What is even more interesting is
that the CSRF logic is executed before the WebGUI sets the
X-Frame-Options header, which should mitigate Clickjacking. In case of
an invalid CSRF token, execution of the script will be stopped after the
error page is returned and as a result the X-Frame-Options header will
not be set. Consequently, the CSRF error page is prone to Clickjacking

/* Include authentication routines */
if (!$nocsrf) {
	function csrf_startup() {
		global $config;
		csrf_conf('rewrite-js', '/csrf/csrf-magic.js');
		$timeout_minutes =
isset($config['system']['webgui']['session_timeout']) ?
$config['system']['webgui']['session_timeout'] : 240;
		csrf_conf('expires', $timeout_minutes * 60);
/* make sure nothing is cached */
if (!$omit_nocacheheaders) {
	header("Expires: 0");
	header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
	header("Cache-Control: no-cache, no-store, must-revalidate");
	header("Pragma: no-cache");
header("X-Frame-Options: SAMEORIGIN");

The CSRF error page does include a Javascript framebreaker script that
also mitigates Clickjacking in some cases. In this case it is trivial to
bypass this framebreaker script by opening the target page within a
sandboxed iframe [5] with the allow-forms attribute set. The allow-forms
attribute allows for the form post when a victim clicks the 'Try again'

if ($GLOBALS['csrf']['frame-breaker']) {
	$buffer = str_ireplace('</head>', '<script type="text/javascript">if
(top != self) {top.location.href =
self.location.href;}</script></head>', $buffer);

An attacker can use this issue to perform a Clickjacking attack against
an authenticated admin. This requires that the attacker knows the URL of
the WebGUI and tricks an authenticated admin into visiting a specially
crafted webpage. This webpage will make an arbitrary POST to the WebGUI
containing an invalid token. The POST is done to a sandboxed iframe.
Using UI redressing the attacker can trick the victim into clicking the
'Try again' button, resulting in the POST to be resend to the WebGUI -
this time containing a valid CSRF token. A successful attack will result
in the execution of arbitrary code by the WebGUI. Since the WebGUI runs
as the root user, this will result in a full compromise of the pfSense

Powered by blists - more mailing lists

Your e-mail address:

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.