当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(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标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

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

01.jpg


WTF,如果where语句的条件是数组,而且数组的第一个值是'exp',那么第二个值就可以直接写SQL语句?
WTF,那岂不是一个完美的SQL注入?
可能有些人不明白。我说细一点,很多站长写查询语句会这样:

$data = array();
$data['user'] = $_POST['username'];
$data['pass'] = md5($_POST['password']);
M('user')->where($data)->find();


这应该是一个ThinkPHP对数据库查询的基础方法。那么,如果我传入的参数是这样:
username[0]=exp&username[1]=aa'or 1=1%23&password=1,那么,是不是就是一个完美的万能密码?
这个特性在thinkphp3.1、3.2版本中均存在,通用性比较广,危害很大。
有的同学可能觉得有一定局限性,因为thinkphp的I函数中有如下代码:

}elseif(isset($input[$name])) { // 取值操作
$data = $input[$name];
is_array($data) && array_walk_recursive($data,'filter_exp');
$filters = isset($filter)?$filter:C('DEFAULT_FILTER');
if($filters) {
if(is_string($filters)){
$filters = explode(',',$filters);
}elseif(is_int($filters)){
$filters = array($filters);
}

foreach($filters as $filter){
if(function_exists($filter)) {
$data = is_array($data)?array_map_recursive($filter,$data):$filter($data); // 参数过滤
}else{
$data = filter_var($data,is_int($filter)?$filter:filter_id($filter));
if(false === $data) {
return isset($default)?$default:NULL;
}
}
}
}
}else{ // 变量默认值
$data = isset($default)?$default:NULL;
}


is_array($data) && array_walk_recursive($data,'filter_exp');有个简单的过滤,看看filter_exp函数:

function filter_exp(&$value){
if (in_array(strtolower($value),array('exp','or'))){
$value .= ' ';
}
}


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如下数据包即可发现报错(为了方便操作,我注释了验证码检查部分,实际操作中带上验证码发送数据包即可):

02.jpg


爆出数据库用户名:

03.jpg


究其原因,我们看到login处的代码,/Application/Admin/Controller/PublicController.class.php:

public function login($username = null, $password = null, $verify = null){
if(IS_POST){
/* 检测验证码 TODO: */
if(!check_verify($verify)){
//$this->error('验证码输入错误!');
}
/* 调用UC登录接口登录 */
$User = new UserApi;
$uid = $User->login($username, $password);
if(0 < $uid){ //UC登录成功
/* 登录用户 */
$Member = D('Member');
if($Member->login($uid)){ //登录用户
//TODO:跳转到登录前页面
$this->success('登录成功!', U('Index/index'));
} else {
$this->error($Member->getError());
}
} else { //登录失败
switch($uid) {
case -1: $error = '用户不存在或被禁用!'; break; //系统级别禁用
case -2: $error = '密码错误!'; break;
default: $error = '未知错误!'; break; // 0-接口参数错误(调试阶段使用)
}
$this->error($error);
}
} else {
if(is_login()){
$this->redirect('Index/index');
}else{
/* 读取数据库中的配置 */
$config = S('DB_CONFIG_DATA');
if(!$config){
$config = D('Config')->lists();
S('DB_CONFIG_DATA',$config);
}
C($config); //添加配置

$this->display();
}
}
}


获取了$username和$password后传入login函数,跟进:

public function login($username, $password, $type = 1){
return $this->model->login($username, $password, $type);
}


又传入$this->model->login函数,跟进:

public function login($username, $password, $type = 1){
$map = array();
switch ($type) {
case 1:
$map['username'] = $username;
break;
case 2:
$map['email'] = $username;
break;
case 3:
$map['mobile'] = $username;
break;
case 4:
$map['id'] = $username;
break;
default:
return 0; //参数错误
}
/* 获取用户数据 */
$user = $this->where($map)->find();
if(is_array($user) && $user['status']){
/* 验证用户密码 */
if(think_ucenter_md5($password, UC_AUTH_KEY) === $user['password']){
$this->updateLogin($user['id']); //更新用户登录信息
return $user['id']; //登录成功,返回用户ID
} else {
return -2; //密码错误
}
} else {
return -1; //用户不存在或被禁用
}
}


如我之前说的,直接带入where语句。于是我们只需要让username是一个数组,第一个值为exp,第二个值为注入语句即可。
thinkphp的这个注入与mongodb注入类似,虽然处于框架之中,但因为框架设计不合理导致注入的产生。

修复方案:

不知道。

版权声明:转载请注明来源 phith0n@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:12

确认时间:2014-12-11 17:02

厂商回复:

