### 简要描述: 没有上一个问题严重,但也是thinkphp设计上的隐患,提出来希望能修改,不过忽略了也没办法。 实际上这两个洞的意义不仅于此,这是框架流行的时代,注入的一个新思路。 ### 详细说明: 这个问题其实应该从前段时间Th1nk发的mongodb注入说起,http://drops.wooyun.org/tips/3939,其中提到了mongodb一种注入方式: [<img src="https://images.seebug.org/upload/201412/11010451ed8ce1bd4914c841e72711fd60631a1c.jpg" alt="05.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201412/11010451ed8ce1bd4914c841e72711fd60631a1c.jpg) 然后parsec团队里前段时间也在讨论这个问题,究竟这个漏洞是php的特性,还是mongodb的特性。后来jin发了一个精华:http://wooyun.org/bugs/wooyun-2010-086474,也从侧面印证了一个问题,这个特性(获得的GP可以是字符串也可以是数组)不仅仅是PHP存在,只要框架支持,那么就可以存在。 当然我这个洞是PHP的洞,但实际上问题出在thinkphp框架上。 问题还是在“表达式查询”这里:http://document.thinkphp.cn/manual_3_2.html#express_query 在文档里看到,我们居然可以控制查询表达式的符号: [<img src="https://images.seebug.org/upload/201412/110100502d3a9b64af7553e2c6e93c2b44c0bf8b.jpg" alt="04.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201412/110100502d3a9b64af7553e2c6e93c2b44c0bf8b.jpg)...
### 简要描述: 没有上一个问题严重,但也是thinkphp设计上的隐患,提出来希望能修改,不过忽略了也没办法。 实际上这两个洞的意义不仅于此,这是框架流行的时代,注入的一个新思路。 ### 详细说明: 这个问题其实应该从前段时间Th1nk发的mongodb注入说起,http://drops.wooyun.org/tips/3939,其中提到了mongodb一种注入方式: [<img src="https://images.seebug.org/upload/201412/11010451ed8ce1bd4914c841e72711fd60631a1c.jpg" alt="05.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201412/11010451ed8ce1bd4914c841e72711fd60631a1c.jpg) 然后parsec团队里前段时间也在讨论这个问题,究竟这个漏洞是php的特性,还是mongodb的特性。后来jin发了一个精华:http://wooyun.org/bugs/wooyun-2010-086474,也从侧面印证了一个问题,这个特性(获得的GP可以是字符串也可以是数组)不仅仅是PHP存在,只要框架支持,那么就可以存在。 当然我这个洞是PHP的洞,但实际上问题出在thinkphp框架上。 问题还是在“表达式查询”这里:http://document.thinkphp.cn/manual_3_2.html#express_query 在文档里看到,我们居然可以控制查询表达式的符号: [<img src="https://images.seebug.org/upload/201412/110100502d3a9b64af7553e2c6e93c2b44c0bf8b.jpg" alt="04.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201412/110100502d3a9b64af7553e2c6e93c2b44c0bf8b.jpg) 这个设计和mongodb的就很类似,很可能造成安全问题,比如万能密码。 写个例子证明: ``` public function test() { if (IS_POST) { $uname = I('post.uname', '', 'trim'); $upass = I('post.upass', '', 'trim'); $remember = I('post.remember'); if (empty($uname) || empty($upass)) { $this->error('用户名或密码不能为空'); } $row = M('user')->where(array( 'uname' => $uname, 'passwd' => $upass ))->find(); if (empty($row)) { echo 0; }else{ echo 1; } } } ``` 这是控制器里的一个登录函数,如果账号/密码输入正确则输出1,否则输出0. 很普通的一个逻辑,也是经常出现在各种应用中前/后台登录的方式。 正常情况下,随便输入一个账号/密码是肯定错误的,输出0: [<img src="https://images.seebug.org/upload/201412/110117253032229d80d7b9b0b66bbc428cf2a064.jpg" alt="06.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201412/110117253032229d80d7b9b0b66bbc428cf2a064.jpg) 我们将uname[0]设置为neq,也就是“不等于”,upass[0]也设置为neq,1随意: [<img src="https://images.seebug.org/upload/201412/1101193294d2200ca51f43d0ef86dca9b7e27d13.jpg" alt="07.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201412/1101193294d2200ca51f43d0ef86dca9b7e27d13.jpg) 果然已经注入成功了,我们看看数据库语句究竟是什么: [<img src="https://images.seebug.org/upload/201412/11012029002b160f4c5b40e0d1fd38e8668edceb.jpg" alt="08.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201412/11012029002b160f4c5b40e0d1fd38e8668edceb.jpg) 实际上我们控制了操作符,所以让uname<>aaaa,upass<>bbbb,那么这句话肯定成立,就此造成了一个万能密码,成功登录。 具体实例可能需要慢慢找,因为一般password会进行md5,导致我们传入数组是不行的。但这个思路可以引申到所有使用where语句的地方。 ### 漏洞证明: 见详细说明。