
1. 项目概述编码绕过的本质与价值在渗透测试和网络安全攻防演练中SQL注入始终是Web安全领域最经典、最危险的漏洞之一。随着防御措施的普及简单的单引号闭合、UNION SELECT查询已经很难直接奏效各种WAFWeb应用防火墙和开发者自研的过滤机制层出不穷。这就催生了“绕过”技术的蓬勃发展而其中利用不同编码方式进行绕过因其灵活性和对底层协议、数据库特性的深度依赖成为了高阶攻击者和安全研究员必须掌握的核心技能。这个项目标题“SQL注入--不同编码绕过的区别”直接点出了一个关键但常被混淆的领域。很多初学者知道“编码可以绕过”但面对URL编码、十六进制、Unicode、宽字节等术语时往往一头雾水不清楚它们各自的原理、适用场景和根本区别。盲目尝试不仅效率低下还可能触发更严格的防御规则。本文旨在彻底厘清这些编码绕过技术的底层逻辑让你不仅知道“怎么用”更明白“为什么能用”以及“什么时候该用哪个”。简单来说编码绕过的核心思想是让攻击载荷Payload在“传输/解析”和“执行”这两个阶段以不同的形态呈现从而欺骗过滤机制。过滤逻辑通常在某个中间环节如应用层代码的preg_match检查载荷而数据库引擎则在最终执行时解释它。如果我们能让载荷在过滤环节“看起来无害”而在数据库执行时“恢复原貌”绕过就成功了。不同的编码方式正是利用了不同环节客户端、服务器端中间件、数据库对数据解码规则的差异来实现这一“变形”。2. 核心原理编码如何成为“穿墙术”要理解区别必须先建立统一的认知框架。一次典型的HTTP请求与SQL注入数据会经历多个处理阶段每个阶段都可能涉及编码转换。下图展示了关键环节[攻击者构造Payload] -- [HTTP请求发送可能伴随浏览器/工具自动编码] -- [Web服务器如Apache/Nginx/IIS接收并初步解析] -- [后端语言PHP/Java/Python获取参数并应用过滤规则] -- [过滤后的参数拼接到SQL语句] -- [数据库驱动发送SQL到数据库引擎] -- [数据库引擎解析并执行SQL]编码绕过的机会就诞生于上述链条中前后环节对同一串字节流的解释不一致。我们常说的“双重URL编码”、“十六进制”、“Unicode”、“宽字节”注入其发力的环节和依赖的条件截然不同。2.1 关键环节的编码/解码行为HTTP传输与URL编码浏览器或攻击工具在发送GET/POST请求时会对URL中的非安全字符如空格、引号、尖括号等进行百分号编码%XX格式。Web服务器在接收到请求后通常会自动进行一次URL解码将%20还原为空格%27还原为单引号等然后将解码后的参数传递给后端程序。后端程序过滤这是防御的主战场。开发者使用preg_replace、str_replace、addslashes等函数或WAF规则对解码后的参数进行关键字匹配、危险字符转义或删除。数据库解析数据库引擎接收到完整的SQL语句字符串后会按照SQL语法进行解析。某些数据库支持在SQL语句中直接使用十六进制字面量如0x63616D或会对特定编码如GBK的多字节字符进行特殊解释。编码绕过的核心就是构造一个Payload使其在阶段2过滤之后进入阶段3数据库解析之前或之时被转换成我们真正想要执行的恶意SQL片段。3. 各类编码绕过技术深度解析与对比下面我们将逐一拆解常见的编码绕过技术并附上详细的实战示例和原理剖析。3.1 双重多重URL编码绕过这是最基础但非常有效的绕过方式主要针对在URL解码后才对参数进行字符串匹配过滤的防御逻辑。原理 假设防御代码逻辑是if (preg_match(‘/union/i’, $_GET[‘id’])) { die(‘Blocked!’); }。这里$_GET[‘id’]中的值是Web服务器经过一次URL解码后传递给PHP的。例如我们提交id1 union select 1,2,3由于union是明文会被拦截。如果我们提交id1 %75%6E%69%6F%6E select 1,2,3呢这里%75%6E%69%6F%6E是union的URL编码。服务器收到后进行一次URL解码得到1 union select 1,2,3依然会被拦截。关键在于双重编码。我们提交id1 %2575%256E%2569%256F%256E select 1,2,3。注意看这里%25是百分号%本身的URL编码%-%25。第一次解码服务器服务器看到%2575将其解码为%75。同理其他部分解码为%6E、%69等。此时参数变为1 %75%6E%69%6F%6E select 1,2,3。过滤逻辑检查这个字符串里面没有明文union只有%75%6E...因此绕过成功。第二次解码可能发生在数据库连接层或框架自身有些应用程序库或后续处理逻辑可能会意外地再次对已解码的参数进行URL解码这是一种不规范但可能存在的处理。于是%75%6E%69%6F%6E被第二次解码还原为明文union。最终拼接到SQL语句时就成了1 union select 1,2,3注入成功。实战示例与注意点 假设目标URL为http://target.com/page.php?idPAYLOAD过滤规则过滤union,select,from等关键字。构造Payload1and12%2555%254E%2549%254F%254E%2553%2545%254C%2545%2543%25541,2,version--这里%2555%254E...是UNION的双重编码U-%55-%2555。是URL编码的空格%20的替代有时过滤规则可能不检查。实操心得双重URL编码绕过的成功率取决于目标应用是否有“二次解码”的行为。在测试时可以先尝试对单个字符如空格%20变成%2520进行双重编码观察页面响应是否正常以此探测是否存在这种特性。此外并非所有工具都默认支持双重编码Burp Suite的Decoder模块或CyberChef是手动构造和测试多重编码Payload的利器。3.2 十六进制编码绕过十六进制编码绕过主要应用于绕过对引号的过滤尤其是在magic_quotes_gpc开启或使用了addslashes函数的环境下它转义了单引号‘使其变成\导致字符串闭合失效。原理 MySQL等数据库支持十六进制字面量。字符串‘admin’可以用十六进制表示为0x61646D696E。当SQL语句中使用0x...时数据库引擎会直接将其解释为对应的字符串完全不需要单引号。这就完美避开了对引号的检查和转义。实战示例与注意点 假设登录查询语句为SELECT * FROM users WHERE username‘$_POST[user]‘ AND password‘$_POST[pass]‘且使用了addslashes转义。正常注入思路被阻断useradmin‘--会被转义为admin\--导致语法错误。十六进制绕过我们不知道管理员密码但想绕过密码检查。可以构造useradmin‘ AND 11--但引号会被转义。此时我们可以将整个用户名条件用十六进制表示。计算admin的十六进制admin-0x61646D696E。Payload:user0x61646D696E OR 11-- passanything最终SQL变为SELECT * FROM users WHERE username0x61646D696E OR 11-- ‘ AND password‘anything‘由于0x61646D696E被解析为字符串admin且后面跟了OR 11永真条件成立从而绕过认证。更常见的用法是在UNION注入中查询information_schema时绕过对库名、表名的引号过滤UNION SELECT 1,group_concat(table_name),3 FROM information_schema.tables WHERE table_schema0x64767761这里的0x64767761就是数据库名dvwa的十六进制形式。重要注意事项十六进制编码绕过的核心在于Payload中的关键字本身如SELECT, UNION并没有被编码编码的只是我们想要作为数据部分传入的字符串如表名、库名。因此如果过滤规则是直接匹配union、select这些关键字十六进制编码字符串数据是无济于事的需要结合其他方法如大小写、双写来绕过对关键字的过滤。3.3 Unicode编码绕过这种绕过方式高度依赖于Web服务器或应用框架自身对Unicode字符的规范化处理常见于IIS ASP/ASP.NET环境有时也出现在一些能解析Unicode的Java或PHP应用中。原理 攻击者可以在Payload中插入Unicode转义序列如%u0053代表大写字母S。如果Web服务器如IIS在将请求参数传递给后端脚本语言之前主动将这些Unicode序列解码为对应的ASCII字符而后端过滤代码检查的是解码前的字符串那么就能实现绕过。实战示例与注意点 假设一个ASP站点过滤了select关键字。原始Payload?id1 union select 1,2,3会被拦截。Unicode变形Payload?id1 union s%u0065lect 1,2,3%u0065是字母e的Unicode编码。如果IIS服务器接收到此请求可能会将s%u0065lect规范化还原为select然后才交给ASP脚本处理。但ASP脚本中的过滤逻辑如果只是简单匹配参数字符串中的s%u0065lect由于它不是完整的select因此被放过。而数据库最终接收到的是经过IIS解码后的select注入成功。实操心得Unicode绕过具有很强的环境特异性。在测试时可以使用Burp Suite的Intruder模块配合包含各种Unicode变形字符的字典进行Fuzz测试。例如将关键字中的每个字母都替换为其Unicode全角形式或零宽字符变体有时也能起到奇效。但需要注意的是现代WAF和框架对此类攻击的防护已经越来越强。3.4 宽字节注入GBK编码绕过宽字节注入是编码绕过中原理最独特、也最经典的一种它利用的是数据库连接字符集如GBK、BIG5与Web应用层字符集如UTF-8不一致或数据库自身对多字节字符的解析特性。原理 以最常见的GBK宽字节注入为例。GBK是一种双字节编码一个汉字由两个字节组成。当数据库连接使用GBK字符集而PHP开启了magic_quotes_gpc或使用了addslashes函数时单引号‘会被转义为\即\\的ASCII码是0x5C。攻击者精心构造一个Payload使得转义符\0x5C与前一个字节由我们控制组合在GBK编码下被解释为一个合法的汉字从而“吃掉”了转义符让后面的单引号成功逃逸闭合了字符串。经典Payload分析 假设查询语句为SELECT * FROM users WHERE id‘$_GET[‘id’]‘ LIMIT 1且使用了addslashes。我们输入id1‘ AND 11--addslashes处理1\ AND 11--单引号前加了反斜杠\。如果我们输入id1%df‘ AND 11--%df‘经过URL解码为0xDF。addslashes处理在‘前加\变成0xDF0x5C0x27即%df%5c%27。关键步骤当数据库连接字符集为GBK时它会将%df%5c这两个字节当作一个双字节字符来解析。在GBK编码表中0xDF5C对应汉字“運”具体汉字因编码表而异。于是数据库看到的字符串变成了1運‘ AND 11--。转义符\0x5C被“吞并”了单引号‘0x27得以暴露成功闭合了前面的字符串并开始了新的注入语句。实战示例与注意点检测在可能存在字符转义的地方提交%df‘观察是否报错。如果报错信息与编码相关或页面显示异常则可能存在宽字节漏洞。利用一旦确认存在就可以使用%df‘来闭合字符串进行后续的联合查询、报错注入等操作。防御根本的防御方法是统一整个应用的字符集为UTF-8并在数据库连接时使用SET NAMES ‘utf8‘或mysql_set_charset(‘utf8‘)确保字符集一致。使用预处理语句PDO参数化查询可以从根本上免疫此类注入。深度剖析宽字节注入不限于%df任何高位为1ASCII值大于128的字节与0x5C组合在GBK编码下都可能形成一个汉字。常见的测试字符包括%81到%FE。此外这种思路可以扩展如果过滤的是其他字符如‘被转义为\‘也可以寻找能“吞掉”\的编码组合。4. 编码绕过的组合拳与实战场景在实际的渗透测试中单一的编码绕过技术往往不足以突破层层防御。高手通常需要根据实际情况灵活组合多种技术。4.1 场景一综合过滤关键字引号空格假设一个目标存在以下过滤过滤union,select,from等关键字不区分大小写。使用addslashes转义单引号。过滤空格。我们的绕过思路可能是绕过关键字过滤使用双重URL编码或大小写混合。例如将union写为%2555%254E%2549%254F%254E双重编码的UNION或UnIoN。绕过引号过滤在需要字符串的地方如数据库名使用十六进制编码。例如database()的结果如果需要比较可以用hex()函数转为十六进制再比较或者直接使用0x...形式。绕过空格过滤使用/**/MySQL注释符、%0a换行符、%09制表符或括号()来替代空格。构造一个复杂的Payload示例 原始注入语句1‘ union select 1,table_name from information_schema.tables where table_schemadatabase()--绕过后的可能形态1%df‘/**/%2555%254E%2549%254F%254E/**/%2553%2545%254C%2545%2543%2554/**/1,table_name/**/%2546%2552%254F%254D/**/information_schema.tables/**/%2557%2548%2545%2552%2545/**/table_schema0x[当前数据库名的十六进制]--这个Payload同时运用了宽字节(%df‘)、双重URL编码关键字、注释符代替空格(/**/)和十六进制编码数据库名。4.2 场景二针对WAF的编码混淆现代云WAF通常具备多层解码和语法分析能力。对抗它们需要更巧妙的混淆。多重编码嵌套对Payload先进行Base64编码再进行URL编码甚至混合HTML实体编码。前提是目标应用存在相应的解码逻辑链。非常规字符插入在关键字中插入不影响数据库解析但能干扰WAF正则表达式的字符。例如利用MySQL的特性在关键字中插入/*!50000*/内联注释仅当MySQL版本大于等于5.00.00时执行其中的内容如uni/*!50000*/on sel/*!50000*/ect。这严格来说不是编码但属于字符变形常与编码结合使用。协议层面混淆在HTTP协议层面使用Transfer-Encoding: chunked分块传输或者对参数名本身进行编码可能绕过一些基于正则匹配的WAF规则。5. 防御视角如何应对编码绕过了解了攻击手法从防御者角度我们可以制定更有效的策略使用预处理语句参数化查询这是唯一从根本上杜绝SQL注入的方法。它将SQL语句结构与数据参数完全分离无论参数中包含什么编码、什么字符都只会被当作数据处理而不会被解析为SQL语法。这是最高优先级的防御措施。统一字符集确保Web应用前端、后端逻辑、数据库连接三者的字符集完全一致推荐使用UTF-8并在连接数据库后立即执行SET NAMES ‘utf8mb4‘或对应驱动的方法。最小化解码应用程序只应在明确的、必要的地方进行一次解码。避免对用户输入进行多次、非预期的解码操作。白名单过滤对于已知有限集合的输入如状态、类型使用白名单验证只允许预期的值。对输入进行规范化在过滤之前先对输入进行标准化Canonicalization。例如将URL编码、Unicode编码等统一解码为最简单的形式然后再进行关键字或危险字符检查。但这种方法需要处理所有可能的编码变体容易有遗漏。使用成熟的Web框架和安全库现代框架如Spring Security, Laravel, Django通常内置了经过良好测试的防护机制比自己手写过滤更可靠。WAF作为纵深防御在应用前部署WAF可以拦截大量已知攻击模式。但需知WAF可被绕过不能作为唯一防线。编码绕过的艺术本质上是攻击者与防御者对数据流理解深度的较量。掌握这些区别与原理无论是为了更有效地进行安全测试还是为了构建更坚固的防御体系都至关重要。在实际操作中耐心、对细节的观察如错误信息、页面差异以及一个系统的测试流程比记住所有Payload更重要。