PfSense Vulnerabilities Part 4: Directory Traversal

Introduction

In this article we'll present the CVE-2014-4690 vulnerability existing in pfSense version <= 2.1.3. In later versions of pfSense, the vulnerabilities have been successfully remediated and are no longer present. You should also read the previous articles about PfSense vulnerabilities at the following locations:

LFI vulnerability in traversal in pkg_mgr_install.php

Let's take a look a the code contained in /usr/local/www/pkg_mgr_install.php file. It's has been copied below for completeness and clarity.

  if ($_GET) {
  $pkgname = str_replace(array("<", ">", ";", "&", "'", '"'), "",
  htmlspecialchars_decode($_GET['pkg'], ENT_QUOTES |
NT_HTML401));
  switch($_GET['mode']) {
  case 'showlog':
  if (strpos($pkgname, ".")) {
  update_output_window(gettext("Something is wrong on the
equest."));
  } else if (file_exists("/tmp/pkg_mgr_{$pkgname}.log"))

pdate_output_window(@file_get_contents("/tmp/pkg_mgr_{$pkgname}.log"));
  else
  update_output_window(gettext("Log was not retrievable."));
  break;
  case 'installedinfo':
  if (file_exists("/tmp/{$pkgname}.info")) {
  $status = @file_get_contents("/tmp/{$pkgname}.info");
  update_status("{$pkgname} " . gettext("installation completed."));
  update_output_window($status);
  } else
  update_output_window(sprintf(gettext("Could not find %s."),
pkgname));
  break;
  default:
  break;
  }
  }

Notice that the code accepts two GET parameters mode, which is passed to the switch statement and supports values showlog or installedinfo. The second parameter is pkg, which is read into the pkgname variable by deleting the following characters from the inputted string: <, >, ;, &, ', ". Since the replace statement doesn't check for special characters . and /, we can traverse the directories on the server. In the code we can also see that the value of pkg parameter is unsafely concatenated with "/tmp/{$pkgname}.info". Therefore if we pass the value of ../usr/local/info/gettext in pkg parameter, the whole path to read will be: /tmp/../usr/local/info/gettex.info, which is an existing file on the disk. Take a look at such request below.

image030 Figure 1: A request showing directory traversal in GET parameter pkg

Notice that the file beginning with "This is a gettext.info" is included in the output of a web page as seen below.

image031 Figure 2: A response presenting the requested file

# head /usr/local/info/gettext.info
This is gettext.info, produced by makeinfo version 4.13 from gettext.texi.
To verify that this is the same file, we can connect to the Pfsense ia SSH and issue the head command to display the first part of the ile; the output below verifies the file is the same.
INFO-DIR-SECTION GNU Gettext Utilities
START-INFO-DIR-ENTRY
gettext: (gettext). GNU gettext utilities.
autopoint: (gettext)autopoint Invocation. Copy gettext nfrastructure.
envsubst: (gettext)envsubst Invocation. Expand environment variables.
gettextize: (gettext)gettextize Invocation. Prepare a package for ettext.
msgattrib: (gettext)msgattrib Invocation. Select part of a PO file.
<script type="text/javascript" src="javascript/domTT/domLib.js"></script>
<script type="text/javascript" src="javascript/domTT/domTT.js"></script>
<script type="text/javascript" src="javascript/domTT/behaviour.js"></script>
<script type="text/javascript" src="javascript/domTT/fadomatic.js"></script>
<script type="text/javascript" src="/javascript/row_helper_dynamic.js"></script>

Let's also display that in a web browser to present it in a clear way.

image032 Figure 3: The file displayed in a web browser

Since the string concatenation appends the .info at the end of the string, we can only display files ending with .info extension. We can quickly search for all those files by issuing a find command as presented below.

# find / -name "*.info"
/usr/local/info/gettext.info
/usr/local/info/autosprintf.info
/usr/pbi/snort-amd64/info/autosprintf.info
/usr/pbi/snort-amd64/info/gettext.info
/usr/pbi/snort-amd64/info/m4.info
/usr/pbi/snort-amd64/info/autoconf.info
/usr/pbi/open-vm-tools-nox11-amd64/info/autosprintf.info
/usr/pbi/open-vm-tools-nox11-amd64/info/gettext.info
/usr/pbi/open-vm-tools-nox11-amd64/info/m4.info
/usr/pbi/open-vm-tools-nox11-amd64/info/autoconf.info
/usr/pbi/havp-amd64/info/autosprintf.info
/usr/pbi/havp-amd64/info/gettext.info

Note that the script does not accept NULL byte %00, which would allow us to download arbitrary file from the server.

An attacker can use this vulnerability to get the contents of arbitrary .info files from Pfsense. To fix the vulnerability the /usr/local/www/pkg_mgr_install.php script needs to implement proper security measures to prevent directory traversal attacks on the server.

LFI vulnerability in system_firmware_restorefullbackup.php

A LFI vulnerability exists in the system_firmware_restorefullbackup.php script. If a user has only the "Diagnostics: Restore Full Backup" privileges, as shown below, he won't be able to access the LFI vulnerability.

image044 Figure 4: The 'restore full backup' privileges

Instead it must have "Allow access to all pages" privileges, which is a lot of privileges to begin with.

image045 Figure 5: The 'access to all pages' privileges

Nevertheless, the web application is vulnerable to LFI injection, where we can pass arbitrary value in the downloadbackup GET parameter as shown on the picture below.

image046 Figure 6: A request requesting the /etc/passwd file

The response to the picture can be shown below, where it's evident that the /etc/passwd has returned to the user.

image047 Figure 7: The contents of /etc/passwd file

An attacker with previously described privileges could use this vulnerability to gain access to the whole Pfsense.

An attacker can use this vulnerability to download arbitrary file from the system. The fix the vulnerability the value passed in GET parameter downloadbackup needs to be properly secure to not allow reading arbitrary files from the server.

Conclusion

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

Comments