thinkphp5.0 SQL注入详细分析
字数 1183 2025-08-18 11:36:00
ThinkPHP 5.0 SQL注入漏洞详细分析
漏洞概述
ThinkPHP 5.0.15版本中存在一个SQL注入漏洞,攻击者可以通过构造特殊的数组参数,将恶意SQL语句注入到数据库查询中。该漏洞主要源于框架对数组参数的处理不当,特别是在使用inc或dec操作时未对用户输入进行充分过滤。
漏洞基础
关键函数
list()- 把数组中的值赋给一组变量array_walk_recursive()- 对数组中的每个成员递归地应用用户函数is_scalar()- 检测变量是否是一个标量
环境搭建
- 使用Composer回退到5.0.15版本:
"require": {
"php": ">=5.4.0",
"topthink/think-installer": "5.0.15"
}
- 创建测试控制器:
namespace app\index\controller;
class Index {
public function index() {
$username = request()->get('username/a');
db('users')->insert(['username' => $username]);
return 'Update success';
}
}
- 数据库配置:
create database tpdemo;
use tpdemo;
create table users(
id int primary key auto_increment,
username varchar(50) not null
);
漏洞复现
攻击URL:
http://127.0.0.1/tp5.0.22/public/index.php/index/Index/index?username[0]=dec&username[1]=updatexml(1,concat(0x7e,user(),0x7e),1)&username[2]=1
漏洞详细分析
1. 参数获取阶段
请求进入request()->get('username/a')方法:
/a表示强制将参数转换为数组- 框架通过
input()方法处理输入参数
input()方法关键流程:
- 解析参数名和类型(
username/a被拆分为username和a) - 对数据进行递归过滤(
array_walk_recursive) - 强制类型转换(
typeCast将数据转为数组)
2. 数据库操作阶段
进入db('users')->insert(['username' => $username]):
2.1 表信息获取
- 通过
getTableInfo()获取表结构 - 执行
SHOW COLUMNS FROM users查询字段信息 - 确定字段绑定类型(
getFieldBindType)
2.2 SQL构建
在parseData()方法中处理数据:
- 当参数是数组且第一个元素为
inc或dec时,会直接拼接SQL - 攻击payload:
username[0]=dec&username[1]=恶意SQL&username[2]=1 - 最终拼接为:
`username` = updatexml(1,concat(0x7e,user(),0x7e),1)-1
2.3 SQL执行
- 使用PDO预处理执行生成的SQL语句
- 由于恶意SQL已被直接拼接,导致注入成功
漏洞原理总结
- 参数处理不当:框架允许通过数组形式接收参数,且对数组元素的过滤不充分
- SQL拼接漏洞:当使用
inc或dec操作时,直接将用户输入拼接到SQL语句中 - 缺乏预处理:虽然使用了PDO,但恶意SQL在预处理前已被拼接
修复建议
- 升级到最新版本的ThinkPHP
- 对用户输入进行严格过滤,特别是数组参数
- 避免直接将用户输入拼接到SQL语句中
参考链接
该漏洞展示了框架设计中对用户输入处理的重要性,特别是在ORM操作中应严格避免直接拼接用户输入到SQL语句中。