thinkphp5.0 SQL注入详细分析
字数 1183 2025-08-18 11:36:00

ThinkPHP 5.0 SQL注入漏洞详细分析

漏洞概述

ThinkPHP 5.0.15版本中存在一个SQL注入漏洞,攻击者可以通过构造特殊的数组参数,将恶意SQL语句注入到数据库查询中。该漏洞主要源于框架对数组参数的处理不当,特别是在使用incdec操作时未对用户输入进行充分过滤。

漏洞基础

关键函数

  • list() - 把数组中的值赋给一组变量
  • array_walk_recursive() - 对数组中的每个成员递归地应用用户函数
  • is_scalar() - 检测变量是否是一个标量

环境搭建

  1. 使用Composer回退到5.0.15版本:
"require": {
    "php": ">=5.4.0",
    "topthink/think-installer": "5.0.15"
}
  1. 创建测试控制器:
namespace app\index\controller;

class Index {
    public function index() {
        $username = request()->get('username/a');
        db('users')->insert(['username' => $username]);
        return 'Update success';
    }
}
  1. 数据库配置:
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()方法关键流程:

  1. 解析参数名和类型(username/a被拆分为usernamea
  2. 对数据进行递归过滤(array_walk_recursive
  3. 强制类型转换(typeCast将数据转为数组)

2. 数据库操作阶段

进入db('users')->insert(['username' => $username])

2.1 表信息获取

  • 通过getTableInfo()获取表结构
  • 执行SHOW COLUMNS FROM users查询字段信息
  • 确定字段绑定类型(getFieldBindType

2.2 SQL构建

parseData()方法中处理数据:

  • 当参数是数组且第一个元素为incdec时,会直接拼接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已被直接拼接,导致注入成功

漏洞原理总结

  1. 参数处理不当:框架允许通过数组形式接收参数,且对数组元素的过滤不充分
  2. SQL拼接漏洞:当使用incdec操作时,直接将用户输入拼接到SQL语句中
  3. 缺乏预处理:虽然使用了PDO,但恶意SQL在预处理前已被拼接

修复建议

  1. 升级到最新版本的ThinkPHP
  2. 对用户输入进行严格过滤,特别是数组参数
  3. 避免直接将用户输入拼接到SQL语句中

参考链接

该漏洞展示了框架设计中对用户输入处理的重要性,特别是在ORM操作中应严格避免直接拼接用户输入到SQL语句中。

ThinkPHP 5.0 SQL注入漏洞详细分析 漏洞概述 ThinkPHP 5.0.15版本中存在一个SQL注入漏洞,攻击者可以通过构造特殊的数组参数,将恶意SQL语句注入到数据库查询中。该漏洞主要源于框架对数组参数的处理不当,特别是在使用 inc 或 dec 操作时未对用户输入进行充分过滤。 漏洞基础 关键函数 list() - 把数组中的值赋给一组变量 array_walk_recursive() - 对数组中的每个成员递归地应用用户函数 is_scalar() - 检测变量是否是一个标量 环境搭建 使用Composer回退到5.0.15版本: 创建测试控制器: 数据库配置: 漏洞复现 攻击URL: 漏洞详细分析 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语句中 参考链接 ThinkPHP 5漏洞分析之SQL注入(一) 该漏洞展示了框架设计中对用户输入处理的重要性,特别是在ORM操作中应严格避免直接拼接用户输入到SQL语句中。