thinkphp5框架SQL注入分析:parseData

前言

漏洞位置在存在于 Builder 类的 parseData方法中,将可控参数未经过滤就拼接进了insert语句,造成SQL注入

漏洞影响版本: 5.0.13<=ThinkPHP<=5.0.155.1.0<=ThinkPHP<=5.1.5

环境搭建

下载源码

1
composer create-project --prefer-dist topthink/think=5.0.15 tpdemo

修改composer.json中的require字段,然后执行composer update

1
2
3
4
"require": {
"php": ">=5.4.0",
"topthink/framework": "5.0.15"
}

创建数据库,然后在/application/database.php配置数据库连接信息

1
2
3
4
5
6
create database tpdemo;
use tpdemo;
create table users(
id int primary key auto_increment,
username varchar(50) not null
);

/application/index/controller/Index.php

添加控制器

1
2
3
4
5
6
7
8
9
10
11
12
<?php
namespace app\index\controller;

class Index
{
public function index()
{
$username = request()->get('username/a');
db('users')->insert(['username' => $username]);
return 'Update success';
}
}

/application/config.php

把app_debug改成true

WGLTsJ.png

漏洞复现

payload

1
http://localhost/tpdemo/public/?username[0]=inc&username[1]=updatexml(1,concat(0x7,user(),0x7e),1)&username[2]=1

WGLLIx.png

漏洞分析

/thinkphp/library/think/db/Query.php

$this->builder等于think\db\builder\Mysql,调用的是think\db\builder\Mysql里的insert方法

WGLqd1.png

/thinkphp/library/think/db/Builder.php

来到think\db\builder\Mysql的insert方法,进入parseData

WGL7L9.png

/thinkphp/library/think/db/Builder.php

这里会对我们传入的username数组进行解析。先用switch case判断username[0]的值是exp、inc或者dec,然后再把username[1]也就是注入payload与操作符、username[2]进行拼接。

WGLXi6.png

parseKey函数不会修改输入内容,最后返回的$result

WGLvRO.png

/thinkphp/library/think/db/builder/Mysql.php

parseKey原封不动的返回了我们的payload

WGLjJK.png

/thinkphp/library/think/db/Builder.php

回到think\db\builder\Mysql的insert方法,parseData解析完username数组后,执行str_replace把返回结果拼接到insert语句里

WGOSQe.png

最终返回的结果

WGLxzD.png

/thinkphp/library/think/db/Query.php

然后回到开始的insert,执行sql语句

WGOpsH.png

总结

自己画了张流程图

WGO9Ld.png

再参考下大佬的图

WGLbZR.png

参考链接

https://github.com/Mochazz/ThinkPHP-Vuln


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!