该漏洞在系统没有对用户数据做严谨判断的情况下会导致SQL注入的产生。目前的github版本TP和OT均已修正~

最新状态:

2014-12-13:感谢作者的反馈,在上一版的基础上改进了修正方法,包括I函数和全局过滤机制。


漏洞评价:

评论

  1. 2014-12-11 09:01 | Coody 认证白帽子 ( 核心白帽子 | Rank:1565 漏洞数:189 | 不接单、不黑产;如遇接单收徒、绝非本人所...)

    卧槽,牛逼

  2. 2014-12-11 09:03 | bitcoin ( 普通白帽子 | Rank:715 漏洞数:218 | 学习是最好的投资!)

    你关注的白帽子 phith0n 发表了漏洞 ThinkPHP框架架构上存在SQL注入

  3. 2014-12-11 09:03 | 天地不仁 以万物为刍狗 ( 普通白帽子 | Rank:977 漏洞数:264 | 天地本不仁 万物为刍狗)

    前排 为什么楼主不选通用呢?通用有现金啊。。。。

  4. 2014-12-11 09:05 | 残废 ( 普通白帽子 | Rank:179 漏洞数:40 | 我是残废,啦啦啦啦)

    卧槽 吊炸天

  5. 2014-12-11 09:06 | 残废 ( 普通白帽子 | Rank:179 漏洞数:40 | 我是残废,啦啦啦啦)

    前排出售瓜子 香烟 Ph牛叼炸天

  6. 2014-12-11 09:07 | roker ( 普通白帽子 | Rank:357 漏洞数:108 )

    师傅好叼

  7. 2014-12-11 09:10 | ljhj ( 路人 | Rank:29 漏洞数:7 | 专注弱口令30年,好品质值得信赖。)

    洞主牛逼,能带我飞么?

  8. 2014-12-11 09:11 | 玉林嘎 ( 普通白帽子 | Rank:758 漏洞数:96 )

    膜拜P牛

  9. 2014-12-11 09:24 | 一只猿 ( 普通白帽子 | Rank:463 漏洞数:89 | 硬件与无线通信研究方向)

    这个屌啊

  10. 2014-12-11 09:28 | sn... ( 实习白帽子 | Rank:91 漏洞数:12 | 感觉下面有点硬。。。)

    洞主 好叼。。。

  11. 2014-12-11 09:30 | hkAssassin ( 普通白帽子 | Rank:358 漏洞数:66 | 我是一只毛毛虫。)

    这个屌!!

  12. 2014-12-11 09:32 | 点点 ( 普通白帽子 | Rank:214 漏洞数:38 | 准备申请سمَـَّوُوُحخ ̷̴̐...)

    @xsser 预测这么准

  13. 2014-12-11 09:39 | 浩天 认证白帽子 ( 普通白帽子 | Rank:915 漏洞数:79 | 度假中...)

    思维好激进

  14. 2014-12-11 09:45 | chock ( 实习白帽子 | Rank:58 漏洞数:15 | 今夜我们都是wooyun人,我们一定要收购长亭)

    关注

  15. 2014-12-11 09:49 | 子非海绵宝宝 认证白帽子 ( 核心白帽子 | Rank:1044 漏洞数:106 | 发扬海绵宝宝的精神!你不是海绵宝宝,你怎...)

    牛逼!!

  16. 2014-12-11 09:59 | 北洋贱队 ( 普通白帽子 | Rank:252 漏洞数:25 )

    什么时候公开,急需详情

  17. 2014-12-11 10:01 | 泳少 ( 普通白帽子 | Rank:231 漏洞数:79 | ★ 梦想这条路踏上了,跪着也要...)

    思路挺不错的啊

  18. 2014-12-11 10:06 | loserkk ( 路人 | Rank:2 漏洞数:1 | 请不要这样子看着我!!)

    关注

  19. 2014-12-11 10:10 | 浮萍 ( 普通白帽子 | Rank:555 漏洞数:118 | 默默潜水)

    mark

  20. 2014-12-11 10:21 | Power ( 实习白帽子 | Rank:54 漏洞数:22 | 还需要等待.........)

    关注

  21. 2014-12-11 10:21 | 铁蛋火车侠 ( 普通白帽子 | Rank:156 漏洞数:31 | Q群371620085 技术交流群 有漂亮妹纸!)

    我操

  22. 2014-12-11 10:23 | 疯狂的dabing ( 实习白帽子 | Rank:33 漏洞数:9 | Hehe is golden.)

    我去,这么屌,很难想象TP会犯这种错误,坐等详情!

  23. 2014-12-11 10:26 | 牛肉包子 ( 普通白帽子 | Rank:254 漏洞数:64 )

    屌屌啊!

  24. 2014-12-11 10:34 | qiaoy ( 普通白帽子 | Rank:110 漏洞数:16 )

    .

  25. 2014-12-11 11:00 | Ano_Tom ( 普通白帽子 | Rank:368 漏洞数:40 | Talk is cheap.:)

  26. 2014-12-11 11:06 | phith0n 认证白帽子 ( 核心白帽子 | Rank:656 漏洞数:107 | 一个想当文人的黑客~)

    @天地不仁 以万物为刍狗 你咋知道不是通用?

  27. 2014-12-11 11:10 | ghy459 ( 实习白帽子 | Rank:62 漏洞数:5 | 深挖洞,广积shell。)

    膜拜膜拜~

  28. 2014-12-11 11:24 | Blunber ( 实习白帽子 | Rank:84 漏洞数:13 )

    mark

  29. 2014-12-11 11:37 | 狗狗侠 ( 普通白帽子 | Rank:497 漏洞数:55 | 我是狗狗侠)

    是绕过thinkphp框架进行注入?

  30. 2014-12-11 11:59 | 天地不仁 以万物为刍狗 ( 普通白帽子 | Rank:977 漏洞数:264 | 天地本不仁 万物为刍狗)

    @phith0n 没看见标志···

  31. 2014-12-11 12:00 | 兔兔侠 ( 路人 | Rank:2 漏洞数:1 )

    内容呢

  32. 2014-12-11 12:09 | 寂寞的瘦子 ( 普通白帽子 | Rank:242 漏洞数:53 | 一切语言转汇编理论)

    安全架构师了!!!

  33. 2014-12-11 12:48 | answer ( 普通白帽子 | Rank:347 漏洞数:45 | 答案)

    溜溜 膜拜p牛

  34. 2014-12-11 12:49 | Neeke ( 普通白帽子 | Rank:101 漏洞数:24 | 求传授刷Rank方法?)

    坐等公开

  35. 2014-12-11 13:14 | 小胖子 认证白帽子 ( 核心白帽子 | Rank:1727 漏洞数:140 | 如果大海能够带走我的矮丑...)

    ph牛好叼,我换个马甲你还知道我是谁吗!!哇哈哈哈哈哈

  36. 2014-12-11 13:34 | mramydnei ( 普通白帽子 | Rank:348 漏洞数:80 )

    @小胖子 我分分钟看出来你是谁

  37. 2014-12-11 13:34 | 0749orz ( 路人 | Rank:3 漏洞数:4 | 厌了,烦了~~~)

    坐等公开

  38. 2014-12-11 13:41 | 笨笨熊 ( 路人 | Rank:0 漏洞数:1 | PHPer)

    坐等公开啊!!!

  39. 2014-12-11 14:39 | px1624 ( 普通白帽子 | Rank:1036 漏洞数:175 | px1624)

    膜拜p牛

  40. 2014-12-11 15:12 | 秋风 ( 普通白帽子 | Rank:438 漏洞数:44 | 码农一枚,关注互联网安全)

    NB!

  41. 2014-12-11 15:15 | hkAssassin ( 普通白帽子 | Rank:358 漏洞数:66 | 我是一只毛毛虫。)

    你们都看到细节了么!都说思路牛逼,我也知道思路牛逼可是没细节啊!

  42. 2014-12-11 17:16 | 袋鼠妈妈 ( 普通白帽子 | Rank:449 漏洞数:61 | 故乡的原风景.MP3)

    强留名

  43. 2014-12-11 18:05 | xiaobai ( 实习白帽子 | Rank:40 漏洞数:1 | 别看资料看聊效)

    https://github.com/payonesmile/thinkphp/commit/23c6e130ce75f2132e5b48699363a75ed28e15b2这里有问题代码位置,可以推断~

  44. 2014-12-11 18:38 | 龍 、 ( 普通白帽子 | Rank:398 漏洞数:135 | 你若安好 我就是晴天)

    洞主牛逼,能带我飞么?

  45. 2014-12-11 19:40 | bey0nd ( 普通白帽子 | Rank:895 漏洞数:142 | 相忘于江湖,不如相濡以沫)

    @xiaobai 应该是

  46. 2014-12-11 22:34 | 哲璇 ( 普通白帽子 | Rank:168 漏洞数:31 | 低调奢华)

    火钳刘明

  47. 2014-12-11 22:46 | Tang ( 实习白帽子 | Rank:38 漏洞数:5 | 忙碌状态)

    坐等公开

  48. 2014-12-12 14:00 | lazypig ( 路人 | Rank:0 漏洞数:2 | 如果你决定了方向,勇气可以带你走的更远。)

    后排出售盒饭

  49. 2014-12-12 15:20 | 临雨听风 ( 路人 | Rank:5 漏洞数:1 | 新人求罩)

    围观学长~

  50. 2014-12-13 09:47 | Xser ( 普通白帽子 | Rank:194 漏洞数:61 | JDSec)

    @phith0n 我记得Thinkphp的where查看如果只对字符型的,他是不会过滤的 = =……他过滤数组进去的和对象进去的对象。。。。。。。。。应该漏洞是这样引起的吧

  51. 2014-12-13 13:50 | phith0n 认证白帽子 ( 核心白帽子 | Rank:656 漏洞数:107 | 一个想当文人的黑客~)

    @Xser 不是。

  52. 2014-12-14 09:30 | Glory ( 路人 | Rank:2 漏洞数:1 | 一名在校初中屌丝。没钱没职业。就知道撸政...)

    都这么牛逼,活不下去了

  53. 2014-12-15 09:56 | no.thinking ( 路人 | Rank:4 漏洞数:3 | no.thinking)

    mark

  54. 2014-12-15 10:51 | Damo ( 普通白帽子 | Rank:209 漏洞数:31 | 我只是喜欢看加菲猫而已ส็็็็็็็็...)

    @phith0n 我要给你生孩子

  55. 2014-12-15 12:48 | 多情公子 ( 路人 | Rank:0 漏洞数:2 | google)

    卧槽,好屌...

  56. 2014-12-15 14:01 | abaddon ( 实习白帽子 | Rank:37 漏洞数:10 | 我叫什么名字)

    基于架构的三个美刀符号的闪电 好钓 等公开 要把这报告读透了

  57. 2014-12-16 09:53 | f4ckbaidu ( 普通白帽子 | Rank:182 漏洞数:23 | 开发真是日了狗了)

    屌炸天,mark

  58. 2014-12-16 11:54 | 六都仔刘满 ( 路人 | 还没有发布任何漏洞 | 我自横刀向天笑,去留肝胆两昆仑!)

    ph牛好叼,我换个马甲你还知道我是谁吗!!哇哈哈哈哈哈

  59. 2014-12-22 21:37 | cat73 ( 实习白帽子 | Rank:34 漏洞数:6 | 喵爱吃鱼, 喵要吃好多好多鱼~~地址栏输入...)

    @xiaobai 厂商回复提到了I函数的修改与输入过滤问题 应该是这个吧: https://github.com/liu21st/thinkphp/commit/5f95d62cf2f978609d44c8072ee399aa64a6c2e3

  60. 2014-12-23 23:37 | sin ( 实习白帽子 | Rank:38 漏洞数:2 | 寻找最优雅的解决方案)

    @xiaobai @cat73 你们2个太机智了.......

  61. 2015-01-06 21:04 | 1c3z ( 实习白帽子 | Rank:88 漏洞数:29 | 我读书少,你可别骗我!!!)

    看到3个美元符号就点进来了

  62. 2015-01-24 13:49 | BeenQuiver ( 普通白帽子 | Rank:101 漏洞数:26 | 专注而高效,坚持好的习惯千万不要放弃)

    thinking method!

  63. 2015-01-29 18:21 | 1c3z ( 实习白帽子 | Rank:88 漏洞数:29 | 我读书少,你可别骗我!!!)

    thank for share!!

  64. 2015-02-19 21:33 | Friday ( 实习白帽子 | Rank:40 漏洞数:10 | 破土的小竹笋)

    为神马加了个空格,就算是过滤了exp?

  65. 2015-03-11 09:18 | Mark ( 路人 | Rank:8 漏洞数:2 | 渗透你的心)

    被雷劈了

  66. 2015-03-11 10:41 | ppt ( 路人 | Rank:11 漏洞数:2 | ) | ( 我猜出了用户名,可我没猜出密码。)

    这种“新”特性可以多看看

  67. 2015-03-11 12:14 | 小峰子0204 ( 路人 | Rank:6 漏洞数:5 )

    这个牛

  68. 2015-03-14 00:44 | 崔超杰 ( 普通白帽子 | Rank:192 漏洞数:53 | 知仙)

    不错

  69. 2015-03-30 17:32 | Sunshie ( 实习白帽子 | Rank:58 漏洞数:10 | http://phpinfo.me)

    牛B

  70. 2015-04-24 23:58 | mango ( 核心白帽子 | Rank:1668 漏洞数:248 | 我有个2b女友!)

    表达式错误:$username[1]=AAA'A

  71. 2015-09-23 10:40 | sOnsec ( 实习白帽子 | Rank:93 漏洞数:24 | 安全是什么...)

    赞p牛