ThinkPHP 5.1.x SQL注入漏洞分析
字数 1307 2025-08-18 11:37:37

ThinkPHP 5.1.x SQL注入漏洞分析与防护指南

漏洞概述

ThinkPHP 5.1.23之前的版本存在SQL注入漏洞(CVE-2018-16385),该漏洞源于程序在处理order by参数时,未正确过滤处理数组的key值。当攻击者能够控制该参数且传递的数据为数组时,可导致SQL注入攻击。

受影响版本

  • ThinkPHP < 5.1.23

漏洞原理分析

漏洞位置

漏洞主要存在于/thinkphp/library/think/db/Builder.php文件的parseOrder()函数中。

漏洞触发流程

  1. 参数处理流程

    • 当传入的$order参数为数组时,foreach函数将其分为key和value形式处理
    • $val为数组时,会进入parseOrderField()函数
  2. 关键函数分析

    • parseKey()函数对传入的$key进行多重判断:
      1. is_numeric判断是否为数字
      2. 判断$key是否属于Expression
      3. strpos($key,false ===strpos($key,
      4. key && ($strict ||!preg_match(s]/', $key))
    • 攻击者的SQL注入语句会满足第4个条件,导致$key被加上反引号后直接返回
  3. 拼接过程

    • 处理后的$key$valfield字符串拼接
    • 最终与order by形成完整的SQL查询语句
    • 系统调用query()函数执行查询,触发漏洞

利用关键点

  1. field()函数要求

    • 必须指定≥2个字段才能正常运行
    • 当表中只有一个字段时,可随意指定数字或字符串参数
    • 第一个参数必须是正确的表字段(会被反引号包裹)
    • 第二个参数可以是任意数字或字符串
  2. 利用条件

    • 传入的$order必须是数组
    • $val也必须是数组
    • 至少知道数据库表中的一个字段名称
    • 能够闭合反引号

漏洞复现

环境搭建

  1. 使用Composer安装ThinkPHP 5.1.1:

    composer create-project topthink/think=5.1.1 tp5.1 --prefer-dist
    
  2. 创建Demo文件Test.php,放置在/tp5.1/application/index/controller/目录下

  3. 创建匹配的数据库表(如user表,至少包含id字段)

攻击Payload

http://127.0.0.1/tp5.1/public/index/test/index?order[id`,111)|updatexml(1,concat(0x3a,user()),1)%23][]=1

http://127.0.0.1/tp5.1/public/index/test/index?order[id`,'aaa')|updatexml(1,concat(0x3a,user()),1)%23][]=1

漏洞修复方案

官方修复

升级到ThinkPHP 5.1.24或更高版本

手动修复

参考官方补丁进行代码修改:
https://github.com/top-think/framework/commit/f0f9fc71b8b3716bd2abdf9518bcdf1897bb776

防护建议

  1. 对所有用户输入进行严格的过滤和验证
  2. 使用参数化查询或预处理语句
  3. 遵循最小权限原则,限制数据库用户权限
  4. 在生产环境中关闭错误信息显示
  5. 定期更新框架和组件到最新版本

总结

该SQL注入漏洞源于ThinkPHP对order by参数中数组key值处理不当,攻击者通过精心构造的数组参数可绕过过滤机制,实现SQL注入攻击。开发人员应及时更新框架版本,并对所有用户输入保持高度警惕,实施严格的安全验证措施。

ThinkPHP 5.1.x SQL注入漏洞分析与防护指南 漏洞概述 ThinkPHP 5.1.23之前的版本存在SQL注入漏洞(CVE-2018-16385),该漏洞源于程序在处理 order by 参数时,未正确过滤处理数组的key值。当攻击者能够控制该参数且传递的数据为数组时,可导致SQL注入攻击。 受影响版本 ThinkPHP < 5.1.23 漏洞原理分析 漏洞位置 漏洞主要存在于 /thinkphp/library/think/db/Builder.php 文件的 parseOrder() 函数中。 漏洞触发流程 参数处理流程 : 当传入的 $order 参数为数组时, foreach 函数将其分为key和value形式处理 当 $val 为数组时,会进入 parseOrderField() 函数 关键函数分析 : parseKey() 函数对传入的 $key 进行多重判断: is_numeric 判断是否为数字 判断 $key 是否属于 Expression 类 strpos($key,false ===strpos($key, key && ($strict ||!preg_match(s]/', $key)) 攻击者的SQL注入语句会满足第4个条件,导致 $key 被加上反引号后直接返回 拼接过程 : 处理后的 $key 与 $val 及 field 字符串拼接 最终与 order by 形成完整的SQL查询语句 系统调用 query() 函数执行查询,触发漏洞 利用关键点 field()函数要求 : 必须指定≥2个字段才能正常运行 当表中只有一个字段时,可随意指定数字或字符串参数 第一个参数必须是正确的表字段(会被反引号包裹) 第二个参数可以是任意数字或字符串 利用条件 : 传入的 $order 必须是数组 $val 也必须是数组 至少知道数据库表中的一个字段名称 能够闭合反引号 漏洞复现 环境搭建 使用Composer安装ThinkPHP 5.1.1: 创建Demo文件 Test.php ,放置在 /tp5.1/application/index/controller/ 目录下 创建匹配的数据库表(如 user 表,至少包含 id 字段) 攻击Payload 或 漏洞修复方案 官方修复 升级到ThinkPHP 5.1.24或更高版本 手动修复 参考官方补丁进行代码修改: https://github.com/top-think/framework/commit/f0f9fc71b8b3716bd2abdf9518bcdf1897bb776 防护建议 对所有用户输入进行严格的过滤和验证 使用参数化查询或预处理语句 遵循最小权限原则,限制数据库用户权限 在生产环境中关闭错误信息显示 定期更新框架和组件到最新版本 总结 该SQL注入漏洞源于ThinkPHP对 order by 参数中数组key值处理不当,攻击者通过精心构造的数组参数可绕过过滤机制,实现SQL注入攻击。开发人员应及时更新框架版本,并对所有用户输入保持高度警惕,实施严格的安全验证措施。