当前位置: 首页 > news >正文

SQL注入黑名单绕过实战:5种编码变形与等价替换技巧

1. 项目概述:当SQL注入遇上黑名单

在Web安全测试或者CTF比赛中,SQL注入是最经典也最考验基本功的漏洞类型。但现实世界和高质量的靶场(比如Bugku)不会把漏洞赤裸裸地摆在你面前,它们往往会设置一些障碍,最常见的就是黑名单过滤。所谓黑名单,就是开发者预定义了一个“坏词”列表,比如union,select,or,and,空格,--等等,一旦检测到你的输入中包含这些词,就直接拦截或替换掉,让你的攻击Payload失效。

“Bugku SQL注入实战:绕过黑名单的5种骚操作”这个标题,精准地指向了安全爱好者、CTF选手以及初入行的渗透测试工程师们最头疼也最想掌握的实战技能点。它不是一个泛泛而谈的SQL注入教程,而是聚焦于“绕过”这个对抗性动作,提供了五种具体的、可复现的“骚操作”和完整的Payload。这意味着,读者拿到这篇文章,目标非常明确:当常规的注入语句被拦截时,我手里还有哪些牌可以打?这篇文章的价值就在于,它把这些“牌”的玩法、原理和适用场景,掰开揉碎了讲给你听。

对于新手,这能帮你快速突破CTF中常见的过滤关卡;对于有一定经验的从业者,这能系统化你的绕过思路,在面对更复杂的WAF(Web应用防火墙)或自定义过滤时,能更快地组合出有效的测试向量。接下来,我们就深入这五种绕过黑名单的“骚操作”,看看它们是如何在“猫鼠游戏”中为攻击者打开缺口的。

2. 绕过黑名单的核心思路与原理拆解

在开始具体操作之前,我们必须先理解绕过黑名单的本质。黑名单过滤是一种“已知威胁”防御模型,它基于一个假设:我能列举出所有危险的字符串。但SQL语言的灵活性和数据库解析器的特性,使得这个假设非常脆弱。绕过黑名单的核心思路,可以归结为以下几点:

2.1 编码与变形:让“坏人”穿上“马甲”这是最基础的思路。过滤系统匹配的是字符串的字面形式,如果我们能改变这个形式,但不改变数据库最终解析的结果,就能实现绕过。例如,将关键字进行URL编码、十六进制编码、Unicode编码,或者使用大小写变换(SeLeCt)、内联注释(/*!select*/)等。关键在于,数据库的SQL解析器在解释语句时,会将这些变形还原成标准的关键字。

2.2 等价替换:寻找“替身演员”如果union被禁,有没有其他方式能达到联合查询的效果?如果and被禁,有没有其他逻辑运算符?如果空格被禁,有没有其他字符能起到分隔作用?这就是等价替换的思路。它要求我们对SQL语法有更深入的理解,知道哪些功能可以由不同的语法结构实现。

2.3 利用解析特性:在“语法盲区”跳舞数据库解析SQL语句时,在某些上下文环境下会对字符有特殊的解释。例如,注释符/**/里的内容在某些情况下会被忽略,反引号、括号的用法,甚至字符串拼接函数都可以被用来“包裹”或“分割”被过滤的关键字,从而骗过简单的字符串匹配。

2.4 多级组合:混合双打单一的绕过技巧可能被更完善的黑名单针对。高水平的绕过往往是多种技巧的组合。比如,先对关键字进行编码,然后用特殊字符代替空格,最后利用数据库特性(如H2数据库的%00截断)来确保Payload执行。这需要测试者根据目标的过滤强度进行动态调整。

理解了这些核心思路,我们再看具体的五种“骚操作”,就会明白它们不是孤立的奇技淫巧,而是这些思路的具体实践。每一种操作都瞄准了黑名单防御的某个薄弱环节。

3. 五种绕过黑名单的“骚操作”详解与Payload构造

下面,我们结合Bugku这类靶场中常见的过滤场景,逐一拆解这五种操作。我会为每种操作提供原理说明、典型Payload示例以及关键的注意事项。

3.1 操作一:内联注释与版本特异性语法

