89 SHARES Facebook Twitter

The Joomla! team released a new version of Joomla! CMS yesterday to patch a serious and easy to exploit remote code execution vulnerability that affected pretty much all versions of the platform up to 3.4.5. As soon as the patch was released, we were able to start our investigation and found that it was already being exploited in the wild – 2 days before the disclosure.

We will now shed some light on vulnerability, specifically how it works.

PHP Session 102

By default, Joomla! stores users session in the site’s database. Here’s an example of what a typical session would look like:

A quick look reveals an interesting behavior about PHP’s way of unserializing sessions (which can be reproduced using PHP function session_decode). PHP’s session serialization function is a bit different than the usual serialize() we’re used to, especially when it comes to array indexes. Here’s a comparison of the two for a given array, array( ‘a’ => ‘a’, ‘b’ => ‘b’):

A standard serialize() call would give us a:2:{s:1:”a”;s:1:”a”;s:1:”b”;s:1:”b”;}

call would give us Whereas session_encode() is returning a|s:1:”a”;b|s:1:”b”;

As you can see, the second encoding still uses regular variable serialization but differ in the way it’s declaring indexes for the $_SESSION array. In this case, this is one of the thing that will allow attackers to store arbitrary session data inside the database.

When User Input Meets Session Data

Some of you might have noticed already, but the above session was created by me using Firefox. But wait, how does Joomla! know this?

When it creates a new session, Joomla! takes the client’s user-agent and stores it in the session’s session.client.browser index, which will be saved later on the database. Meaning, one could in theory close the current serialized object/array they are into and start a new one, using a payload similar to “}__test|a:100:{some serialized data}. The problem with this approach, as some will have noticed, is that we leave an extra pipe ( | ) character, which breaks the resulting serialized payload. To get anything malicious in the session, an attacker needs to get rid of all the data located after the injected payload.

Tainted Session Data Meets MySQL

Checking the session table’s collation gives us the last piece of the puzzle:

WordPress had a very similar issue recently, involving the lack of support of MySQL’s utf8_general_ci collation for 4 byte UTF-8 characters. MySQL’s default behavior when it meets an UTF-8 character that isn’t supported by utf8_general_ci is that it will just truncate all the data, starting from that specific character, exactly what’s needed for the exploit to work. The payload would then become something like: “}__test|a:100:{some serialized data}

What About Achieving Code Execution?

From the moment the attacker can push an arbitrary serialized payload in its session, he’s conducting what is known as an Object Injection attack, which as we have seen in the wild and shown in past disclosures usually allows Remote Code Execution to occur on the victim’s site. We won’t show this part here as there is still a lot of sites not updated, but you get the point.

Update As Soon As Possible

Attackers are already exploiting this vulnerability in the wild, so updating your sites should be done in priority. In the event where this wouldn’t be possible, we strongly encourage you to consider adding other security measures to prevent it from being hacked, such as a Website Application Firewall (WAF).