Critical Joomla File Upload Vulnerability

Critical Joomla File Upload VulnerabilityI was reading the Joomla Update, http://developer.joomla.org/security/news/563-20130801-core-unauthorised-uploads

A bug in Joomla Core and having the criticality is always awesome to see 🙂

I decided to give the bug a look to see what the actual problem was. I looked at the diffs (changes made) to the latest version 2.5.14
https://github.com/joomla/joomla-cms/commit/fa5645208eefd70f521cd2e4d53d5378622133d8

From the commits, there are multiple changes. To summarize, I wrote a small script which uses all the affected functionality.

This is Pseudo Code.

[php]

//the "allowable" variable, as can be seen, is the white list of extensions that are allowed by default to be uploaded on Joomla.
$allowable = array (
‘bmp’,
‘csv’,
‘doc’,
‘epg’,
‘gif’,
‘ico’,
‘jpg’,
‘odg’,
‘odp’,
‘ods’,
‘odt’,
‘pdf’,
‘png’,
‘ppt’,
‘swf’,
‘txt’,
‘wmv’,
‘xcf’,
‘xls’
);

//by default no values are set for the "ignored" variable.
$ignored = array (”);

//function to get the file extension and then compare it with $allowable and $ignored.
function getExt($file) {
$dot = strrpos($file, ‘.’) + 1;
return substr($file, $dot);
}

//this particular regular expressions strips possibly malicious input and keeps the filename clean.
$regex = array(‘#(\.){2,}#’, ‘#[^A-Za-z0-9\.\_\- ]#’, ‘#^\.#’);

//the "file" variable is the name of the file you are uploading.
$file = "PUTFILENAMEHERE";
preg_replace($regex, ”, $file);

//"format" picks up the extension of the file.
$format = getExt($file);

//If extension is not in "allowable" and is not in "ignored", upload file
if (!in_array($format, $allowable) && !in_array($format, $ignored))
{ echo "You are not allowed to upload this extension\n"; die();}

echo "Filter Bypassed!\n";
[/php]

So, if we try to upload our file webshell.php on the server it will, as should, fail. Extension PHP is not in the variable $allowed.

The bug here was, if you upload a file name webshell.php. (with an extra dot at the ending) The extension retrieved through getExt function is empty.

Let’s look at the expression in concern, if (!in_array($format, $allowable) && !in_array($format, $ignored))

First half of the expression !in_array($format, $allowable) => TRUE
Since an empty extension doesn’t exist in the allowable array. Output is False but since there is a ! it will inverse the output and it becomes TRUE.

Second half of the expression !in_array($format, $ignored) => FALSE
Since by default there are no extensions defined, the “ignored” array is empty. And we are passing an empty extension so it is TRUE and in-versing that makes it FALSE.

From our truth tables we know, TRUE AND FALSE = FALSE. So, the “if” statement will be skipped and we successfully bypass the filter simply by appending a dot to the file name that is to be uploaded.

Fix:
The fixes that are implemented are quite simple, Joomla is now removing any trailing dots and apart from that it exists if there is no file extension found.

Exploitability:
A user who has access to the upload functionality, can upload files with any extension. The server will sanitize the uploaded file webshell.php. to webshell.php and store it on the web server which can lead to RCE and a complete compromise of the system.

Author


Related Tags:

3 comments

Hi,

“….The server will sanitize the uploaded file webshell.php. to webshell.php and store it on the web server….”

in my test case the server does not sanitize the file – it stayed named “webshell.php.” Any ideas?

You can simply execute the webshell.php. (with the trailing dot) Apache ignores the dot and executes the PHP just fine.

Omair

Leave a Reply

Your email address will not be published. Required fields are marked *

For security, use of Google's reCAPTCHA service is required which is subject to the Google Privacy Policy and Terms of Use.

I agree to these terms.