ThinkPHP5漏洞分析之SQL注入(五)
字数 941 2025-08-18 11:38:45
ThinkPHP5 SQL注入漏洞分析(五):orderby方法注入
漏洞概述
本漏洞存在于ThinkPHP框架的Builder类的parseOrder方法中,由于未对用户输入进行充分过滤,直接将数据拼接进SQL语句,导致SQL注入漏洞。影响版本为:5.1.16 <= ThinkPHP5 <= 5.1.22。
环境搭建
-
创建测试项目:
composer create-project --prefer-dist topthink/think=5.1.22 tpdemo -
修改composer.json:
"require": { "php": ">=5.6.0", "topthink/framework": "5.1.22" }然后执行
composer update -
创建控制器文件
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); } } -
配置数据库(
config/database.php)并开启调试模式(config/app.php中设置app_debug和app_trace为true) -
创建数据库:
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报错信息。
漏洞分析
漏洞触发流程
- 用户输入通过
request()->get('orderby')获取 - 输入数据经过
filterValue方法简单过滤,但未对数组键名进行过滤 - 数据直接传入
order方法并存储在$this->options['order']中 - 调用
find方法时,Builder类的select方法生成SQL语句 parseOrder方法处理排序条件时未对用户输入进行充分过滤
关键代码分析
-
输入处理:
- 用户输入直接通过
request()->get()获取 - 虽然经过
filterValue过滤,但对数组键名无过滤
- 用户输入直接通过
-
order方法(Query类):
public function order($field) { if (is_string($field)) { $field = empty($field) ? [] : explode(',', $field); } $this->options['order'] = $field; return $this; }- 直接存储用户输入到
$this->options['order']
- 直接存储用户输入到
-
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注入
防护建议
- 升级到ThinkPHP 5.1.23或更高版本
- 对用户输入的排序字段进行严格过滤
- 使用参数化查询或预处理语句
- 最小化错误信息暴露(关闭app_debug)