测试 SQL 注入是字符型还是数字型的方法

在 SQL 注入测试中,首先需要判断注入点属于数字型还是字符型(字符串型),因为两者的注入语法和闭合方式完全不同。以下是几种常用且有效的测试方法。

方法一:使用单引号(最简单直接)

向参数提交一个单引号 ‘,观察页面返回。

字符型:SQL 语句中会使用单引号包裹用户输入,例如 WHERE name = ‘$input’。输入 ’ 后,SQL 变成 WHERE name = ‘’’,导致引号未闭合,通常会触发数据库错误(如 You have an error in your SQL syntax)或页面异常显示。

数字型:SQL 中直接拼接数字,例如 WHERE id = $input。输入 ’ 后,SQL 变成 WHERE id = ‘,因为 ’ 不是有效数字,数据库可能会报类型转换错误,或者由于参数被强制转换(如 MySQL 中 ‘1’ 会自动转为 1),但通常不会出现明显的语法错误,可能返回正常或空结果。

如果单引号导致页面报错或出现数据库错误信息,大概率是字符型。如果页面无变化或只返回空结果,可能是数字型(但需进一步确认)。

方法二:使用逻辑运算(and 1=1 / and 1=2)

分别提交两个请求:参数=原始值 and 1=1 和 参数=原始值 and 1=2。

数字型:SQL 直接拼接,例如 id = 1 and 1=1 为真,id = 1 and 1=2 为假。两次返回结果应不同(前者有数据,后者无数据或页面不同)。

字符型:直接拼接会导致语法错误(因为缺少引号闭合)。需先闭合引号,例如 name = ‘admin’ and ‘1’=‘1’。因此测试时使用 参数=原始值’ and ‘1’=‘1 和 参数=原始值’ and ‘1’=‘2。

测试步骤:

先判断是否可以使用 and 1=1 和 and 1=2 产生差异。

如果直接加入 and 1=1 页面正常,and 1=2 页面异常 → 数字型。

如果直接加入报错,尝试在参数后加单引号再跟 and ‘1’=‘1,如果成功且结果差异 → 字符型。

方法三:使用加法/减法运算(适用于数字型)

提交 参数=原始值+1 或 参数=原始值-1。

数字型:SQL 会计算算术表达式,例如 id = 1+1 等价于 id = 2,返回 id=2 的结果。如果页面结果与原始值(如 id=1)不同,说明是数字型。

字符型:‘admin’+1 在大多数数据库中会报错或转换为数字(如 MySQL 中 ‘admin’ 转为 0,‘admin’+1 = 1),但这可能产生不可预测结果。但通常字符型不会直接支持算术运算,容易报错。

注意:该方法适用于支持隐式类型转换的数据库(如 MySQL),但不如前两种可靠。

方法四:利用注释符号测试闭合方式

提交 参数=原始值’ – (注意 – 后要有空格) 或 参数=原始值’ #(MySQL)。如果页面返回正常,说明字符型且单引号被正确闭合注释掉。如果报错,尝试双引号 " 或括号等。

数字型:不需要注释,直接加 and 1=1 即可工作。

综合判断流程

先提交单引号 ‘,观察页面是否报错 → 报错则字符型嫌疑大。

提交 and 1=1 和 and 1=2:

如果两者返回不同结果 → 数字型。

如果报错,则尝试提交 ’ and ‘1’=‘1 和 ’ and ‘1’=‘2:

如果返回不同结果 → 字符型(单引号闭合)。

如果仍报错,尝试双引号 " and “1”=“1 → 字符型(双引号闭合)。

提交 参数=原始值+1,如果页面结果与原始值不同 → 数字型。

实际测试 Payload 示例

假设原始 URL 为 http://example.com/page?id=1

测试 Payload 预期现象(数字型) 预期现象(字符型)

?id=1’ 可能报类型错误或正常返回空 数据库语法错误,页面报错

?id=1 and 1=1 正常返回数据 可能报错(缺少引号)

?id=1 and 1=2 无数据或不同页面 可能报错

?id=1’ and ‘1’=‘1 报错(因为数字型不应有引号) 正常返回数据(闭合成功)

?id=1’ and ‘1’=‘2 报错 无数据(假条件)

