ThinkPHP5漏洞分析之SQL注入(三)
字数 1239 2025-08-18 11:38:45

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

漏洞概述

本漏洞存在于ThinkPHP5框架的Mysql类中,具体问题出在parseWhereItem方法。由于程序未对用户输入数据进行充分过滤,导致恶意数据被直接拼接进SQL语句,形成SQL注入漏洞。该漏洞影响ThinkPHP5全版本。

漏洞环境搭建

环境准备步骤

  1. 创建测试项目:

    composer create-project --prefer-dist topthink/think=5.0.10 tpdemo
    
  2. 修改composer.json文件:

    "require": {
        "php": ">=5.4.0",
        "topthink/framework": "5.0.10"
    }
    
  3. 执行更新:

    composer update
    
  4. 创建控制器文件application/index/controller/Index.php

    <?php
    namespace app\index\controller;
    
    class Index
    {
        public function index()
        {
            $username = request()->get('username');
            $result = db('users')->where('username','exp',$username)->select();
            return 'select success';
        }
    }
    
  5. 配置数据库(config/database.php)并开启调试模式(config/app.php中设置app_debugapp_trace为true)

  6. 创建测试数据库:

    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触发漏洞:

http://localhost:8000/index/index/index?username=) union select updatexml(1,concat(0x7,user(),0x7e),1)#

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

漏洞分析

漏洞触发流程

  1. 用户输入通过Request类的get方法获取,经过input方法处理(默认过滤不充分)
  2. 数据传递到Query类的where方法
  3. where方法调用parseWhereExp分析查询表达式
  4. 程序继续调用select方法构建SQL语句
  5. $this->builder\think\db\builder\Mysql类实例,继承自Builder类
  6. Builder类的select方法填充SQL模板,其中WHERE部分包含用户输入
  7. buildWhere函数处理WHERE条件
  8. parseWhereItem函数处理WHERE子单元,当操作符为'exp'时直接拼接用户输入

关键代码分析

漏洞核心在于parseWhereItem方法对'exp'操作符的处理:

// thinkphp/library/think/db/Builder.php

protected function parseWhereItem($field, $val, $rule = '', $options = [], $binds = [], $bindName = null)
{
    // ...
    case 'exp':
        // 表达式查询
        $whereStr .= '( ' . $field . ' ' . $val . ' )';
    break;
    // ...
}

当使用where('username','exp',$username)时,$val(即$username)被直接拼接到SQL语句中,没有任何过滤处理。

漏洞利用条件

  1. 使用where方法且第二个参数为'exp'
  2. 用户输入直接作为第三个参数传入
  3. 应用程序未对用户输入进行额外过滤

防御措施

虽然官方认为这是提供的功能而非漏洞,但开发者应采取以下防护措施:

  1. 避免直接使用'exp'操作符处理用户输入
  2. 对用户输入进行严格过滤和转义
  3. 使用参数化查询或预处理语句
  4. 最小权限原则,数据库用户只赋予必要权限
  5. 生产环境关闭调试模式(app_debug和app_trace设为false)

漏洞修复方案

官方未提供专门修复,但开发者可以:

  1. 重写parseWhereItem方法,增加对'exp'操作符的输入验证
  2. 在业务层对输入数据进行严格过滤
  3. 使用框架提供的安全查询方法替代原始'exp'表达式

攻击流程图

用户恶意输入 → Request::get() → Query::where() → parseWhereExp()
              ↓
Builder::select() → buildWhere() → parseWhereItem('exp')
              ↓
直接拼接进SQL → SQL注入执行

总结

该漏洞展示了框架设计时安全考虑不足可能导致的问题。虽然官方将其视为功能,但开发者应当理解其风险并采取适当防护措施。关键在于永远不要信任用户输入,所有数据在进入SQL查询前都应进行适当验证和过滤。

ThinkPHP5 SQL注入漏洞分析(select方法注入) 漏洞概述 本漏洞存在于ThinkPHP5框架的Mysql类中,具体问题出在 parseWhereItem 方法。由于程序未对用户输入数据进行充分过滤,导致恶意数据被直接拼接进SQL语句,形成SQL注入漏洞。该漏洞影响ThinkPHP5全版本。 漏洞环境搭建 环境准备步骤 创建测试项目: 修改 composer.json 文件: 执行更新: 创建控制器文件 application/index/controller/Index.php : 配置数据库( config/database.php )并开启调试模式( config/app.php 中设置 app_debug 和 app_trace 为true) 创建测试数据库: 漏洞复现 访问以下URL触发漏洞: 注意:需要开启 app_debug 才能看到SQL报错信息。 漏洞分析 漏洞触发流程 用户输入通过Request类的get方法获取,经过input方法处理(默认过滤不充分) 数据传递到Query类的where方法 where方法调用parseWhereExp分析查询表达式 程序继续调用select方法构建SQL语句 $this->builder 为 \think\db\builder\Mysql 类实例,继承自Builder类 Builder类的select方法填充SQL模板,其中WHERE部分包含用户输入 buildWhere函数处理WHERE条件 parseWhereItem函数处理WHERE子单元,当操作符为'exp'时直接拼接用户输入 关键代码分析 漏洞核心在于 parseWhereItem 方法对'exp'操作符的处理: 当使用 where('username','exp',$username) 时, $val (即 $username )被直接拼接到SQL语句中,没有任何过滤处理。 漏洞利用条件 使用where方法且第二个参数为'exp' 用户输入直接作为第三个参数传入 应用程序未对用户输入进行额外过滤 防御措施 虽然官方认为这是提供的功能而非漏洞,但开发者应采取以下防护措施: 避免直接使用'exp'操作符处理用户输入 对用户输入进行严格过滤和转义 使用参数化查询或预处理语句 最小权限原则,数据库用户只赋予必要权限 生产环境关闭调试模式(app_ debug和app_ trace设为false) 漏洞修复方案 官方未提供专门修复,但开发者可以: 重写parseWhereItem方法,增加对'exp'操作符的输入验证 在业务层对输入数据进行严格过滤 使用框架提供的安全查询方法替代原始'exp'表达式 攻击流程图 总结 该漏洞展示了框架设计时安全考虑不足可能导致的问题。虽然官方将其视为功能,但开发者应当理解其风险并采取适当防护措施。关键在于永远不要信任用户输入,所有数据在进入SQL查询前都应进行适当验证和过滤。