public function test01()
{
$data = M('user')->find(I('GET.id'));
var_dump($data);
}
payload:http://tp32.com/index.php/home/index/test01?id[where]=1 and 1=updatexml(1,concat(0x7e,database(),0x7e),1)
漏洞分析:
首先在如下地方进行下断点分析
一开始肯定是触发自动加载机制,实例化一个数据库操作对象
返回接着进入到 I 方法中对接收的参数进行分割判断
然后 I 方法中进行一次 htmlspecialchars 和 think_filter 的过滤处理
随后从I方法中出来之后就进入到了 find 方法中
接着来到进入 _parseOptions 方法中,来进行字段的验证的处理
主要是这段代码,当我们id[where]
是这样的时候,这段代码是不走的,因为is_array($options['where'])
这个条件不满足
出来了之后接着继续走select 方法
之后的都很正常数据也没被处理,最后导致了SQL注入
那么最主要的原因其实也就是 _parseOptions 方法中 字段类型验证 ,如果is_array($options['where'])
这个条件满足,那么我们注入的SQL语句都会被_parseType 进行强转,如果是id[where]则导致不满足,从而产生了SQL注入!
那么我们来跟下如果传入的url是http://tp32.com/index.php/home/index/test01?id=1 and 1=updatexml(1,concat(0x7e,database(),0x7e),1)
,结果会如何
首先这里会让$options[where]下面成为一个数组
然后继续进入到 _parseOptions 方法中
此时该条件满足 所以进入到 字段类型验证的操作
接着继续进入到 _parseType 的方法中该id字段下的内容,就是sql注入的内容就会被强转为 int 类型 导致最后无法触发!!!
修复代码:
https://github.com/top-think/thinkphp/commit/9e1db19c1e455450cfebb8b573bb51ab7a1cef04
v3.2.4 将 $options 和 $this->options 进行了区分,从而传入的参数无法污染到 $this->options,也就无法控制sql语句了