?id=1+1 返回 id=2 的数据 报错或返回其他(如 ‘1’+1 可能变为 2 但罕见)

最可靠的方法组合:单引号 + 逻辑运算对比。只要掌握上述三种主要探测方式,就能快速区分数字型与字符型注入点。判断清楚后,即可根据类型构造具体的注入语句(如 UNION 查询、报错注入等)。


如何判断 SQL 注入中过滤掉了哪些内容

在 SQL 注入测试中,确定了注入点类型(数字型/字符型)之后,下一步往往是探测 Web 应用或 WAF 对输入实施了哪些过滤。这包括:过滤了哪些特殊字符、哪些 SQL 关键字、是否进行了转义、是否使用了黑名单或白名单等。下面给出系统性的判断方法。

一、基础探测思路

过滤的本质是破坏或阻止你构造有效的 SQL 注入 payload。判断过滤内容的核心方法是:试探性地输入可能被用于注入的字符/关键字,观察返回结果(报错信息、响应内容、页面行为)与正常输入的差异。通过差异推断哪些字符被删除、替换、转义或直接拦截。

二、具体测试步骤与判断依据

1. 测试特殊字符是否被过滤/转义

这些字符常用于闭合语句或构造注入:’ " ` ) ( ; % \ 等。

方法:依次输入这些字符,观察:

直接消失:例如输入 1’,回显变成 1(引号被删除) → 可能使用了黑名单删除。

被转义:输入 1’,回显 1' 或数据库报错 ’’’’ 转义后多一个引号 → 可能开启了 addslashes() 或 magic_quotes_gpc(已废弃)或使用了转义函数。

触发 WAF 阻断:返回 403、跳转、或提示恶意请求 → 该字符在黑名单中且触发了拦截。

无影响且无报错:正常执行 → 该字符可能未被过滤,或数据库本身能处理。

常见测试集:

' " ` ) ( ; \ %0a %0b /* // # -- +

2. 测试注释符是否可用

注释符用于闭合语句剩余部分:–、#、/*。输入 ’ – 或 1’ # 后页面表现:

原本错误的语句变得正常 → 注释符有效且未被过滤。

