Escaping from Mozilla Firefox in Restricted Environments

Escaping from Mozilla Firefox in Restricted Environments

How to execute operating system commands by leveraging legitimate functions of Mozilla Firefox.

By Bastian Kanbach

Lead Consultant

20 Nov 2018

Software environments in which users should only be able to perform a limited amount of tasks often use Kiosk applications to reduce the opportunities of a user to interact with the system. In many environments, only a few pre-defined applications are published to the user, like web browsers or POS software, depending on what the user needs to do.

An attacker who targets such a restricted environment usually tries to find a way to bypass the boundaries of the published application, in order to execute commands on the underlying operating system. The overall goal of the attacker is usually to establish a foothold on the system and potentially compromise further systems that are connected to it. Consequences can vary between operational and financial damage, including the loss of sensitive data, depending on what the purpose of the attacked system is.

In Windows there are many well-known ways for an attacker to create an interactive shell, such as Sticky Keys, “File open” dialogues, Typing commands in address bars, help menus etc. In Linux environments this is more complicated and it is not sufficient to just type a command in the address bar of a browser.

The following write-up describes a technique than can be used to execute code on the underlying operating system by including a custom module for smartcard-based authentication (PKCS11) into Mozilla Firefox. The write-up focuses on Linux environments but the same can be achieved when the underlying operating system is Microsoft Windows.


When performing security assessments the first step is reconnaissance to discover as much about the target system as possible. If Firefox is the only available application, reconnaissance is more difficult, but not impossible. “File open” dialogues can be helpful to determine how the file system is structured. In some cases File open/File save dialogues can be locked down so that neither directories nor files are visible. However, Firefox allows any user to traverse the file system by using the “file:” protocol handler. The screenshot below shows the root directory of the underlying operating system after calling file:///

Examples for directories of interest are the /etc directory which could contain valuable information about the system’s configuration or the /tmp directory which is world-writable and could aid an attacker in dropping files on the system. Not only directories can be browsed, but also files like /etc/os-release that are readable by the current user:

Gathering some information about the operating system is important for all further steps. Further reconnaissance via the “Help” menu and the “About Firefox” view revealed that Firefox runs as a 32-bit process. This information is helpful, since the target architecture of the module has to match with the architecture of the process. 

Breakout using a custom PKCS11 module

Options for spawning an interactive shell are limited, however the “Security Devices” feature in Mozilla Firefox allows to load *.so or *.dll files that are stored locally. This feature is mainly used to set up smartcard-based authentication, for example when a webserver requires a client certificate. The implementation is based on the PKCS11 standard that also defines an API to communicate with smartcards. 

Now that we have identified the architecture and a location to download files to, we have three steps to create a functional PKCS11 library that spawns a shell and is compatible with Mozilla Firefox: 

  1. Find a suitable PKCS11 library
  2. Instrument and compile the PKCS11 library
  3. Adjust dynamic dependencies of the resulting library

Find a suitable PKCS11 library

A basis for such a module is the open-source middleware “OpenSC”, which is found on Github: 

A library capable to communicate with the PKCS11 API needs to have the following functions implemented: 


Implementing such a module from scratch would be very time consuming, however the existing OpenSC codebase can be leveraged to do the necessary customisations.

Instrument and compile the PKCS11 library

In order to understand the code flow, it is important to find some kind of “entry point” first. Of special interest is the file src/pkcs11/pkcs11-global.c: 

CK_RV C_Initialize(CK_VOID_PTR pInitArgs)
	CK_RV rv;
#if !defined(_WIN32)
	pid_t current_pid = getpid();
	int rc;
	unsigned int i;
	sc_context_param_t ctx_opts;

The snippet above shows the function C_Initialize that is automatically called once the PKCS11 module is loaded by the browser. This is a good start for some extra lines of code: 

CK_RV C_Initialize(CK_VOID_PTR pInitArgs)
    int res = system("/usr/bin/xterm");
    printf("%d", res);
	CK_RV rv;
#if !defined(_WIN32)
	pid_t current_pid = getpid();
	int rc;
	unsigned int i;
	sc_context_param_t ctx_opts;

A call of the system() command was inserted that invokes an external application, in this case /usr/bin/xterm, to spawn an interactive terminal. Please note that the call of “system()” in the code blocks the main thread of the Firefox process and keeps it unresponsive until xterm is closed. However for this Proof-of-concept it is adequate.

For a simple Proof-of-concept this modification is sufficient. The OpenSC project now needs to be compiled for a 32-bit architecture, because the targeted Firefox instance was launched as a 32-bit process. After compiling the project, the resulting shared library that Firefox could open was created with the name "" and can be found in src/pkcs11/.libs/. After hosting the file on an accessible web server, it needs to be downloaded to the target system, for example by using the browser’s “Save link as” function. Loading this file into Firefox usually initially fails, indicated by the error message "module load failed". This relates to a missing library that depends on, which means the dynamic dependencies need to be adjusted.

Adjust dynamic dependencies of the resulting library

To find out which libraries are missing, the “ldd” command can be used: 

root@debian:~/OpenSC/src/pkcs11/.libs# ldd (0xb774b000) => /root/OpenSC/src/libopensc/.libs/ (0xb75a4000) => /lib/i386-linux-gnu/ (0xb758c000) => /lib/i386-linux-gnu/ (0xb756d000) => /lib/i386-linux-gnu/ (0xb73b6000)
	/lib/ (0xb774d000)

As shown above, the compiled module depends on a library called “”, stored at /root/OpenSC/src/libopensc/.libs/ So far only was downloaded to the target system and cannot be found by the library, resulting in an error.

The tool “patchelf” can be used to adjust the location, from which is loaded. To change the search path from /root/OpenSC/src/libopensc/.libs/ to /tmp/ the following command can be used: 

patchelf --set-rpath /tmp

The command above changes the “rpath” to /tmp. To check if the modification was successful, the ldd command can be invoked again: 

root@debian:~/OpenSC/src/pkcs11/.libs# ldd (0xb774b000) => /tmp/ (0xb75a4000) => /lib/i386-linux-gnu/ (0xb758c000) => /lib/i386-linux-gnu/ (0xb756d000) => /lib/i386-linux-gnu/ (0xb73b6000)
	/lib/ (0xb774d000)

After modifying the shared object, all payloads are prepared. To spawn a shell, the following actions need to be performed: 

  1. Download the modified version of to /tmp/
  2. Download the modified version of to an arbitrary location
  3. Add as a security device in Firefox

After specifying the path to the shared object, the PKCS11 module gets loaded by Firefox and the code is executed:

The screenshot above shows that xterm was successfully spawned. 


The technique described can be used in situations when code needs to be executed and Firefox is published as a single Kiosk application.
Although this method requires some effort in advance to create a shared object that executes custom code, it is cross-platform and very easy to invoke once the library is downloaded to the target system.


If you have a question for us or require any further information, please get in touch.

Contact Us

About Bastian Kanbach

Lead Consultant

Bastian works in our Assurance Team in Essen. See the contact page for how to get in touch.

CHECK IT Health Check Service
Cyber Essentials
CESG Certified Service
First - Improving Security Together
BSI ISO 9001 FS 581360
BSI ISO 27001 IS 553326
PCI - Approved Scanning Vendor