这是MySQL数据库下非常经典且强大的一种绕过方式。MySQL支持一种特殊的注释语法:/*!50001select*/。这里的50001是一个版本号,其含义是:当MySQL数据库版本大于或等于5.00.01时,注释中的内容会被当作SQL代码执行;如果版本低于此号,则整个被当作注释忽略。而很多简单的黑名单过滤,只会去匹配/**/之间的内容是否为关键字,却不会解析这种带有版本号的特殊注释。

  • Payload示例

    -1‘ union /*!50001select*/ 1,2,group_concat(table_name) from /*!50001information_schema*/.tables where table_schema=database()--+

    这个Payload假设union,select,information_schema都被过滤了。我们用/*!50001select*/代替了select,用/*!50001information_schema*/代替了information_schema。对于过滤系统来说,它可能只看到了/*...select...*/,认为这是一个注释而放行,但MySQL(版本>=5.00.01)实际执行时,会将其中的selectinformation_schema作为关键字解析。

  • 实操心得

    1. 版本号选择:通常使用50001(即5.00.01)即可,这是为了兼容绝大多数MySQL 5.x及以上版本。你也可以尝试/*!select*/(不带版本号),在某些环境下也能被解析。
    2. 位置灵活:内联注释几乎可以放在SQL语句的任何位置,包括关键字中间(如s/*!*/elect),这能进一步扰乱基于正则的过滤。
    3. 注意空格:有时过滤会严格检查/*后紧跟的内容,适当调整空格可能有助于绕过。

3.2 操作二:关键字双写与大小写绕过

这是一种非常“朴素”但有时有效的绕过方式,针对的是编写不严谨的黑名单过滤逻辑。

  • 双写绕过:假设过滤逻辑是:检测到select这个单词,就将其替换为空字符串(‘’)。那么,如果我们输入selselectect,过滤系统会找到中间的select并将其删除,剩下的部分恰好又拼接成了select

    • Payload示例-1‘ ununionion selselectect 1,2,3--+
    • 原理ununionion经过替换(删除union)后变成unionselselectect经过替换(删除select)后变成select
  • 大小写绕过:如果过滤逻辑是简单的、区分大小写的字符串匹配(比如用strpos()indexOf()查找select),那么使用大小写混合的形式就能绕过。

    • Payload示例-1‘ UniOn SeLeCt 1,2,3--+
    • 原理:MySQL的SQL关键字是不区分大小写的。UniOnSeLeCt对数据库解析器来说,与unionselect完全等价。
  • 注意事项

    双写绕过高度依赖于过滤的实现方式是“查找并替换一次”。如果过滤是“循环查找替换直到不存在”或“直接拒绝请求”,则此方法失效。大小写绕过在如今稍具规模的WAF或过滤组件中基本都已防护,但在一些自写的、简单的过滤脚本中仍可能遇到。

3.3 操作三:使用非标准空格与注释符

空格在SQL语句中用于分隔关键字和标识符,是最常被过滤的字符之一。但除了标准的空格( ,ASCII 32),还有很多字符在SQL解析器眼里也能起到“分隔”作用。

  • 常见空格替代符

    • /**/(多行注释):最常用,如union/**/select
    • /*!*/(内联注释):同上。
    • %09(水平制表符,Tab):URL编码形式。
    • %0a(换行符,LF)
    • %0d(回车符,CR)
    • %0b(垂直制表符)
    • %a0(不间断空格,在某些编码下)
    • +(在URL参数中,有时会被解析为空格)
    • 括号():在某些语境下可以用于包裹参数,避免使用空格,例如select(1),(2)
  • Payload示例

    -1‘%0aunion%0aselect%0a1,2,3%0afrom%0aadmin--+

    这里用%0a(换行符)代替了所有空格。对于通过GET/POST传递的参数,需要对其进行URL编码。

  • 注释符的妙用: 除了用于注释,/**/还可以作为“可被忽略的填充物”插入到关键字中,破坏黑名单的匹配。

    • Payload示例un/**/ion sel/**/ect 1,2,3
    • 原理:过滤系统可能匹配不到完整的unionselect,但数据库解析时会忽略注释,最终执行union select

