0x00
继续看,这个漏洞和上一篇文章审计的依旧有很多共通之处,所以现在审计也是变得越来越轻松了。
0x01漏洞概述
本次漏洞存在于 Mysql 类的 parseWhereItem 方法中。由于程序没有对数据进行很好的过滤,直接将数据拼接进 SQL 语句。再一个, Request 类的 filterValue 方法漏过滤 NOT LIKE 关键字,最终导致 SQL注入漏洞 的产生。漏洞影响版本: ThinkPHP=5.0.10 。
环境准备
composer create-project topthink/think=5.0.10 tp5010
composer.json文件:
"require": {
"php": ">=5.4.0",
"topthink/framework": "5.0.10"
},
更新:执行composer update
接下来设置漏洞点和配置数据库
将 application/index/controller/Index.php 文件代码设置如下:
namespace app\index\controller;
class Index
{
public function index()
{
$username = request()->get('username/a');
$result = db('users')->where(['username' => $username])->select();
var_dump($result);
}
}
创建数据库信息如下:
create database tpdemo;
use tpdemo;
create table users(
id int primary key auto_increment,
username varchar(50) not null
);
insert into users(id,username) values(1,'wtz');
在 config/database.php 文件中配置数据库相关信息
开启 config/app.php 中的 app_debug 和 app_trace
漏洞分析
payload:
http://127.0.0.1:88/tp5010/public/index.php/index/index?username[0]=not%20like&username[1][0]=%%&username[1][1]=233&username[2]=)%20union%20select%201,user()%23
这里就是not like 模糊查询,
eg:
查询user表中姓名中没有“王”字的:
select * from user where name not like '%王%'
not like我们可控,这也是sql注入的直接原因
因为官方有安全更新,我们先去github上找一下对于这个sql注入漏洞的安全更新
可以看到,增加了过滤
NOT LIKE
前面已经提过:所有用户参数都会经过 Request 类的 input 方法处理,该方法会调用 filterValue 方法。
该方法是用来过滤表单中的表达式,但是我们仔细看其代码,会发现少过滤了 NOT LIKE ,而本次漏洞正是利用了这一点。
注意我们payload是NOT LIKE
我们开启debug,开始分析一下
用户输入的数据会原样进入框架的 SQL 查询方法中。首先程序先调用 Query 类的 where 方法,通过其 parseWhereExp 方法分析查询表达式,然后再返回并继续调用 select 方法准备开始构建 select 语句。(这个点得记住,框架的sql查询方法先进入 Query 类)
我们先进入Query类去看看
在select方法中
这里$this->builder 为 \think\db\builder\Mysql 类,该类继承于 Builder 类,所以接着会调用 Builder 类的 select 方法。
我们直接去看Builder 类的 select 方法。
在 select 方法中,程序会对 SQL 语句模板用变量填充,其中用来填充 %WHERE% 的变量中存在用户输入的数据。
可以看到这里返回的就是我们预期的查询语句,那么他是怎么拼接过来的呢?
我们去看一下parseWhere方法
去看一下buildWhere这个构造select语句的方法
看到这里经由parseWhereIte方法后直接进行拼接
而且经过了parseWhereItem方法
该函数的返回结果存储在 $str 变量中,并被拼接进 SQL 语句。
,我们往下看看这个方法 在这个方法中
where子单元分析
我们可以看到NOT LIKE 可以被我们控制!我们也就控制了mysql的逻辑运算符。利用这一点构造我们的查询语句
最后成功构造我们的sql查询语句,返回了$whereStr
漏洞修复
下面是抄的:
在 5.0.10 之后的版本,官方的修复方法是:在 Request.php 文件的 filterValue 方法中,过滤掉 NOT LIKE 关键字。而在 5.0.10 之前的版本中,这个漏洞是不存在的,但是其代码也没有过滤掉 NOT LIKE 关键字,这是为什么呢?经过调试,发现原来在 5.0.10 之前的版本中,其默认允许的表达式中不存在 not like (注意空格),所以即便攻击者可以通过外部控制该操作符号,也无法完成攻击。(会直接进入下入157行,下图是 5.0.9 版本的代码)相反, 5.0.10 版本其默认允许的表达式中,存在 not like ,因而可以触发漏洞。
攻击总结
七月火师傅的图:
参考