返回错误或依然异常 → 可能注释符被过滤(删除或转义)。可尝试 URL 编码 %23(#)、%2D%2D(–)或使用 ;%00 等替代。

3. 测试 SQL 关键字是否被过滤

常用关键字:SELECT、UNION、AND、OR、WHERE、FROM、ORDER、BY、INSERT、UPDATE、DELETE、DROP 等。

探测方法:在参数中注入关键字,观察响应。

大小写绕过测试:输入 SeLeCt。若小写被过滤,大写可能漏过 → 说明过滤可能不区分大小写或仅过滤特定大小写形式。

双写绕过测试:输入 SELSELECTECT。若过滤机制仅删除一次关键字,可能残留 SELECT。

使用注释或换行分割:输入 SEL/foo/ECT。若内联注释未被过滤,可能绕过。

URL 编码/双重编码:%53%45%4C%45%43%54。如果 WAF 解码一次而应用解码两次,可能绕过。

观察报错:如果输入包含 AND 1=1,页面报错“非法关键字” → 明确过滤了 AND。

没有报错但注入失败:可能是过滤了该关键字,也可能是其他原因(如参数类型限制)。

4. 测试空格是否被过滤

注入语句中空格常被用于分隔关键字。输入多个空格、%20、%0a、%09、%0d、/**/、%0b、%0c 等。

如果普通空格被删除(如 1 and 1=1 变成 1and1=1 报错),尝试使用其他空白符替代:%0a、%0d、%09(Tab)、%0b、%0c。

若所有空白符都被过滤,可尝试使用内联注释 /注释/ 代替空格,如 1/foo/and/bar/1=1。

5. 测试等号(=)是否被过滤

= 常用于条件判断。可替代方法:LIKE、REGEXP、IN、BETWEEN、<>、>、< 等。

输入 1 and 1=1 如果报错,尝试 1 and 1 like 1。若后者成功,说明 = 被过滤。

6. 测试函数名是否被过滤

例如 DATABASE()、VERSION()、USER()、SLEEP()、BENCHMARK() 等。

若 AND SLEEP(5) 无效但 AND BENCHMARK(1000000,MD5(‘a’)) 有效 → SLEEP 被过滤。

尝试大小写变形、双写、注释分割,或使用等价函数(如 SLEEP 可用 BENCHMARK 替代)。

7. 联合测试 —— 使用故意错误的 payload 观察错误信息

构造一个必然出错的注入,例如 id=1’ and extractvalue(1,concat(0x7e,version()))–+(针对 MySQL)。如果返回数据库错误信息,可能会直接揭示哪些字符或语法被过滤。很多情况下,错误信息会显示被转义后的内容或拦截日志。

三、高级方法:二分法/字典枚举

如果手动测试繁琐,可以使用脚本向目标发送大量 payload,根据响应内容(页面长度、状态码、返回文本)自动判断过滤规则。例如:

发送 1’ + + ‘1’=‘1,观察 character 是否影响结果。

发送 1 union select 1,2,3,逐步修改关键字,直到不再被拦截。

四、典型过滤模式及特征一览表

过滤现象可能原因
输入 ’ 变成 '使用了 addslashes 或 mysqli_real_escape_string
输入 ’ 消失黑名单删除单引号
输入 union select 导致 403/500WAF 或代码中过滤了该关键字组合
输入 %27(单引号的URL编码)正常后端解码后未正确过滤,或WAF未检测编码
空格变成 + 或消失过滤空格,但未过滤其他空白符
输入 1 and 1=1 正常,但 1 union select 1 报错可能仅过滤了 union 关键字
所有输入都变成纯文本/无变化参数可能使用了 intval() 强制转换或参数化查询,无法注入

五、实际操作建议

分段测试:先测试特殊字符,再测试 SQL 关键字,最后测试函数。

保留原始正常请求:作为对比基准。

使用不同的注入位置:GET 参数、POST body、Cookie、HTTP 头,过滤规则可能不同。

尝试编码绕过:URL编码、Unicode编码、十六进制编码、双重编码。

使用内联注释:MySQL 中 /!50000SELECT/ 可能绕过简单黑名单。

结合报错信息:如果开启了错误显示,可以直接看到被转义后的 SQL 片段。

六、示例:判断过程实录

假设原始 URL:http://example.com/news.php?id=1

测试 id=1’ → 页面空白,无报错 → 可能单引号被删除或转义。

测试 id=1%27 → 同样空白 → 过滤了单引号。

测试 id=1 and 1=1 → 页面正常返回新闻内容 → and 未被过滤。

测试 id=1 union select 1 → 页面返回 403 Forbidden → 关键字 union 被 WAF 拦截。

测试 id=1 UnIoN SeLeCt 1 → 也返回 403 → 过滤不区分大小写。

测试 id=1 /!50000union/ select 1 → 页面返回正常(无注入结果)但仍正常显示 → 可能内联注释没有被正确解析,或者联合查询本身因列数不对而失败,需要进一步测试。但至少说明 /!/ 没有被过滤掉。

结论:单引号被过滤;union 关键字被黑名单过滤(不区分大小写),但其他关键字(and)可用;可使用内联注释,但需要寻找其他注入方式(如布尔盲注、时间盲注)。

通过以上系统化的测试,可以逐步绘制出目标应用的“过滤映射表”,从而定制出能绕过这些规则的注入 payload。

SQL注入绕过过滤技术大全

在SQL注入过程中,目标应用常常会实施各种过滤(黑名单、转义、WAF规则等)。掌握绕过技术是成功注入的关键。本文按过滤类型系统介绍绕过方法,每种方法附带原理和示例。

一、关键字过滤绕过

应用可能过滤 SELECT、UNION、AND、OR、WHERE 等SQL关键字。

1. 大小写变形

原理:过滤仅针对特定大小写形式(如全部小写)。

示例:SeLeCt、UnIoN、aNd、oR。

适用:简单黑名单。

2. 双写关键字

原理:过滤逻辑可能是删除关键字,删除一次后剩余部分重新拼接成完整关键字。

示例:SELSELECTECT → 删除中间的 SELECT 剩下 SELECT;ANDAND → 剩下 AND。

注意:适用于仅替换/删除一次的情况。

3. 内联注释分割

原理:MySQL 中 /!12345SELECT/ 仍会被解析为 SELECT(12345 为版本号,可省略)。

示例:/!UNION/、/!50000SELECT/。

扩展:任意注释内容:SEL/foo/ECT,部分WAF不检测注释内容。

4. 使用等价符号或函数替代

AND/OR:使用 && 替代 AND,|| 替代 OR(需URL编码 %26%26、%7C%7C)。

等号:= 被过滤时使用 LIKE、REGEXP、IN、BETWEEN、<>、>、<。

示例:1 AND 1=1 → 1 && 1 LIKE 1。

5. 换行/回车分割

原理:某些过滤只匹配空格后的关键字,换行符可被忽略。

示例:1%0aAND%0a1=1(%0a是换行)。

6. URL编码/双重编码

原理:WAF只解码一次,后端却解码两次,导致WAF看到编码字符不拦截。

示例:%25%37%33%25%36%35%25%36%63%25%36%35%25%36%33%25%37%34 解码一次为 %73%65%6c%65%63%74,再解码为 select。

7. 使用空字节(仅旧版PHP ) 原理:C语言字符串以空字节 %00 结尾,部分WAF忽略其后内容。

示例:1%00 union select。

二、空格过滤绕过

空格用于分隔SQL语句中的关键字或条件。

1. 替代空白符

可用的空白符(URL编码后):

制表符 %09、换行 %0a、回车 %0d、换页 %0c、垂直制表 %0b。

示例:1%09and%091=1。

2. 使用注释代替空格

内联注释:/注释/ 可当作空格。

示例:1/foo/and/bar/1=1。

3. 使用括号包裹表达式

原理:括号不需要空格,可改变运算顺序。

示例:1 and(1=1)。

*4. 使用特殊符号(MySQL)

+、-、*、/、% 等算术运算符可分割关键字(但需注意优先级)。

示例:1+and+1=1(+ 在数字上下文中可能被当做加法,需谨慎)。

5. 使用反引号(MySQL)

示例:1and1=1(较少用)。

三、引号过滤绕过

当单引号被过滤或转义时,无法闭合字符串。

1. 使用宽字节注入(GBK/GB2312编码)

原理:PHP使用 addslashes 转义单引号(’ -> '),但在GBK编码中,反斜杠 \(%5c)与前面的字符组合成宽字节字符,使得转义失效。

示例:输入 %df%27,经过转义变成 %df%5c%27,%df%5c 被解释为汉字“運”,剩下的 %27 成为独立单引号。

前提:数据库连接编码为GBK,且使用 addslashes(或 magic_quotes_gpc)。

2. 使用十六进制或编码表示字符串

原理:不使用引号表示字符串,直接传递十六进制值。

示例:SELECT * FROM users WHERE name = 0x61646d696e(0x61646d696e 是 admin 的十六进制)。

3. 使用函数返回值代替字符串

示例:CHAR(97,100,109,105,110) 返回 admin。

4. 无引号情况利用(数字型注入)

原理:如果注入点是数字类型,根本不需要引号闭合,直接注入数字即可。

5. 逃逸转义:使用 \ 吃掉后续字符(特殊场景)

如果应用将 ’ 变成 ',输入 \ 可能导致后续字符被转义,但需要具体上下文。

四、注释符过滤绕过

–、#、/* 被过滤时,可使用其他方法闭合语句。

1. 使用 ; 或 %00 截断

示例:1’ union select 1;%00(%00 空字节截断MySQL字符串)。

注意:空字节注入在旧版MySQL有效。

2. 使用 || 或 && 构造闭合

原理:不依赖注释,通过逻辑闭合。例如字符型注入:1’ and ‘1’=‘1,无需注释。

3. 利用数据库特性闭合

MySQL:1’ and ‘1’=‘1’ 最后多出的单引号被 and 后条件匹配掉。

MSSQL:可使用 – 的变体 ;– 等,或利用 %00。

4. 使用括号和函数平衡

如果必须注释掉后面的内容,且 #、– 被过滤,可考虑构造能让剩余语句语法正确的 payload。

五、函数/关键字组合过滤绕过

有时单独过滤 SELECT 或 FROM,但加在一起会拦截。

1. 使用内联版本注释

/!50000SELECT/ 或 /!50000UNION/ 绕过黑名单。

2. 使用等价函数替换

过滤的目标替代方案
DATABASE()SCHEMA()、CURRENT_SCHEMA
VERSION()@@VERSION、@@GLOBAL.VERSION、@@VERSION_COMMENT
USER()CURRENT_USER()、SESSION_USER()、SYSTEM_USER()
SLEEP(n)BENCHMARK(1000000,MD5(‘a’))、HEAVY QUERY
BENCHMARKSLEEP 或 LATENCY(MariaDB)
CONCAT()CONCAT_WS()、GROUP_CONCAT 或
SUBSTR()MID()、SUBSTRING()、RIGHT()、LEFT()
ORD()ASCII()、CHAR()

3. 使用报错函数替代联合查询

当 UNION 被严厉过滤时,使用报错注入(extractvalue、updatexml、floor 等)或布尔盲注。

六、逗号过滤绕过

在 UNION SELECT 1,2,3 或 SUBSTR(str,1,1) 中逗号被过滤。

1. 使用 JOIN 绕过 UNION 中的逗号

UNION SELECT * FROM (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c

等价于 UNION SELECT 1,2,3。

2. 使用 OFFSET 或 FROM … FOR 绕过

LIMIT 1 OFFSET 1 替代 LIMIT 1,1。

3. 使用 CASE WHEN 或 IF 替换截断函数中的逗号

SUBSTR(str FROM 1 FOR 1)   -- 替代 SUBSTR(str,1,1)
MID(str FROM 1 FOR 1)

*4. 使用 JOIN 结合 USING 或 ON 绕过(特殊场景)

七、HTTP参数污染(HPP)

原理:WAF只检查同名参数的第一个值,而后端可能取最后一个值(或合并)。

示例:?id=1&id=UNION SELECT。某些WAF检测第一个 id=1 放行,后端获取 id 数组,PHP/Apache 默认取最后一个值,导致注入参数传入。

适用:部分WAF和中间件配置。

八、分块传输绕过(Chunked Transfer Encoding)

原理:将payload分块发送,WAF可能未对分块内容进行完整检测。

实现:使用Burp Suite等工具将POST请求改为分块编码,将恶意SQL语句拆成多块,使WAF看不到完整关键字。

九、数据库特性类绕过

1. MySQL 特殊写法

反引号:SELECTidFROM users(可用于绕过某些正则,将关键字包在反引号内)。

花括号:SELECT {id} FROM users(某些版本支持)。

科学计数法:1e0 代替 1。

2. MSSQL 特性

注释 /* 与 – 但支持 ;–。

变量:DECLARE @q varchar(2000); SET @q=‘SELECT’; EXEC (@q); 可绕过简单过滤。

LIKE 通配符:% 和 _。

3. PostgreSQL 特性

$tag$ 字符串引用:SELECT $tag$admin$tag$ 无引号。

:: 类型转换:‘1’::int。

4. Oracle 特性

字符串连接:‘ad’||‘min’。

CHR():CHR(97)||CHR(100) 构造字符串。

十、综合绕过思路总结

在实际测试中,过滤往往是多层的。推荐步骤如下:

探测过滤规则:逐一输入特殊字符、关键字,观察响应。

尝试最基础的绕过:大小写、双写、URL编码。

使用替代空白符/注释:如果空格被过滤。

使用数据库特有语法:如内联注释、/!50000UNION/。

考虑编码与WAF解析差异:双重编码、分块传输、HPP。

转换注入方式:无法联合查询时转向报错注入、布尔盲注、时间盲注。

终极方法:使用DNSlog外带数据(OOB),彻底绕过回显限制。

附:快速绕过对照表

过滤内容常用绕过方法
SELECTSeLeCt、SELSELECTECT、/!SELECT/
AND/OR&&、
空格%09、%0a、/**/、+、括号
单引号宽字节、十六进制、函数、无引号数字型
注释符利用逻辑闭合、;%00、
逗号JOIN、FROM … FOR、CASE 替代
等号LIKE、REGEXP、IN、<>
函数名等价函数、大小写、内联注释

掌握以上技术后,面对绝大多数过滤都能找到绕过路径。实战中需结合具体数据库类型和过滤规则灵活组合使用。