Fortinet SIEM vulnerability allows us to get RCE on internet exposed hosts

If you want to see a full demo of this exploit, click here.

Introduction

Soon after the Blackhat USA training we gave last summer during the first week of August, our attention was caught by the release of a Fortinet’s security bulletin originally issued on June 21st 2020. It stated that all the versions of their platform FortiSIEM equal to 5.2.8 and below were vulnerable to CVE-2015-0279, an Expression Language injection bug leading to unauthorized code execution. The affected component, found and reported by Code White guys, was an old acquaintance of ours: the infamous java library Richfaces.

Wait a second! There is a working proof of concept publicly available on the internet named Richsploit for the exploitation of that vulnerability! And hey! We wrote it! πŸ˜€

At that point we were just curious to see if our Richsploit tool worked as-is against the target. We procured the version 5.2.8 of the FortiSIEM VM, the last declared to be vulnerable in the Fortinet security bulletin, and installed it in our environment.

The initial analysis revealed that the vulnerable web application was hosted on Glassfish and served through an Apache web server instance configured in reverse proxy, with all the relevant traffic forwarded back and forth to/from the backend application server listening to tcp port 8080.

The vulnerable endpoint was reachable under the β€œ/phoenix” path of the web interface.

That interface was using Richfaces version 4.3.7, as a simple β€œfind” on the FortiSIEM filesystem revealed:

In this article we are not going to re-explain again the exploitation steps for CVE-2015-0279 and precisely how the EL injection on the β€œMediaOutputResource” component works, as it was done several times in our past posts (for example here and here).

Instead let’s jump straight in to the nitty-gritty of the story. Our first attempt to leverage the vulnerability was performed just by running the compiled version of Richsploit as provided in the redtimmy’s github repository:

$ java -jar Richsploit.jar -e 1 -p "touch /tmp/TEST" -u https//victim_ip/phoenix -v 4

All we were trying to do was to create an empty file named β€œTEST” into the β€œ/tmp” directory of the remote system by abusing CVE-2015-0279. However, in response we got the following error:

The stacktrace inside the Glassfish log files was instead more precise and verbose:

This was only one of a long sequence of stacktraces we dealt with. From that moment on indeed we began to establish a real fight with the FortiSIEM device. We had to overcome several obstacles before getting our re-adapted Richsploit payload working: fix libraries incompatibility, settle mismatching EL implementations and API packages, bypass the LookAhead protection mechanism, etc…

At Red Timmy we have created a series of videos showing step by step how all these issues have been solved and the exploit payload adjusted accordingly, in case you are interested (more to be mentioned below, at the end of the article).

For example, one of the latest problems we faced before achieving RCE was the following. At some point, after sending our malicious payload, the β€œrestoreState()” method inside the β€œMediaOutputResource” class is invoked, but an exception is thrown at line 92.

Here the β€œrestoreAttachedState()” method of the β€œUIComponentBase” object is called passing as parameters a β€œcontext” and the fourth element of an array object called β€œstate”. The latter is an attacker-controlled element filled up with a malicious EL statement of type β€œMethodExpression”.

However, when β€œrestoreAttachedState()” is invoked (snippet of code above), it checks if β€œstate” (referred as β€œstateObj” in the current context) is an instance of β€œList” or β€œStateHolderSaver”. Of course it is not, and an illegal state exception with error string β€œUnknown object type” is thrown. We specifically solved this issue by crafting a fake β€œStateHolderSaver” class with which we wrapped our β€œMethodExpression” object which in turn contained the malicious EL statement.

The bottom line was that at some point in time we had in our hands a working exploit. Why not try identifying the presence of potentially vulnerable FortiSIEM devices by dorking on google? Full of curiosity, we launched a couple of search queries and would have expected to discover machines from any domain or company in the consequent output, except instances owned by Fortinet itself, as instead it has happened. Indeed in the results, amongst the other items, we found two internet-exposed Fortinet hosts. On the other hand, they are the guys who have released the security bulletin and the patch for their own products affected by CVE-2015-0279. For sure those machines are running a patched version of FortiSIEM, we thought. Anyway, browsing the URL β€œhttps://victim/phoenix/rfRes/org.richfaces.resource.MediaOutputResource.faces?do=” an HTTP error 500 was returned to us, indicating the resource was there, ready to serve our payload. Bad sign for Fortinet, we thought. Furthermore, as Richfaces is an outdated and not supported project anymore, there is no official patch. The only fix possible is just to remove or make the vulnerable component unreachable, and our case did not fall in any of these categories.

While we were thinking a non-invasive and non-intrusive EL statement to use in order to confirm presence and exploitability of the vulnerability, we came up with this easy, one-liner payload, below:

#{facesContext.externalContext.response.setContenType("SOMETHING")}

If an EL injection vulnerability is present, all it does is to set the Content-Type in the server response equal to β€œSOMETHING”. In our case we decided to make it print out the string representation of one of the constructors of β€œpublic.java.lang.ProcessBuilder”. We sent the request to the target hosts and the result was what is visible in the following screenshot:

This actually confirmed our malicious EL statement was executed in the Fortinet owned machines, without the need to run any command at the operating system level.

On mid of August, few hours after the discovery, we responsibly disclosed the issue to the company with the advice to install the update as indicated in their own security bulletin. The answer arrived quickly 2 days later.

For one of the two Fortinet machines we reported, the upgrade was basically applied immediately and they asked us to double-check from our side. We confirmed indeed the issue was fixed. Three weeks later they wrote again to us about the other host, essentially declaring that machine would have been disconnected from internet and not supported anymore in future.

However until today that host is reachable and seem to be still vulnerable.

FortiSIEM <= 5.2.8 remote exploit

Although Richsploit is already freely available to everybody, we are not going to publicly release an exploit for FortiSIEM CVE-2015-0279. However, if you want to support us, we have recorded some video lessons where you can learn, step-by-step, how to create a working exploit from scratch, adopting a trial and error methodology, as would do an attacker in a real-life scenario. Here is the link: Exploiting Richfaces EL injection on FortiSIEM <= 5.2.8.

Other vulnerable instances on the internet

In the course of our investigation through google dorks we have found other machines that could be remotely compromised. For example a SOC-as-a-service / SIEM-as-a-service provider based in US was exposing three different vulnerable instances of FortiSIEM. Additionally we discovered that a couple of universities, telco companies and a government institution, in different geographical locations, had exposed vulnerable instances of the product too.

We have managed to contact and reach out to most of them. After almost 2 months the majority of these instances are now patched.

Brilliant! That’s all for today. Don’t’ forget to follow us on twitter. And while you are there, why do not subscribe to our online Hacking Java Web and Client Apps course?