3.4 操作四:十六进制与URL编码绕过

当过滤发生在应用层,而解码发生在更深层(如数据库驱动或数据库自身)时,编码绕过就派上了用场。其核心是让攻击Payload在传输和过滤检查时是一个“无害”的编码字符串,在最终执行时被解码还原为“有害”的SQL代码

  • 十六进制编码:常用于处理字符串值,特别是当单引号被过滤时。

    • 场景:需要注入字符串‘admin‘,但单引号被过滤。
    • 操作:将admin转换为十六进制0x61646d696e
    • Payload示例... where username=0x61646d696e
    • 原理:MySQL会将十六进制数字自动解释为字符串。这样我们就避免了使用单引号。
  • URL编码:主要针对HTTP请求过程中的过滤。WAF或应用代码可能在收到URL编码后的参数前就进行检查,也可能在之后。多次编码可能绕过前者。

    • Payload示例union->%75%6e%69%6f%6e(一次URL编码) ->%25%37%35%25%36%65%25%36%39%25%36%66%25%36%65(对%75等字符再次编码,即双重URL编码)。
    • 原理:如果过滤检查发生在第一次解码之前,它看到的是%75%6e...,匹配不到union关键字。但服务器端可能进行两次解码,最终还原为union
  • 实操心得

    1. 编码位置:不一定需要编码整个关键字,有时只编码关键字符(如空格、单引号)即可。
    2. 组合使用:可以将十六进制编码与内联注释结合,例如/*!50001select*/ 0x61646d696e
    3. 注意数据库差异:十六进制语法可能因数据库而异(MySQL用0x,PostgreSQL用x‘...‘)。

3.5 操作五:利用数据库特性与函数拼接

