2018-10-25 20:22:2829096人阅读
1. 漏洞描述
MetInfo企业建站系统采用了开源的PHP+MySQL架构,第一个版本于2009年发布,目前最新的版本是V6.1.2,更新于2018年9月26日。MetInfo是一款功能全面、使用简单的企业建站软件,用户可以在不需要任何编程的基础上,通过简单的安装和可视化编辑设置就能够在互联网搭建独立的企业网站,能够极大的降低企业建站成本。目前国内各行业网站均有MetInfo的身影。此次爆出漏洞的版本是官网在9月26日所发布的最新版6.1.2版本,无需登录即可进行SQL注入,漏洞编号CNVD-2018-20024.
2. 影响版本
Metinfo 6.1.2、6.1.1、6.1.0版本
3. 漏洞分析
漏洞位于app/system/message/web/message.class.php 43行add()方法中,columnid = {$_M[form][id]}没有被单引号保护,存在安全隐患。
接着看参数怎么传递进来的,由于message类继承了web类,我们跟进到app/system/include/class/web.class.php;web类继承了common类,并且其构造函数直接使用了父类的构造函数;再跟进到app/system/include/class/common.class.php,其构造函数调用了load_form()方法进行表单过滤。
load_form()方法主要获取GET、POST、COOKIE方法传递的参数放在$_M['form']中,并经daddslashes()方法过滤。
daddslashes()定义在app/system/include/function/common.func.php第51行,对传递的参数进行addslashes()操作。这里注意,在else语句中,如果之前定义了IN_ADMIN常量,进行trim(addslashes(sqlinsert($string)))操作,反之则进行trim(addslashes($string))。
之前所述的安全隐患点为int型,所以addslashes()函数没有作用,而sqlinsert()函数则如下定义,对常见的SQL注入关键字进行替换,包括select、sleep等,所以这里主要是要绕过sqlinsert(),需要寻找到定义过IN_ADMIN常量的入口。
这里通过搜索找到了admin/index.php,文件第5行定义了IN_ADMIN常量。接着看从admin/index.php入口文件如何调用add()函数的,index.php定义了4个常量,并且包含了app/system/entrance.php。
进入app/system/entrance.php,38-44行,入口文件没有定义M_TYPE,这里会设置M_TYPE常量为system;54-59行,由于定义了M_TYPE为system,进行设置PATH_OWN_FILE常量为PATH_APP.M_TYPE.'/'. M_NAME.'/'.M_MODULE.'/',其中M_NAME、M_MODULE均可控。88-99行包含app/system/include/class/load.class.php,并调用了module()方法。
由于调用module()方法时缺省了参数,因此$path、$modulename、$action均有之前定义的常量赋值,然后再调用_load_class()方法。_load_class()方法可以引用并实例化一个类,当action为空的时候,只引用文件。当action为new时候,会实例化这个类。当action为do开头时候,会实例化类,并执行这个方法。
要想包含app/system/message/web/message.class.php文件,需要满足
M_NAME = $_GET['n'] = message;
M_MODULE = $_GET['m'] = web;
M_CLASS = $_GET['c'] = message;
要想调用add(),必须实例化类并执行方法,但这里限定只能实例化并执行do开头的方法。这里找到了message.class.php中的domessage(),它调用了add()方法。
在调用add()方法前,需要满足$this->check_field();,这里发现只要抓取正常的留言参数填充就可以了,验证码的判断是在add()方法中执行完漏洞语句之后。为了实现布尔注入而不是时间盲注,需要正常时$met_fd_ok的值不为空,从而绕过45行判断,弹出"验证码错误",而异常时$met_fd_ok值为空,弹出"反馈已关闭"。
在数据库中执行一下存在漏洞的SQL语句,看看符合条件的id参数有哪些,满足的columnid有42和44,所以漏洞原作者说只能是42还是不太准确。
最终可以构造如下GET请求注入,注入点为id:
admin/index.php?m=web&n=message&c=message&a=domessage&action=add&lang=cn¶137=1¶186=1@qq.com¶138=1¶139=1¶140=1&id=42 and 1=1
4. 修复建议
将app/system/message/web/message.class.php 43行代码修改如下:
$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]}'"); //单引号保护
5. 参考
https://nosec.org/home/detail/1889.html
https://bbs.ichunqiu.com/thread-46687-1-1.html
本文来自百度安全SiemPent Team,转载请注明出处及本文链接