内容简介:注:只供学习参考,任何用来违法犯罪的与本人无关,违法犯罪快走开,违法犯罪快走开,违法犯罪快走开。漏洞文件:/var/www/html/metinfo6.1.2/app/system/message/web/message.class.php漏洞函数:add 37-51行
0x01 前言
这个本来是不想放出来的,因为metinfo这套cms毕竟使用人数还是挺多的,影响范围也很广。在前两个版本我就提交过此漏洞了鉴于一直不修复。所幸放出来给大家共同学习一下。看到这还请提醒厂商尽快修复了。不过我会在最后留下解决方案。
注:只供学习参考,任何用来违法犯罪的与本人无关,违法犯罪快走开,违法犯罪快走开,违法犯罪快走开。
0x02 漏洞分析
漏洞文件:/var/www/html/metinfo6.1.2/app/system/message/web/message.class.php
漏洞函数:add 37-51行
public function add($info) { global $_M; if(!$_M[form][id]){ $message=DB::get_one("select * from {$_M[table][column]} where module= 7 and lang ='{$_M[form][lang]}'"); $_M[form][id]=$message[id]; } $met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and name= 'met_fd_ok' and columnid = {$_M[form][id]}"); $_M[config][met_fd_ok]= $met_fd_ok[value]; if(!$_M[config][met_fd_ok])okinfo('javascript:history.back();',"{$_M[word][Feedback5]}"); if($_M[config][met_memberlogin_code]){ if(!load::sys_class('pin', 'new')->check_pin($_M['form']['code'])){ okinfo(-1, $_M['word']['membercode']); } }
漏洞触发点:
$met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and name= 'met_fd_ok' and columnid = {$_M[form][id]}");
由于无单引号过滤导致sql注入,这个时候尝试注入发现关键词全被替换了,无法注入。于是查看__controler函数发现调用了父类的初始化函数。
class feedback extends web
跟进web类,没有对用户传入的数据进行过滤等操作,却初始化了common类
class web extends common
查看Common类的初始化函数发现了问题所在
public function __construct() { global $_M;//全局数组$_M ob_start();//开启缓存 $this->load_mysql();//数据库连接 $this->load_form();//表单过滤 $this->load_lang();//加载语言配置 $this->load_config_global();//加载全站配置数据 $this->load_url_site(); $this->load_config_lang();//加载当前语言配置数据 $this->load_url();//加载url数据 }
跟踪 $this→load_form() 函数
protected function load_form() { global $_M; $_M['form'] =array(); isset($_REQUEST['GLOBALS']) && exit('Access Error'); foreach($_COOKIE as $_key => $_value) { $_key{0} != '_' && $_M['form'][$_key] = daddslashes($_value); } foreach($_POST as $_key => $_value) { $_key{0} != '_' && $_M['form'][$_key] = daddslashes($_value); } foreach($_GET as $_key => $_value) { $_key{0} != '_' && $_M['form'][$_key] = daddslashes($_value); } if(is_numeric($_M['form']['lang'])){//伪静态兼容 $_M['form']['page'] = $_M['form']['lang']; $_M['form']['lang'] = ''; } if($_M['form']['metid'] == 'list'){ $_M['form']['list'] = 1; $_M['form']['metid'] = $_M['form']['page']; $_M['form']['page'] = 1; } if(!preg_match('/^[0-9A-Za-z]+$/', $_M['form']['lang']) && $_M['form']['lang']){ echo "No data in the database,please reinstall."; die(); } }
把COOKIE、POST、GET 传入 daddslashes函数进行过滤
function daddslashes($string, $force = 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 { if(!defined('IN_ADMIN')){ $string = trim(addslashes(sqlinsert($string))); }else{ $string = trim(addslashes($string)); } } } return $string; }
这里判断是否开启了get_magic_quotes_gpc() 如果没开启或者 $force !=0 就进入过滤。
然而最重要的环节在这里
if(!defined('IN_ADMIN')){ $string = trim(addslashes(sqlinsert($string))); }else{ $string = trim(addslashes($string)); }
判断 IN_ADMIN 常量是否已经定义了,如果没定义就使用 $string = trim(addslashes(sqlinsert($string)));
来过滤我们的值
而如果定义了就使用 $string = trim(addslashes($string));
来过滤。
刚刚我们进行sql注入测试失败而且语句被过滤了, addslashes只过滤特殊字符,所以我们肯定是被 sqlinsert函数给过滤了。导致我们无法sql注入。至于sqlinsert函数我就不贴出来了,我们要做的是饶过这个函数,而不是饶过他这个规则。
defined('IN_ADMIN') 我们需要找这个常量在哪里定义的。其实写这句话有点多余,看过我之前几篇Metinfo漏洞的话应该就会发现问题了。我写过一个关于/admin/index.php文件任意调用带do方法的问题。
然后我们打开这个文件看一下。
<?php define('IN_ADMIN', true); $M_MODULE='admin'; if(@$_GET['m'])$M_MODULE=$_GET['m']; if(@!$_GET['n'])$_GET['n']="index"; if(@!$_GET['c'])$_GET['c']="index"; if(@!$_GET['a'])$_GET['a']="doindex"; @define('M_NAME', $_GET['n']); @define('M_MODULE', $M_MODULE); @define('M_CLASS', $_GET['c']); @define('M_ACTION', $_GET['a']); require_once '../app/system/entrance.php'; ?>
没错这个常量就是在这个文件定义的。而且他可以调用任意带do方法。不过问题又来了,漏洞函数是add并且不带do,那就找调用白,于是找到 domessage这个函数。
domessage方法 18-24
public function domessage() { global $_M; if($_M['form']['action'] == 'add'){ $this->check_field(); $this→add($_M['form']);
这里在调用 add方法之前先调用了 check_field方法,我们要做的就是保证程序能够顺利执行到add方法,研究了一会发现只需要正常留言,把它传递的参数拷下来就ok了。
然后顺利执行到了add方法,成功的进行了sql注入。
这里说一下这个id=42,这个值42是不能修改的,目的是让他返回验证码错误,饶过了第一层判断。
if(!$_M[config][met_fd_ok])okinfo('javascript:history.back();',"{$_M[word][Feedback5]}"); if($_M[config][met_memberlogin_code]){ if(!load::sys_class('pin', 'new')->check_pin($_M['form']['code'])){ okinfo(-1, $_M['word']['membercode']); } }
至于为什么让他饶过第一层判断返回验证码错误,这样的话我们可以布尔盲注,否则只能进行时间注入。这里不多解释,自己研究一下。
0x03 解决方法
修改文件:metinfo6.1.2/app/system/message/web/message.class.php 修改内容: $met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and name= 'met_fd_ok' and columnid = {$_M[form][id]}"); 修改为: $met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and name= 'met_fd_ok' and columnid = ‘{$_M[form][id]}’"); 这样就解决了。
0x04 漏洞验证脚本
这里我做了一个脚本来看一下效果
想要的在后面下载。
0x05 结束语
脚本在这。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Angular 4 依赖注入教程之二 组件中注入服务
- 服务端注入之Flask框架中服务端模板注入问题
- 服务器端电子表格注入 - 从公式注入到远程代码执行
- SQL注入测试技巧TIP:再从Mysql注入绕过过滤说起
- 手机抓包+注入黑科技HttpCanary——最强大的Android抓包注入工具
- 三, 跨语言微服务框架 - Istio官方示例(自动注入.请求路由.流量控制.故障注入) 原 荐
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。