漏洞demo:
public function inc() { $username = request()->get('name/a'); db('user')->insert(['name' => $username]); return 'Update success'; }
首先看TP的数据获取:$username = request()->get('name/a');
request(助手函数就是获取thinkphp/library/think/Request.php 的实例,然后调用其get方法:
重点跟进input(方法:
exp数据这种就是在这里过滤的。
input助手函数干的事:
1.使用默认的过滤器进行过滤
2.过了EXP这种表达式关键字符
3.对数据类型进行强制转化,默认是字符串格式
然后接着看操作数据库一块:db('user')->insert(['name' => $username]);
db助手函数:
thinkphp/library/think/Db.php 数据库的工厂类:
return hinkdbconnectorMysql 对象的实例:
继承于:thinkphp/library/think/db/Connection.php 类。
然后继续执行 ->name($name); 则会触发thinkphp/library/think/db/Connection.php 类中的 __call 方法:
这里回调的类就是: hinkdbQuery 类中的name( 方法:
hinkdbQuery 中的__construct( 方法:
builder 属性就是 hinkdbuilderMysql 类的实例:
父类:thinkphp/library/think/db/Builder.php
整个TP的DB类库我们就已经理完了,TP5相对TP3来说代码也更加优化了,代码逐渐组件化,各自的职责也更加明显了,实现了代码分离。
下面开始分析漏洞代码:
db('user')->insert(['name' => $username]);
db('user')主要还是进行了name属性的设置,并且return thinkphp/library/think/db/Query 实例。
继续调用了:think/db/Query 类中的 insert( 方法:
跟进:$options = $this->parseExpress();
将链式操作中设置的$this->options属性进行解析合并。
eg: db('name')->where()->order()->select(); 这种操作。
然后看重点:
$sql = $this->builder->insert($data, $options, $replace);
通过前面的分析,我们已经知道$this->builder 属性就是 hinkdbuilderMysql 类的实例:
因为input数据获取函数并没有过滤inc,dec这两个值,导致可以进入到这里,造成注入。
漏洞exp:
/public/index.php/index/index/inc?name[0]=inc&name[1]=updatexml(1,concat(0x23,user(),0x7e),1)&name[2]=1
网上说的漏洞版本: 5.0.13<=ThinkPHP<=5.0.15 、 5.1.0<=ThinkPHP<=5.1.5
主要还是为了照顾一个朋友,所以写的细一点,自己也刚好记录一下。