测试url:
http://127.0.0.1/thinkphp/thinkphp_5.1.24/public/index.php/index/index/sqli2?id=2
控制器是获取id参数作为进行聚合查询的字段名,如下图所示
看一下存在漏洞的parseKey方法
可以看到,这里直接在$key的前后加上反引号就直接返回了。根据前面几个漏洞的分析我们可以知道parseKey是用来解析字段名的。对于insert和update之类的数据,程序一般是字段名固定,数据和where语句的等于号之后的值部分可控,因此在这两种查询中parseKey里的参数是用户接触不到的【update member set money=$m where id=$id】。而对于聚合查询而言,一共就只需要一个字段名参数【select max($id) from member】,如果用户可控,就刚好在parseKey进行了拼接。
调试一下,url如下:
http://127.0.0.1/thinkphp/thinkphp_5.1.24/public/index.php/index/index/sqli2?id=kkk
跟进aggregate
跟进parseKey,注意这里的第三个参数为true
可以看到,由于第三个参数是true,所以143行是一个恒真条件,然后在144行在$key前后加上反引号`,最后直接返回。
我们在最终执行SQL语句处看一下最后的SQL语句是啥。
可以看到直接拼接了进去。尝试payload:
id`) from member where updatexml(1,concat(0x7e,user(),0x7e),1) %23
可以看到,我们的数据成功逃逸出了反引号和括号。
不过这个payload的限制就是payload前半部分的id`) from member必须是存在的字段名和表名,否则前半部分就会报错。如果师傅们有啥姿势欢迎留言~