漏洞概要 关注数(24) 关注此漏洞
缺陷编号:wooyun-2014-086737
漏洞标题:ThinkPHP框架架构上存在SQL注入
相关厂商:ThinkPHP
漏洞作者: phith0n
提交时间:2014-12-11 08:58
修复时间:2015-03-11 09:00
公开时间:2015-03-11 09:00
漏洞类型:SQL注射漏洞
危害等级:高
自评Rank:20
漏洞状态:厂商已经确认
漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]
Tags标签: 无
漏洞详情
披露状态:
2014-12-11: 细节已通知厂商并且等待厂商处理中
2014-12-11: 厂商已经确认,细节仅向厂商公开
2014-12-14: 细节向第三方安全合作伙伴开放
2015-02-04: 细节向核心白帽子及相关领域专家公开
2015-02-14: 细节向普通白帽子公开
2015-02-24: 细节向实习白帽子公开
2015-03-11: 细节向公众公开
简要描述:
ThinkPHP框架本身缺陷导致SQL注入漏洞,基本影响所有使用ThinkPHP开发的应用,包括thinksns、onethink等,这里以thinkphp自家的OneThink为例。
这个猛料,希望能加精呀~
详细说明:
很多人天真的以为,使用了框架提供的数据库查询方法,不再进行SQL语句拼接,就能完美避免SQL注入。那么你就错了,有时候框架反而成为带你进入陷阱的人。
我们翻开最新版thinkphp框架文档,其中的“表达式查询”章节:http://document.thinkphp.cn/manual_3_2.html#express_query
WTF,如果where语句的条件是数组,而且数组的第一个值是'exp',那么第二个值就可以直接写SQL语句?
WTF,那岂不是一个完美的SQL注入?
可能有些人不明白。我说细一点,很多站长写查询语句会这样:
这应该是一个ThinkPHP对数据库查询的基础方法。那么,如果我传入的参数是这样:
username[0]=exp&username[1]=aa'or 1=1%23&password=1,那么,是不是就是一个完美的万能密码?
这个特性在thinkphp3.1、3.2版本中均存在,通用性比较广,危害很大。
有的同学可能觉得有一定局限性,因为thinkphp的I函数中有如下代码:
is_array($data) && array_walk_recursive($data,'filter_exp');有个简单的过滤,看看filter_exp函数:
exp后面会加个空格。不过有几个很严重的问题:
一、filter_exp在I函数的fiter之前,所以如果开发者这样写I('get.school', '', 'trim'),那么会直接清除掉exp后面的空格,导致过滤无效。而这个写法是很普遍的,包括我自己都经常这样写。
二、thinkphp的MVC架构中,Controller函数的变量也作为GET/POST传参的方式,如http://serverName/index.php/Home/Blog/archive/year/2013/month/11我们即可访问到public function archive($year='2013',$month='01')。而这个URL同样可以写为http://serverName/index.php?c=Blog&a=archive&year=2013&month=11,那么同样可以写为http://serverName/index.php?c=Blog&a=archive&year=2013&month[0]=exp&month[1]=sqli
这是文档里自己的例子:http://document.thinkphp.cn/manual_3_2.html#action_bind,这样传递的参数是不会经过I函数的,所以I函数里的过滤也没有效果。漏洞证明里的OneThink就是因为这个原因被注入的。
三、thinkphp老版本并不是使用I函数获取变量,但exp这个特性确实一直存在的。包括thinksns中,也是直接使用$_POST[xxx]获取的变量值,所以这个安全隐患会一直存在。在Thinksns中我也找到了实例验证。
以OneThink 1.1为例说明吧,详见漏洞证明。
漏洞证明:
OneThink是ThinkPHP自家出的一个内容管理系统,方便开发者进行二次开发。
官网:http://www.onethink.cn/, 最新版为1.1。
安装好,直接向后台登录处POST如下数据包即可发现报错(为了方便操作,我注释了验证码检查部分,实际操作中带上验证码发送数据包即可):
爆出数据库用户名:
究其原因,我们看到login处的代码,/Application/Admin/Controller/PublicController.class.php:
获取了$username和$password后传入login函数,跟进:
又传入$this->model->login函数,跟进:
如我之前说的,直接带入where语句。于是我们只需要让username是一个数组,第一个值为exp,第二个值为注入语句即可。
thinkphp的这个注入与mongodb注入类似,虽然处于框架之中,但因为框架设计不合理导致注入的产生。
修复方案:
不知道。
版权声明:转载请注明来源 phith0n@乌云
漏洞回应
厂商回应:
危害等级:高
漏洞Rank:12
确认时间:2014-12-11 17:02
厂商回复:
该漏洞在系统没有对用户数据做严谨判断的情况下会导致SQL注入的产生。目前的github版本TP和OT均已修正~
最新状态:
2014-12-13:感谢作者的反馈,在上一版的基础上改进了修正方法,包括I函数和全局过滤机制。