这是最高阶的一种绕过方式,需要深入了解特定数据库的“怪癖”和丰富的内置函数。

  • 字符串拼接绕过关键字检测:如果union select被整体视为一个黑名单词组,可以尝试将其拆开,再用函数拼接。

    • Payload示例(MySQL)
      -1‘ and 1=2 uni‘+‘on sel‘+‘ect 1,2,3--+
      这里假设+在字符串上下文是连接符(如在SQL Server中)。在MySQL中,更常用concat()函数。
      -1‘ and 1=2 union concat(sel,ect) 1,2,3--+
      (假设concat函数可用,且select不被单独过滤)。更实际的用法是拼接出数据库名、表名。
  • 利用特定数据库特性

    • MySQL反引号:反引号用于引用标识符(数据库名、表名、列名)。在某些过滤宽松的场景,可以尝试selectunionselect`(虽然这通常不合法,但说明了利用特殊符号的思路)。
    • SQLite中的||:在SQLite中,||是字符串连接符,可用于拼接关键字。
    • 注释符截断:在某些旧版本或特定配置的数据库中,--#之后的内容需要换行符才被认作注释结束,否则可能被当作语句的一部分执行,这可以用于构造畸形语句。
  • Payload示例(利用concatsubstring

    -1‘ union select 1,2,concat(table_name) from information_schema.tables where table_schema=database() limit 0,1--+

    如果concat也被禁?可以尝试concat_ws(),或者更底层的方法。这种场景下,比拼的就是对数据库函数库的熟悉程度。

  • 注意事项

    这种方法成功率不稳定,严重依赖于目标系统的数据库类型、版本、配置以及过滤逻辑的精细程度。它通常是在其他常规方法都失效后的“奇招”,需要大量的尝试和模糊测试。

4. 实战演练:组合Payload构建与测试流程

掌握了五种单独的技巧,就像学会了五种武术招式。但在实战中,敌人不会按套路出牌,你需要根据对方的反应(返回的错误信息、拦截提示等)灵活组合这些招式。下面是一个模拟在Bugku类靶场中的实战测试流程。

4.1 信息收集与过滤探测

首先,你需要判断是否存在注入点,以及过滤了什么。

  1. 基础探测:提交id=1‘id=1‘ and ‘1‘=‘1,观察回显差异,确认注入点。
  2. 过滤探测:逐步提交包含可能被过滤关键词的Payload,观察是被拦截(如返回“非法参数”)、被转义(如单引号变成\‘)还是被执行(返回数据库错误或正常数据)。
    • 测试union select
    • 测试and 1=1
    • 测试or 1=1
    • 测试空格
    • 测试--#
    • 测试information_schema

4.2 逐步构造绕过Payload

假设我们探测到union,select,空格,information_schema被过滤,单引号被转义。

  • 第一步:绕过单引号和空格由于单引号被转义,我们尝试用数字型注入,或者利用十六进制。先处理空格,用/**/代替。

    • 尝试Payload:1/**/and/**/1=11/**/and/**/1=2,通过回显差异确认and可用且空格绕过成功。
  • 第二步:绕过union select尝试内联注释:1/**/un/*!50001ion*/ sel/*!50001ect*/ 1,2,3如果不行,尝试双写(假设过滤是替换式):1/**/ununionion/**/selselectect/**/1,2,3还不行,尝试大小写混合:1/**/UnIoN/**/SeLeCt/**/1,2,3或者尝试用%0a代替/**/1%0aUnIoN%0aSeLeCt%0a1,2,3

  • 第三步:绕过information_schema这是MySQL获取元数据的主要方式。如果被过滤,可以尝试:

    1. 使用内联注释:from /*!50001information_schema*/.tables
    2. 使用sys库(MySQL 5.7+):from sys.schema_table_statistics(但需要权限)。
    3. 盲猜表名和列名(在CTF中常见),或者利用polygonid()等函数进行报错注入,从错误信息中带出数据,从而完全避开查询information_schema
  • 第四步:组合最终Payload假设我们通过%0a绕过空格,通过内联注释绕过selectinformation_schema,最终构造出获取表名的Payload:

    -1%0aun/*!50001ion*/%0asel/*!50001ect*/%0a1,2,group_concat(table_name)%0afrom%0a/*!50001information_schema*/.tables%0awhere%0atable_schema=database()--+

    将这个Payload提交,观察是否成功返回数据库表名。

4.3 自动化测试与工具辅助

手动构造和测试非常耗时。在实际安全测试中,我们会借助工具:

  • Sqlmap:强大的自动化SQL注入工具。它内置了大量的绕过脚本(tamper scripts)。针对黑名单,你可以使用--tamper参数。
    • 例如:sqlmap -u “http://target.com/page?id=1“ --tamper=space2comment,equaltolike
    • space2comment会将空格替换为/**/equaltolike会将=替换为LIKE,这些都能用来绕过简单的过滤。
    • Sqlmap的tamper脚本可以链式调用,组合多种绕过技术。
  • 自定义脚本:对于特定的、奇怪的过滤规则,可能需要自己编写Python等脚本,按照探测到的过滤逻辑自动生成和测试变异Payload。

重要提示:在真实授权测试中,自动化工具可能产生大量请求,务必控制速率,并在测试时间窗口内进行。在CTF中,则鼓励手动探索以加深理解。

5. 防御视角与总结反思

作为一名安全从业者,只会攻击不懂防御是片面的。通过分析这些绕过技术,我们能更好地理解如何构建更安全的代码。

5.1 黑名单过滤为什么总是失效?根本原因在于“枚举不完整”和“上下文缺失”。SQL注入的变体无穷无尽,依赖预定义的黑名单注定会漏报。而且,过滤系统往往在应用层进行简单的字符串匹配,无法理解SQL语句的语义上下文,因此很容易被编码、注释等技巧欺骗。

5.2 更有效的防御措施是什么?

  1. 使用参数化查询(预编译语句):这是防止SQL注入的黄金标准。将SQL语句的结构(如SELECT * FROM users WHERE id = ?)与数据(如?对应的值)分开发送给数据库。数据库会先编译语句结构,再将数据代入,从根本上杜绝了数据被解释为代码的可能性。无论输入中包含什么unionselect,都只会被当作纯数据处理。MyBatis中应使用#{}而非${},就是因为#{}实现了参数化查询,而${}是危险的字符串拼接。
  2. 输入验证与白名单:对于已知固定格式的输入(如数字ID、固定选项),使用白名单验证(只允许已知好的值)比黑名单拒绝(拒绝已知坏的值)要可靠得多。例如,如果id参数应该是数字,就直接用intval()或类似函数转为整数。
  3. 最小权限原则:数据库连接账户不应使用rootdbo等高权限账户。应为其分配仅能满足应用功能所需的最小权限(如只有特定表的SELECT权限),这样即使发生注入,危害也能被限制。
  4. Web应用防火墙(WAF):WAF基于更复杂的规则(如语义分析、行为分析)和不断更新的威胁情报,可以提供一层额外的防护。但它不是银弹,也可能被绕过,应作为纵深防御的一环,而非唯一依赖。
  5. 框架的安全特性:使用现代、成熟的开发框架(如Spring Security, Laravel等),并正确配置其内置的安全机制,可以避免很多低级的安全漏洞。

回过头看这“五种骚操作”,它们本质上是攻击者与防御者在不同认知层面上的博弈。防御者如果只停留在“字符串匹配”的层面,那么攻击者总有办法通过编码、变形、利用特性来绕过。而防御者一旦将防线建立在“语义分离”(参数化查询)和“最小权限”这些更根本的层面上,攻击的成本就会急剧上升。

对于学习者和测试者而言,深入理解这些绕过技术,不仅是为了在CTF中得分,更是为了在代码审计和渗透测试中,能够更准确地评估系统的脆弱点,并为其提供真正有效的加固建议。安全是一个持续对抗的过程,而理解攻击,是做好防御的第一步。在下次遇到一个看似固若金汤的黑名单时,不妨从这五个角度想一想,或许就能找到那条隐藏的路径。

http://www.cnnetsun.cn/news/3702453.html

相关文章:

  • 数字孪生空间计算技术:亚毫米级精度实现与应用
  • 如何高效使用开源翻译工具:智能游戏本地化实战指南
  • HR知识卡片-18:组织变革模型
  • Jellium Desktop智能家居设备支持列表:兼容的设备
  • 从零到一:AI大模型应用开发实战指南(Python、Prompt、RAG与低代码平台)
  • TPIC7710EVM评估板:汽车电子驻车制动系统开发实战指南
  • 诊断技术十年演进:从传统到智能化的突破
  • 基于Arduino与超声波传感器的TFT雷达扫描系统设计与实现
  • 古月学院课程代码揭秘:从零开始手写URDF模型的完整教程
  • 基于Java+Vue的旅游攻略分享系统架构设计与实践
  • 树莓派GUI开发实战:用Pyside6与gpiozero实现LED亮度控制
  • LTX2.3+ComfyUI:AI视频生成技术解析与漫剧创作实战指南
  • GenshinCelShaderURP实战教程:Nilou模型卡通渲染效果实现步骤详解
  • 打包 APK 时,报错:The destination folder does not exist or is not writeable
  • 树莓派PySide6 QML串口工具开发:从环境搭建到实战优化
  • Matlab实现风光水火储多能互补优化调度模型
  • AI编程驱动视频自动化生成:Claude Code与Cursor整合实践
  • Garth安全实践:保护Garmin账号认证信息的5个关键策略
  • 如何快速入门Windows-iotcore-samples:从环境搭建到第一个Blinky项目
  • 谜语大全 API 参数详解与请求优化最佳实践
  • 基于RP2040的极简时钟设计:驱动TFT屏实现无表盘指针动画
  • Arduino蓝牙串口通信协议解析与精简实现教程
  • DevOps实践指南:从CI/CD到文化转型
  • HTTPS性能优化实战:从TLS握手到HTTP/2的全链路提速指南
  • 从源码到运行:SoulSync开发者指南 — 架构解析与贡献教程
  • 炉石传说HsMod完整指南:5分钟安装,解锁32倍速和200+皮肤定制
  • Windows Subsystem for Android开发调试全攻略:从问题定位到解决方案
  • 掌控板教学应用设计:从工具选型到项目落地的实战指南
  • 扩散模型中文生成难题:从原理到ControlNet的实战解决方案
  • 为什么你的Windows安全工具总加载失败?OpenArk内核驱动终极解决方案