1. 项目概述当“与”和“或”被屏蔽时在渗透测试或安全审计的日常工作中我们经常会遇到各种Web应用防火墙WAF或开发者自定义的输入过滤机制。其中对SQL注入攻击中最基础、最常用的逻辑运算符AND和OR进行过滤或拦截是一种非常常见的初级防御手段。很多刚入门的安全测试人员一旦发现and 11或or 11这类经典探测语句被拦截就可能会认为注入点不存在或无法利用从而错失良机。这个项目要探讨的正是如何在这种“基础逻辑运算符被过滤”的特定场景下依然能够完成SQL注入的探测、信息获取乃至最终的数据窃取。这不仅仅是几个技巧的堆砌更是一种绕过思维和语法理解的综合体现。对于安全从业者而言掌握这类绕过技术能更深刻地理解SQL语言的灵活性以及防御措施的局限性从而在设计防御方案时考虑得更加周全。2. 核心绕过思路与原理剖析2.1 理解过滤的本质与盲点当应用层过滤AND和OR时通常的实现方式有以下几种大小写敏感过滤简单匹配字符串and和or。大小写不敏感过滤通过正则表达式如/\b(and|or)\b/i进行匹配。空格分隔过滤将输入按空格分割成单词再检查是否包含黑名单词汇。替换为空将and和or替换为空字符串。我们的绕过思路正是针对这些过滤逻辑的盲点来设计的。核心原理在于SQL解析器与应用程序的输入过滤器对语句的理解方式是不同的。过滤器看到的可能是我们输入的原始字符串而SQL解析器看到的则是经过我们精心“编码”或“变形”后的最终指令。2.2 主要绕过技术分类基于上述原理我们可以将绕过技术分为几个层面编码与变形层改变AND/OR的书写形式使其绕过字符串匹配。等价替换层寻找在SQL中与AND/OR逻辑功能完全等价的其他运算符或表达式。语法技巧层利用SQL注释、运算符优先级、子查询等语法特性重构查询逻辑避免直接使用被过滤的关键字。3. 编码与变形绕过技巧详解这类方法的核心是“欺骗”字符串匹配过滤器让AND/OR以另一种形态出现但数据库依然能正确识别。3.1 大小写变种与双写绕过这是最基础的尝试针对简单的字符串匹配。大小写混合AnD,aNd,Or,oR。如果过滤器是大小写敏感的这招可能直接生效。双写绕过如果过滤逻辑是“替换为空”例如将and替换成空字符串。那么我们可以输入anandd。过滤器移除中间的and后剩下的字符恰好又组成了and。原始输入1 anandd 11过滤后1 and 11实操心得双写绕过对简单的str_replace类过滤非常有效但在现代WAF中已较少见因为它们多采用正则匹配单词边界。3.2 内联注释绕过MySQL数据库支持一种特殊的注释语法/*! ... */其中的代码会被MySQL执行但其他数据库可能将其视为普通注释。更重要的是我们可以在关键字中间插入注释来分割它。示例1 /*!and*/ 11或1 an/* */d 11。原理对于过滤器/\band\b/来说an/* */d不是一个完整的单词and因此可能被放过。但MySQL在解析SQL时会忽略注释最终执行的还是1 and 11。注意事项这种方法高度依赖于数据库类型主要是MySQL和WAF对注释的处理方式。有些WAF也会解析注释内的内容。3.3 URL编码与双重编码这是对付较弱过滤器的有效手段。简单URL编码将关键字中的某个或全部字符进行URL编码百分号编码。and-a%6ed(编码了n) 或%61%6e%64(全部编码)。如果应用在过滤前没有进行URL解码那么%6e不会被匹配为n。双重URL编码更保险的做法是进行两次编码。and- 第一次编码%61%6e%64- 第二次编码%2561%256e%2564。如果应用只解码一次看到的是%61%6e%64可能不匹配and。而数据库连接驱动或框架通常会进行完整的解码最终还原为and。实战场景在Burp Suite的Repeater模块中可以方便地对Payload进行各种编码操作快速测试过滤器的解码层次。3.4 Unicode编码与HTML实体在一些特殊的上下文如输出到HTML页面后又被后端处理或数据库支持Unicode解析时可以尝试。Unicode编码and-\u0061\u006e\u0064(UTF-16) 或U0061U006eU0064。这需要数据库连接层或应用层能正确解析这些Unicode序列。HTML实体如果输入经过HTML解析器可以尝试anda的实体。但这在纯SQL注入场景中较少直接生效多见于跨上下文攻击。注意编码类绕过的成功率与目标系统的处理流水线密切相关。一个典型的处理流程可能是URL解码 - 输入过滤 - SQL拼接 - 执行。你的Payload需要能“存活”过过滤阶段并在执行阶段被正确还原。这通常需要大量的模糊测试Fuzzing来探明路径。4. 逻辑等价替换寻找“替身”这是更高级、更可靠的思路既然不让用AND和OR我们就用其他能达到相同逻辑效果的SQL符号或函数来替代。这要求对SQL逻辑运算有更深的理解。4.1 使用和||运算符在大多数数据库系统如MySQL、PostgreSQL中除了关键字AND和OR还支持对应的标准SQL运算符逻辑与和||逻辑或。这通常是首选的替代方案。原始语句SELECT * FROM users WHERE id1 AND 11绕过语句SELECT * FROM users WHERE id1 11优势简单直接无需编码只要数据库支持且过滤器没有同时屏蔽和||即可。实操心得在测试时的优先级问题需要注意必要时用括号()明确逻辑关系。4.2 利用位运算符与数学函数当连和||也被过滤时我们可以“曲线救国”。用乘法(*)模拟AND在布尔逻辑中TRUE可视为1FALSE可视为0。AND操作类似于乘法1*11(True AND True True)1*00(True AND False False)。我们可以构造原意... AND (SELECT SUBSTR(password,1,1) FROM admin)a替换... * ( (SELECT SUBSTR(password,1,1) FROM admin)a )如果子查询结果为真返回1则1 * 1 1外部条件成立如果为假返回0则1 * 0 0条件不成立。但需注意如果子查询可能返回NULL任何值与NULL相乘结果也是NULL可能导致整个条件失效需要配合IFNULL()或COALESCE()函数处理。用加法()或位或(|)模拟OROR操作类似于加法或最大值101,000。或者使用位或运算符|1|01,0|00。示例... ( (SELECT ...)a )。但加法需注意数值溢出更推荐用|。使用CASE WHEN语句这是最强大、最通用的逻辑控制结构可以完全模拟任何IF-ELSE逻辑自然也能替代AND/OR进行条件判断。示例判断管理员密码第一位是否为 ‘a’如果是则返回1否则返回0。CASE WHEN (SELECT SUBSTR(password,1,1) FROM users WHERE usernameadmin)a THEN 1 ELSE 0 END然后可以将这个CASE表达式用在WHERE子句中与其他条件进行运算如相乘或者直接作为返回字段通过布尔盲注的方式判断。4.3 利用比较运算符与IN、BETWEEN有时复杂的AND/OR条件可以重构为使用其他运算符。用IN替代多个OR等式原句WHERE roleadmin OR rolesuperuser替代WHERE role IN (admin, superuser)用BETWEEN替代范围AND原句WHERE age 18 AND age 60替代WHERE age BETWEEN 18 AND 60虽然这些替代不能覆盖所有AND/OR的场景特别是不同字段间的逻辑连接但在特定查询中改变构造Payload的方式可能恰好避开过滤。5. 基于语法与上下文的高级绕过当上述方法都失效时我们需要跳出“替换关键字”的思维从整个SQL查询的语法结构上寻找突破口。5.1 利用运算符优先级重构逻辑SQL运算符有优先级。例如AND的优先级高于OR。A OR B AND C等价于A OR (B AND C)。如果我们不能使用AND但可以使用OR我们可以通过添加括号来改变逻辑有时能达到类似目的。反之亦然。更关键的是我们可以利用数学比较运算符如和算术运算符来构造复杂的布尔表达式。示例我们想测试id1且usernameadmin。不能使用AND。思路构造一个等式只有当两个条件都满足时等式才为真。例如(id1) (usernameadmin) 2。如果两个条件都为真各返回数值1相加等于2条件成立。这本质上是用加法模拟了AND。5.2 子查询与连接查询替代在某些情况下WHERE子句中的AND条件可以通过子查询或连接查询JOIN来间接实现。使用EXISTS子查询WHERE EXISTS (SELECT ...)本身就是一个条件。我们可以将原本用AND连接的条件部分移到子查询的WHERE条件中。虽然子查询内部可能也需要AND但有时内外层的过滤规则不同可能存在绕过机会。使用IF()或IIF()函数数据库支持的话类似于CASE WHEN可以内联逻辑判断。5.3 注释符截断与多语句执行这是一种风险较高、依赖特定环境的方法但在某些旧系统或配置不当的系统中可能有效。原理利用SQL注释符--或#将原查询后面的部分注释掉然后在其后添加我们自己的完整查询语句其中可以自由使用AND/OR。示例假设原查询是SELECT * FROM products WHERE id[INPUT]。攻击Payload1 --注释掉后续但这样只是终止。要执行新查询通常需要能执行多语句如;分隔。Payload可能为1; SELECT * FROM users WHERE 11 AND usernameadmin --严重警告这需要数据库连接支持多语句查询如PHP中的mysqli_multi_query而现代开发通常使用参数化查询或禁用多语句因此成功率很低且极易触发WAF警报。仅在非常宽松的测试环境中谨慎尝试。6. 实战流程从探测到利用理论需要结合实践。下面以一个假设的、过滤了AND和OR的搜索功能为例梳理完整的测试流程。6.1 信息收集与漏洞探测目标识别找到一个带参数的交互点如/search.php?keywordtest。基础探测提交keywordtest观察是否有SQL错误回显。如果有确认存在注入点。触发过滤提交keywordtest AND 11和keywordtest AND 12。观察是否被拦截返回错误、空白页、WAF拦截页面或行为无差异说明AND被过滤或注释。测试绕过尝试使用和||。keywordtest 11应返回正常结果keywordtest 12应无结果如果两者返回结果不同说明可用且布尔逻辑生效。如果被拦截则进入下一步。6.2 构造布尔盲注Payload假设我们确认可用且页面会根据查询结果返回“有结果”或“无结果”两种不同状态布尔盲注条件。判断数据库名长度keywordtest (SELECT LENGTH(database()))8 --通过改变数字8观察页面状态变化即可判断长度。逐字符猜解数据库名keywordtest (SELECT SUBSTR(database(),1,1))a --使用Burp Suite的Intruder模块对位置1,2,3...和字符a-z, 0-9, _进行暴力猜解。6.3 当和||也被过滤时如果和||也被过滤我们采用“乘法模拟AND”和“CASE WHEN”结合的方式。探测Payloadkeywordtest * (11) --应等同于keywordtest AND 11keywordtest * (12) --应等同于keywordtest AND 12 观察两者响应是否不同。构造盲注Payloadkeywordtest * ( (SELECT CASE WHEN (SUBSTR(database(),1,1)a) THEN 1 ELSE 0 END) )1 --这个Payload的意思是如果数据库名第一个字母是 ‘a’那么CASE表达式返回1整个条件变为test * 1 1理论上成立如果不是 ‘a’则返回0条件变为test * 0 1即01不成立。通过页面状态差异即可判断。6.4 自动化工具辅助手动构造这些复杂的Payload非常繁琐。此时可以借助sqlmap这类自动化工具并为其提供tamper脚本篡改脚本来绕过过滤。编写自定义tamper脚本创建一个.py文件在脚本中定义tamper(payload, **kwargs)函数。这个函数的功能是将Payload中的AND和OR替换成我们想要的等价形式例如替换为和||或者进行双写、注释插入等。# example_tamper.py def tamper(payload, **kwargs): retVal payload if payload: # 替换 AND 为 retVal retVal.replace(AND, ) # 替换 OR 为 || retVal retVal.replace(OR, ||) # 或者使用更复杂的编码 # retVal retVal.replace(AND, an/*!*/d) return retVal使用sqlmap加载tampersqlmap -u http://target.com/search.php?keywordtest --tamperexample_tamper.py --level3 --risk2sqlmap会使用我们提供的脚本对它的Payload进行“化妆”后再发送从而尝试绕过过滤。7. 防御视角与总结作为开发者或安全工程师了解攻击手法是为了更好地防御。根本措施使用参数化查询预编译语句。这是唯一能从根本上杜绝SQL注入的方法。将用户输入始终作为数据参数传递给数据库而不是可执行代码的一部分。无论攻击者如何变形AND、OR都无法改变查询结构。如果必须拼接请严格过滤如果因历史原因无法使用参数化查询输入过滤必须采用白名单机制只允许已知安全的字符而非黑名单禁止已知危险的字符。黑名单永远会有遗漏。使用成熟的WAF商业或开源的WAF如ModSecurity具备更强大的语义分析能力能识别经过编码、变形的攻击Payload而不仅仅是简单的字符串匹配。最小权限原则数据库连接账户应仅具有应用所需的最小权限避免使用root或sa等高权限账户。这样即使发生注入危害也能被限制。从我个人的渗透测试经验来看绕过AND/OR过滤只是SQL注入攻防中最基础的一课。它考验的是测试者对SQL语法理解的深度和思维的灵活性。真正的挑战往往在于如何将这些技巧组合起来应对层层叠加的防御措施。同时这也反复印证了一个安全铁律依赖过滤和黑名单的防御是脆弱且不可靠的将安全建立在“允许什么”而非“禁止什么”的基础上才是更稳固的架构。在实战中遇到这类过滤不要轻易放弃多从SQL语言本身和应用程序解析差异的角度思考往往能发现意想不到的利用路径。