ThinkPHP5漏洞分析之SQL注入(一)
字数 1093 2025-08-18 11:38:41

ThinkPHP5 SQL注入漏洞分析(insert方法注入)

漏洞概述

本漏洞存在于ThinkPHP框架的Builder类的parseData方法中,由于程序未对用户输入数据进行充分过滤,导致恶意数据被直接拼接进SQL语句,造成SQL注入漏洞。

影响版本

  • 5.0.13 ≤ ThinkPHP ≤ 5.0.15
  • 5.1.0 ≤ ThinkPHP ≤ 5.1.5

环境搭建

  1. 创建测试项目:
composer create-project --prefer-dist topthink/think=5.0.15 tpdemo
  1. 修改composer.json:
"require": {
    "php": ">=5.4.0",
    "topthink/framework": "5.0.15"
}
  1. 执行更新:
composer update
  1. 创建控制器文件application/index/controller/Index.php:
<?php
namespace app\index\controller;

class Index
{
    public function index()
    {
        $username = request()->get('username/a');
        db('users')->insert(['username' => $username]);
        return 'Update success';
    }
}
  1. 配置数据库(application/database.php)并开启调试模式(application/config.php中设置app_debug和app_trace为true)

  2. 创建数据库:

create database tpdemo;
use tpdemo;
create table users(
    id int primary key auto_increment,
    username varchar(50) not null
);

漏洞复现

访问以下URL触发SQL注入:

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

注意:需要开启app_debug才能看到SQL报错信息。

漏洞分析

漏洞触发流程

  1. 用户提交的恶意参数通过request()->get('username/a')获取,/a表示获取数组类型参数
  2. 数据传入db('users')->insert()方法
  3. 最终调用Builder类的parseData方法处理数据

关键代码分析

漏洞核心在于parseData方法对用户数据的处理不充分。攻击者可以构造特殊数组参数:

$username = [
    0 => 'inc',       // 操作类型
    1 => '恶意SQL',   // 操作值
    2 => '1'          // 条件值
];

在Builder类的parseData方法中,当操作类型为'inc'时,代码会直接将用户提供的数据拼接到SQL语句中,没有进行充分的过滤。

三种可能触发注入的情况

  1. inc操作$val[0] = 'inc'

    $result[$key] = $key . '+' . $val[1];
    
  2. dec操作$val[0] = 'dec'

    $result[$key] = $key . '-' . $val[1];
    
  3. exp操作$val[0] = 'exp'

    $result[$key] = $key . ' ' . $val[1];
    

虽然exp操作理论上也存在注入风险,但在实际中,ThinkPHP的内置过滤方法会将'exp'替换为'exp空格',从而阻止了注入。

漏洞修复

官方在5.0.16版本中修复了此漏洞,主要修改了Builder.php文件,对inc和dec操作进行了安全处理。

修复措施包括:

  1. 对inc/dec操作的值进行类型检查,确保是数字
  2. 对用户输入进行更严格的过滤

攻击流程图

用户提交恶意参数(username数组)
    ↓
框架接收参数(request()->get('username/a'))
    ↓
调用db('users')->insert()
    ↓
Builder::insert()方法处理
    ↓
调用parseData方法解析数据
    ↓
恶意数据直接拼接到SQL语句
    ↓
执行SQL,触发注入

防护建议

  1. 及时升级到安全版本
  2. 对用户输入进行严格过滤和类型检查
  3. 避免直接将用户输入拼接到SQL语句中
  4. 生产环境关闭调试模式(app_debug)

总结

该漏洞源于框架对数组参数处理不当,特别是在使用inc/dec操作时未充分过滤用户输入。开发人员在使用ORM框架时,仍需保持安全意识,不能完全依赖框架的防护机制。

ThinkPHP5 SQL注入漏洞分析(insert方法注入) 漏洞概述 本漏洞存在于ThinkPHP框架的Builder类的parseData方法中,由于程序未对用户输入数据进行充分过滤,导致恶意数据被直接拼接进SQL语句,造成SQL注入漏洞。 影响版本 : 5.0.13 ≤ ThinkPHP ≤ 5.0.15 5.1.0 ≤ ThinkPHP ≤ 5.1.5 环境搭建 创建测试项目: 修改composer.json: 执行更新: 创建控制器文件application/index/controller/Index.php: 配置数据库(application/database.php)并开启调试模式(application/config.php中设置app_ debug和app_ trace为true) 创建数据库: 漏洞复现 访问以下URL触发SQL注入: 注意 :需要开启app_ debug才能看到SQL报错信息。 漏洞分析 漏洞触发流程 用户提交的恶意参数通过 request()->get('username/a') 获取, /a 表示获取数组类型参数 数据传入 db('users')->insert() 方法 最终调用Builder类的parseData方法处理数据 关键代码分析 漏洞核心在于 parseData 方法对用户数据的处理不充分。攻击者可以构造特殊数组参数: 在Builder类的parseData方法中,当操作类型为'inc'时,代码会直接将用户提供的数据拼接到SQL语句中,没有进行充分的过滤。 三种可能触发注入的情况 inc操作 : $val[0] = 'inc' dec操作 : $val[0] = 'dec' exp操作 : $val[0] = 'exp' 虽然exp操作理论上也存在注入风险,但在实际中,ThinkPHP的内置过滤方法会将'exp'替换为'exp空格',从而阻止了注入。 漏洞修复 官方在5.0.16版本中修复了此漏洞,主要修改了Builder.php文件,对inc和dec操作进行了安全处理。 修复措施包括: 对inc/dec操作的值进行类型检查,确保是数字 对用户输入进行更严格的过滤 攻击流程图 防护建议 及时升级到安全版本 对用户输入进行严格过滤和类型检查 避免直接将用户输入拼接到SQL语句中 生产环境关闭调试模式(app_ debug) 总结 该漏洞源于框架对数组参数处理不当,特别是在使用inc/dec操作时未充分过滤用户输入。开发人员在使用ORM框架时,仍需保持安全意识,不能完全依赖框架的防护机制。