漏洞位于:/zbzcms/cms/cms/include/function.php
function getImage($url,$save_dir='',$filename='',$type=0){
if(trim($url)==''){
return array('file_name'=>'','save_path'=>'','error'=>1);
}
if(trim($save_dir)==''){
$save_dir='./';
}
if(trim($filename)==''){//保存文件名
$ext=strrchr($url,'.');
if(!stristr($ext,'.gif') && !stristr($ext,'.jpg') && !stristr($ext,'.png')){
return array('file_name'=>'','save_path'=>'','error'=>3);
}
$filename=strrchr($url,'/');
$filename=str_ireplace('/','',$filename);
}
if(0!==strrpos($save_dir,'/')){
$save_dir.='/';
}
//创建保存目录
if(!file_exists($save_dir)&&!mkdir($save_dir,0777,true)){
return array('file_name'=>'','save_path'=>'','error'=>5);
}
//获取远程文件所采用的方法
if($type){
$ch=curl_init();
$timeout=5;
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,$timeout);
$img=curl_exec($ch);
curl_close($ch);
}else{
ob_start();
readfile($url);
$img=ob_get_contents();
ob_end_clean();
}
//$size=strlen($img);
//文件大小
$fp2=@fopen($save_dir.$filename,'a');
fwrite($fp2,$img);
fclose($fp2);
unset($img,$url);
return $save_dir.$filename;
可以发现当$url
可控,$type=0
的时候,会执行readfile($url)
,且并没有对$url
进行过滤处理,最后将其保存到$save_dir
所在的位置。追踪所有引入了getImage
函数的php文件,最终发现了如下代码:
//编辑栏目
if($run=='edit_type'){
//下载远程图片到本地S
preg_match_all('/0){
foreach($tupians[1] as $v){
if(strstr($v,'http://') || strstr($v,'https://')){
$tupian_src=getImage($v,"../../upload");
$_POST['lanmuneirong']=str_ireplace($v,$tupian_src,$_POST['lanmuneirong']);
}
}
}
//下载远程图片到本地E
$where="id=".$_POST['id'];
unset($_POST['id']);
echo $c_sql->update('type',$_POST,$where);
我们可以通过post传入一个lanmuneirong的值并通过正则匹配执行getImage()
函数,最终造成SSRF:
这里也可以利用不同浏览器的解析机制不同,造成存储型XSS
漏洞位于:/zbzcms/cms/cms/admin/run_ajax.php
//文件
if($run=='wenjian'){
$path=$_POST['path'];
echo get($path);
}
然后定位get函数,动态变量可控且无任何过滤:
//读取文件方便编码处理
function get($path){
if(!file_exists($path)){
return '文件'.$path.'不存在!';
}
$get=file_get_contents($path);
return $get;
}
后台注入点太多了,这里就列举几例:
公共函数:
public function digui($table,$ziduan,$tid=0,&$result=array(),$spac=0){
$spac=$spac+1;
$sql="select * from $table where $ziduan='$tid' order by paixu,id asc";
$res=mysqli_query($this->link(),$sql);
while($row=mysqli_fetch_assoc($res)){
$row['jibie']=$spac;
$result[]=$row;
$row['jibie']=$spac;
$this->digui($table,$ziduan,$row['id'],$result,$spac);
}
return $result;
后台注入点一:/zbzcms/cms/cms/admin/art_list.php
if(isset($_GET['tid'])){
$tid=$_GET['tid'];
$tid_zis=$c_sql->select("select id from type where tid={$tid}");
后台注入点二:/zbzcms/cms/api/caiji.php
//审核并自动更新
else if($run=='shenhe'){
$tid=$_GET['lanmu'];
$up_arr=array('fabushijian',time());
$ids=$c_sql->select("select id from art where (fabushijian=1 and tid={$tid}) limit 1");
if(isset($ids[0]['id'])){$id=$ids[0]['id'];}
else{exit('待审核文章库没有文章了!');}
$up_arr=array('fabushijian'=>time());
$up=$c_sql->update('art',$up_arr,"id={$id}");
$up=1;
if($up!=1){
exit('审核系统出错');
}
}
else{
exit("run参数有误");
后台注入点三:/zbzcms/cms/cms/admin/run_ajax.php
//新增栏目提交
if($run=='type_add'){
$_POST['fulanmumingcheng']=pinyin($_POST['lanmumingcheng'],$lx='head');
$_POST['youhuabiaoti']=$_POST['lanmumingcheng'];
$_POST['youhuaguanjianci']=$_POST['lanmumingcheng'];
$_POST['youhuazhaiyao']=$_POST['lanmumingcheng'];
$_POST['paixu']=50;
$jibie=$_POST['jibie'];
unset($_POST['jibie']);
$typeid=$c_sql->insert('type',$_POST);
if($_POST['tid']==0){
$red['id']=$typeid;
$red['tid']=$_POST['tid'];
$red['jibie']=$jibie+1;
$red['weizhi_id']=0;
}
else{
$diguis=$c_sql->digui('type','tid',$_POST['tid'],$result); //$tid可控
后台注入点四:此处会进行delete操作
//删除联动
if($run=='delliandong'){
$id=$_POST['id'];
$liandongids=$c_sql->digui('liandong','lid',$id,$result,$spac=0);
$ids[]=$id;
if(count($liandongids)>0){
foreach($liandongids as $arr){
$ids[]=$arr['id'];
}
}
$id=implode(',',$ids);
$sql="delete from liandong where id in ({$id})";
$res=$c_sql->zhixing($sql);
if($res==1){
echo json_encode($ids);
}
else{
exit(0);
}
}
后台注入点五:
//增或改
if($run=='addedit'){
$table=$_GET['table'];
$where="id=".$_POST['id'];
$cha=$c_sql->select("select id from $table where $where");
if(isset($cha[0]['id'])){
$res=$c_sql->update($table,$_POST,$where);
}
else{
$res=$c_sql->insert($table,$_POST);
}
echo $res;
触发点一:/zbzcms/cms/cms/include/function.php
/*删除目录及目录下所有文件或删除指定文件($path待删除目录路径,$delDir1或true删除目录,0或false则只删除文件保留目录*/
function delDirAndFile($path, $delDir = FALSE) {
if($path=='' || $path=='/' || $path=='./' || $path=='../' || $path=='../../' || $path=='../../../'){
exit('严禁该操作');
}
$handle = opendir($path);
if ($handle) {
while (false !== ( $item = readdir($handle) )){
if ($item != "." && $item != "..")
is_dir("$path/$item") ? delDirAndFile("$path/$item", $delDir) : unlink("$path/$item");
}
closedir($handle);
if ($delDir)
return rmdir($path);
}else {
if (file_exists($path)) {
return unlink($path);
} else {
return false;
}
}
}
//删除文件
if($run=='delpath'){
$path=$_POST['path'];
delDirAndFile($path, $delDir = true);
当$delDir
为真时,会删除整个目录内容
触发点二:/zbzcms/cms/cms/include/up.php
//删除文件
if($run=='del'){
$url=$_POST['url'];
if(!unlink($url)){
echo 0;
}
else{
echo 1;
}
}
触发点三:/zbzcms/cms/cms/include/upload.php
//删除
else if(isset($_GET['del'])){
$src=$_GET['del'];
if(!unlink($src)){
echo 0;
}
else{
echo 1;
}
exit;
}
//图片上传
if($run=='youad_pic'){
$path='../../upload/';
$path_res='../../upload/';
$res='';
foreach($_FILES as $i=> $arr){
$tmp_name=$arr['tmp_name'];//临时文件
if($data_pic_name==0){
//后缀
$houzhuis=explode('.',$arr['name']);
$houzhui=$houzhuis[count($houzhuis)-1];
$pathurl=$path.time().'_'.$i.'.'.$houzhui;
}
else{
$pathurl=$path.$arr['name'];
}
is_dir($path) OR mkdir($path, 0777, true);//文件夹不存在创建文件夹
$pathurl=iconv("UTF-8","gb2312",$pathurl);//目标路径
if(move_uploaded_file($tmp_name,$pathurl)){
$pathurl_res=str_ireplace($path,$path_res,$pathurl);
$res.=$pathurl_res;
}
}
print_r($_FILES);
echo $res;
//图片命名,0改名,1原名
if(isset($_GET['data_pic_name'])){$data_pic_name=$_GET['data_pic_name'];}
else{$data_pic_name='0';}
- 上传点二:
zbzcms/cms/cms/include/upload.php
if(isset($_FILES) && isset($_GET['path']) && isset($_GET['name']) && isset($_GET['id'])){
$path = $_GET['path'];//文件上传根目录
$name = $_GET['name'];//文件命名规则
$id = $_GET['id'];//上传插件的id
if (!file_exists($path)) {mkdir($path, 0777, true);}//上传目录不存在则创建
$res='';//返回的参数
$i=1;//递增的文件名
foreach($_FILES as $arr){
//文件名S
if($name==1){$file_name=$arr['name'];}
else{
if($arr['type']=='image/png'){$file_name=time().$i.'.png';}
if($arr['type']=='image/jpeg'){$file_name=time().$i.'.jpg';}
if($arr['type']=='image/gif'){$file_name=time().$i.'.gif';}
}
//文件名E
$tmp_name=$arr['tmp_name'];//临时文件
$url=$path.$file_name;//新文件路径
if(move_uploaded_file($tmp_name,$url)){
$res.="";
}
$i++;
}
print_r($_FILES);
echo $res;
可通过动态变量$path
将文件上传至任意处,当$name=1
时即可上传任意文件:
- 上传点三:
zbzcms/cms/cms/include/up.php
//上传
if($run=='file'){
$res=array();
$path=$_GET['path'];//上传的路径
$filename=$_GET['filename'];//1不更改,0更改
is_dir($path) OR mkdir($path, 0777, true);//文件夹不存在创建文件夹
foreach($_FILES as $k=>$arr){
$path=$_GET['path'];//上传的路径
$name=$arr['name'];//文件名
$type=$arr['type'];//文件类型
$tmp_name=$arr['tmp_name'];//临时文件
$size=$arr['size'];//文件大小
/*目标地址*/
if($filename==1){
$path.=$name;
}
else{
$path.=time().$k.hz($name);
}
/*上传*/
if(move_uploaded_file($tmp_name,$path)){
$res[]=$path;
}
}
echo json_encode($res);
}
- 上传点四:
/zbzcms/cms/cms/zbzedit/php/zbz.php
$arr){
$tmp_name=$arr['tmp_name'];//临时文件
if($data_pic_name==0){
//后缀
$houzhuis=explode('.',$arr['name']);
$houzhui=$houzhuis[count($houzhuis)-1];
$pathurl=$path.time().'_'.$i.'.'.$houzhui;
}
else{
$pathurl=$path.$arr['name'];
}
is_dir($path) OR mkdir($path, 0777, true);//文件夹不存在创建文件夹
$pathurl=iconv("UTF-8","gb2312",$pathurl);//目标路径
if(move_uploaded_file($tmp_name,$pathurl)){
$res[]=str_ireplace($path,$path_res,$pathurl);
}
}
echo json_encode($res);//返回json
}
?>
漏洞位于:/zbzcms/cms/cms/admin/run_ajax.php
//批量上传txt文章
if($run=='uptxt'){
$id=$_GET['id'];
$chatu=$_GET['chatu'];
$fabushijian=$_GET['fabushijian'];
foreach($_FILES as $k=>$arr){
$tmp_name=$arr['tmp_name'];//临时文件
$path='uptxt';
is_dir($path) OR mkdir($path, 0777, true);//文件夹不存在创建文件夹
$pathurl=$path.'/'.$arr['name'];
$pathurl=utf8($pathurl);
if($arr['error']==0){
if(!move_uploaded_file($tmp_name,iconv("UTF-8","gb2312",$pathurl))){
move_uploaded_file($tmp_name,$pathurl);
}
$gml='http://'.$_SERVER['SERVER_NAME'].$_SERVER["REQUEST_URI"];//当前文件夹
$gml=dirname($gml);
$neirong=file_get_contents($gml.'/'.$pathurl);
$neirong=utf8($neirong);
$neirong=''.str_ireplace("\r\n","
",$neirong).'
';
if($chatu==1){
$tuku=ii('tuku');//图库
$tukus=explode(";",$tuku);
$tupians=array();
$suoluetu='';
$tupianshu=rand(1,3);
for ($x=1; $x<=$tupianshu; $x++) {
$k=rand(0,count($tukus)-1);
if($x==1){
$suoluetu=$tukus[$k];
}
$tupians[]="\r\n";
unset($tukus[$k]);
$tukus = array_values($tukus);
}
$neirongs=explode('',$neirong);
if(count($tupians)>0){
foreach($tupians as $k=>$v){
$neirongs[$k]=$neirongs[$k].$v;
}
}
$neirong=implode('',$neirongs);
}
$art['tid']=$id;
$art['biaoti']=str_ireplace('.txt','',$arr['name']);
$art['neirong']=$neirong;
$art['zhaiyao']=jiequ($neirong,100);//截取摘要
$art['suoluetu']=$suoluetu;
$art['paixu']=50;
$art['fabudao']=0;
$art['zuozhe']=$_SESSION['guanliyuan'];
if($fabushijian==0){
$art['fabushijian']=1;
}
else{
$art['fabushijian']=time();
}
$c_sql->insert('art',$art);
}
}
delDirAndFile($path,1);
}
这里也是一处任意文件上传,但是执行到最后的时候又将其进行了删除,从文件监控日志中也可以看出来:
由于上传的路径以及文件名都是确定的,所以可以利用条件竞争的方式进行利用:
漏洞位于:/zbzcms/cms/cms/admin/run_ajax.php
//文件编辑保存
if($run=='wenjian_edit'){
$path=$_POST['path'];
$neirong=$_POST['neirong'];
//如果get_magic_quotes_gpc()是打开的
if(get_magic_quotes_gpc()){
$neirong=stripslashes($neirong);//将字符串进行处理
}
echo file_put_contents($path,$neirong);
}
漏洞位于:/zbzcms/cms/cms/admin/run_ajax.php
//文件安全检测
if($run=='anquan_run'){
$cms_oldname=$_POST['cms_oldname'];
$admin_oldname=$_POST['admin_oldname'];
$cms=$_POST['cms'];
$admin=$_POST['admin'];
$admin_url=ii('电脑站网址');
if(stristr($admin_url,'http://') || stristr($admin_url,'https://')){$admin_url.=cms.'/';}
else{$admin_url='http://'.$_SERVER['HTTP_HOST'].ii('电脑站网址').cms.'/';}
if($_GET['i']==1){
rename("../{$admin_oldname}","../{$admin}");
echo 2;
}
else if($_GET['i']==2){
if(rename("../../{$cms_oldname}","../../{$cms}")){
echo $admin_url.$cms.'/'.$admin;//返回新后台地址
}
}
}