今天你首次真正地“攻击”一个 Web 应用,学会如何通过简单的符号和逻辑判断来发现 SQL 注入点,并精准确定闭合方式。这是手工注入的起手式,也是区分脚本小子与安全研究者的关键分水岭。
第五周·周二:数字型与字符型注入检测,闭合方式
🎯 今日学习目标(达成效果)
- 能准确区分数字型注入与字符型注入的原理:参数是否被引号包裹,决定了注入语法;
- 能通过简单的输入测试(添加单引号、双引号、运算符号)判断目标参数是否存在 SQL 注入漏洞;
- 能识别数据库错误信息,并从中推断出服务器使用的数据库类型以及大致的 SQL 语句结构;
- 能熟练使用注释符(
--、#) 截断原始语句的后续部分,构造属于自己的可控查询; - 能在 sqli-labs Less-1 中独立找出闭合方式为单引号闭合,并成功使用
' OR '1'='1使 SQL 语句逻辑永真; - 能写出完整的注入 payload,解释每一步符号的作用(闭合、逻辑操作、注释)。
📘 一、SQL 注入的本质:打破原有语句结构
SQL 注入漏洞发生在用户输入被拼接到 SQL 查询语句中,且未作任何过滤或参数化。正常登录查询可能是:
SELECT*FROMusersWHEREusername='admin'ANDpassword='pass123';如果用户输入的用户名是admin' --,拼接后就变成:
SELECT*FROMusersWHEREusername='admin'-- ' AND password='...';- 第一个单引号闭合了原本的引号;
--是 SQL 单行注释,后面的所有语句都被数据库忽略;- 最终执行的逻辑变为:
username='admin'成立就返回用户,密码验证被完全绕过。
这就是注入的核心:用特殊字符打破代码与数据的边界。今天我们将系统学习如何寻找这个“边界”,并确定需要用什么符号来闭合它。
📘 二、数字型注入 vs 字符型注入
根据参数在 SQL 语句中是否被引号包围,注入分为两类,它们的检测方法截然不同。
1. 数字型(Numeric)
- SQL 中类似:
SELECT * FROM news WHERE id=123 - 参数
123没有引号,直接是数字。 - 检测方法:
- 算数运算:输入
1+1,如果页面返回 id 为 2 的内容,说明运算被执行(存在注入);输入1-1如果返回 id=0 的内容,也证实了注入。 - 逻辑判断:
and 1=1页面正常,and 1=2页面异常或内容消失,说明注入存在(因为id=123 and 1=2永远不成立,查询无结果)。
- 算数运算:输入
- 闭合需求:数字型不需要闭合引号,可直接追加逻辑,但若需要 UNION 查询,可能需要注释掉后续排序等。
2. 字符型(String)
- SQL:
SELECT * FROM users WHERE username='admin' - 参数
admin被单引号(或双引号)包围。 - 检测方法:
- 添加单引号
':输入admin',SQL 变成... username='admin'',多出一个引号导致语法错误。如果页面显示数据库错误或白屏,说明输入未经处理直接进入 SQL,极可能存在注入。 - 永真/永假测试:如果能确定闭合符号,尝试
' OR '1'='1(需要正确闭合)。比如对于单引号闭合,' OR '1'='1 --会使得 WHERE 条件永真,返回所有数据。
- 添加单引号
- 闭合方式:必须知道前面使用的是什么引号,以及是否有括号。常见的闭合组合:
'(单引号)"(双引号)')(单引号+括号)")(双引号+括号)'))等嵌套形式
如何确认闭合?
通过报错信息或逐步尝试。典型方法:输入\(反斜杠)有时可以转义后面的引号而暴露原始语句(在某些编码下),更通用的方法是使用注释符和永真条件不断测试,直到页面正常且逻辑成立。
📘 三、注释符:截断语句的利器
确定闭合后,我们需要把原始语句后面多余的部分(如' AND password='...')注释掉,才能自由控制查询。不同数据库的注释符有差异,MySQL 支持以下三种:
| 注释符 | 说明 | 示例 |
|---|---|---|
--(两个短横+空格) | 单行注释,注意必须后面有空格(或控制符),在 URL 中常写作--+,+会被解码为空格 | ' OR '1'='1 -- |
# | 单行注释,不需要空格,但 URL 中#通常用于锚点,不会被发送到服务器,因此常使用%23(URL编码的#) | ' OR '1'='1 %23 |
/*...*/ | 多行注释,用于绕过某些过滤或注释掉一段代码 | ' UNION SELECT 1,2,3 /* |
今天重点使用--+或%23。
✍️ 四、动手实践:搭建 sqli-labs 靶场并对 Less-1 进行注入检测
Sqli-labs 是经典的 SQL 注入练习平台,包含了各种闭合和过滤的关卡。我们今天先攻克 Less-1。
1. 安装 sqli-labs 环境(使用 Docker 最简单)
如果你已有 PHP 环境(如 Apache + MySQL),可以手动部署。更推荐使用 Docker:
dockerpull acgpiano/sqli-labs# 或 vulhub 中的 sqli-labsdockerrun-d-p80:80 acgpiano/sqli-labs或者本地搭建:将 sqli-labs 源码放到 Web 目录,设置好数据库连接。为了实验方便,可以临时使用公开在线靶场(但注意稳定性),例如http://sqli-labs:8080/(假设),务必确认是自己搭建的。
假设服务运行在http://192.168.1.100:80(本地虚拟机或本机),我们开始。
2. Less-1 页面分析
访问http://192.168.1.100/Less-1/,你会看到一个提示Please input the ID as parameter with numeric value。正常访问?id=1会显示用户信息Your Login name:Dumb, Your Password:Dumb等。
此时后台 SQL 类似:
SELECT*FROMusersWHEREid='1'LIMIT0,1(注意 id 是被单引号包围的,这是一个字符型注入。)
3. 检测注入点
数字型测试:
?id=1 and 1=2,页面无变化或仍正常显示?因为'1'被视为字符串,and 1=2是在字符串外部,可能没有作用。数字型测试不能直接判断。字符型测试:加单引号
?id=1'。页面返回错误:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''1'' LIMIT 0,1' at line 1错误信息中可以看到
'1'',说明多出一个引号。这证实了注入点存在,且是单引号闭合。永真条件测试:尝试
?id=1' and '1'='1。
原始语句变为:WHERE id='1' and '1'='1' LIMIT 0,1
这是合法的,页面正常显示 id=1 的数据。再尝试?id=1' and '1'='2,页面无显示(因为条件为假)。这进一步确认注入有效,且闭合方式就是'。使用注释符关闭多余部分:
?id=1' --+--+中--注释掉后面的LIMIT 0,1,页面正常。
至此,闭合方式确定为单引号'。
4. 经典永真注入
?id=1' OR '1'='1' --+
SQL 变成:
SELECT*FROMusersWHEREid='1'OR'1'='1'-- ' LIMIT 0,1OR '1'='1'使得整个 WHERE 条件永真,返回所有用户。实际页面会显示多组用户名密码(由于 PHP 代码可能只取一行,Less-1 默认显示第一行,但仍可证明注入成功)。
你还可以尝试?id=-1' OR '1'='1' --+以查看其他数据。
📝 五、课后测试题与解析
测试题:在 sqli-labs Less-1 中找出闭合方式。请描述你的测试步骤以及最终确定的闭合符号。
参考答案与步骤:
- 访问
http://靶机/Less-1/?id=1,页面正常显示用户信息; - 添加单引号测试:
?id=1',页面返回数据库语法错误,提示'1'' LIMIT 0,1。说明参数被单引号包围,且单引号未过滤; - 尝试双引号测试:
?id=1",可能无报错或不同,排除双引号闭合(Less-1 仅单引号); - 使用
?id=1' and '1'='1页面正常,?id=1' and '1'='2页面异常,证明注入逻辑生效且闭合方式为单引号; - 使用注释符闭合:
?id=1' --+正常,最终确定闭合方式为单引号'。
核心 payload:' OR '1'='1' --+
分解:
- 第一个
'用于闭合前端的引号; OR '1'='1'添加永真条件,且末尾的'1'实际是用来与后面的原单引号配对,让语法正确(虽然被注释掉了,但为了严谨);--+注释掉后续的' LIMIT 0,1等,避免干扰。
✅ 今日学习效果自检清单
- 我能区分数字型注入与字符型注入,并分别说出各自的检测方法
- 我亲手在 sqli-labs Less-1 中通过加单引号触发了数据库错误
- 我使用
' and '1'='1和' and '1'='2确认了注入存在 - 我知道了至少两种注释符的用法(
--+和%23) - 我成功通过
' OR '1'='1' --+改变了查询逻辑 - 我明白了闭合的本质:让用户输入跳出数据区域,进入代码区域
⚠️ 阶段避坑重点
- 注释符空格不可丢:
--后面必须有空格或#,URL 编码中常使用--+(+ 解码为空格)或--%20。如果忘记空格,注释无效,可能导致语法错误。 - 区分大小写和数据库特性:MySQL 中
--可行,而#注释在 URL 中需编码为%23。Access 不支持注释符,但通常有限制。 - 不要只依赖报错:有的站点关闭了错误显示,这时使用永真/永假测试(盲注),今天先掌握有报错的容易情况。
- 测试时记录每一种尝试:闭合方式可能多种,形成表格记录,养成良好的手工渗透习惯。
明天我们将深入学习联合查询注入(UNION SELECT)手工步骤,利用今天找到的闭合方式,在 Less-1 中逐步获取数据库名、表名和字段名。请确保你的 sqli-labs 环境正常运行,明天将直接进入实战数据提取。