SQL注入绕过技术全解析:从编码变形到协议层攻击实战

发布时间:2026/7/26 7:55:26
SQL注入绕过技术全解析:从编码变形到协议层攻击实战 1. 项目概述为什么“绕过”是SQL注入的核心进阶技能如果你已经接触过WEB安全或者玩过一些CTF靶场那么“SQL注入”这个词对你来说肯定不陌生。简单来说就是攻击者通过在用户输入中插入恶意的SQL代码欺骗后端数据库执行非预期的命令。新手入门时往往是从‘ or ‘1’‘1这种万能密码开始的。但现实中的安全防护尤其是WAFWeb应用防火墙和开发者自写的过滤逻辑早已不是这种简单字符串匹配就能对付的了。这就引出了我们今天要深入探讨的核心SQL注入的绕过手法。这绝不是为了炫技而是安全测试人员、渗透测试工程师乃至开发者在构建更健壮防御时必须掌握的一课。当你发现一个输入点存在注入嫌疑但常规的union select、and 11直接被拦截或过滤时真正的较量才刚刚开始。理解绕过就是理解防御方的思路从而找到其思维和实现上的盲点。无论是CTFshow、DVWA、Pikachu这些经典靶场还是真实世界的渗透测试绕过手法的精熟程度直接决定了你的测试深度和成功率。本专题旨在系统性地拆解SQL注入中常见的绕过技术。我们不只讲“怎么做”更要深挖“为什么能这么做”以及在实际场景中如何组合运用这些技巧。从基础的编码绕过到利用数据库特性、逻辑缺陷再到高阶的混淆变形我们将逐一剖析并提供可直接复现的测试用例和思考逻辑。2. 绕过手法核心原理与分类框架在开始具体手法之前我们必须建立一个清晰的认知框架。所有的绕过手法本质上都是基于一个核心矛盾应用程序或WAF的过滤/检测逻辑与数据库SQL解析引擎的逻辑存在差异。防御方在代码层或网络层对输入进行清洗和检查但最终这个输入要拼接成SQL语句交给数据库如MySQL、MSSQL、PostgreSQL去解析执行。如果我们的恶意载荷能“骗过”前者的检查同时又能被后者正确理解那么绕过就成功了。基于这个原理我们可以将绕过手法分为以下几大类2.1 基于编码与特殊字符的绕过这是最基础也最常用的一层。防御方可能只过滤了某些关键词的空格或特定写法但我们可以用其“等价形式”来替代。原理利用URL编码、HTML编码、数据库字符集等多种编码方式或使用特殊字符作为分隔符改变payload的“面貌”使其对检测引擎不可读但对数据库解析器依然有效。关键点需要了解不同环节浏览器、服务器中间件、应用代码、数据库对数据的解码顺序和规则。2.2 基于SQL语法特性的绕过数据库为了兼容性和灵活性其SQL语法解析往往比我们想象中更“宽松”。这留下了许多可乘之机。原理利用数据库对大小写不敏感、注释符的灵活使用、内联注释、字符串拼接、特殊运算符等特性构造出语法正确但形态异常的SQL语句。关键点需要熟悉目标数据库的具体方言和特性。MySQL、MSSQL、Oracle的绕过技巧常有不同。2.3 基于逻辑与协议层的绕过这类手法跳出了单纯的payload变形从请求的整体逻辑和传输协议上寻找突破口。原理例如利用HTTP参数污染HPP、请求方法转换GET/POST互换、多部分表单数据Multipart编码、以及慢速攻击等干扰WAF的检测逻辑使其无法正确提取或关联待检测的参数。关键点需要对HTTP协议和WAF的工作原理有较深理解。2.4 混淆与变形技术这是绕过现代AI或语义分析型WAF的进阶手段。原理通过插入大量无意义的空白、注释、换行或者将关键字拆散如SEL/**/ECT甚至使用动态查询执行如MySQL的PREPARE和EXECUTE语句使得payload在静态分析下难以识别。关键点目标是增加payload的熵破坏基于正则表达式或简单模式匹配的检测。注意在实际测试中很少单独使用某一种手法。一个成功的绕过payload通常是多种技术的组合拳。例如可能先通过HPP将参数拆散然后对关键参数进行URL双重编码最后在SQL语句中使用内联注释替换空格。3. 编码与特殊字符绕过实战详解让我们从最实操的部分开始。假设我们面对一个简单的登录框后端SQL语句可能是SELECT * FROM users WHERE username ‘$user‘ AND password ‘$pass‘防御方在$user处过滤了空格和union、select等关键字。3.1 URL编码绕过这是网络传输中最天然的“伪装”。浏览器会自动对URL中的特殊字符进行编码服务器端通常会解码一次。但如果WAF检测在解码前而应用代码在解码后拼接SQL就存在绕过可能。常规注入admin‘ union select 1,2,3--过滤后union和空格被过滤。绕过尝试单次URL编码将空格 编码为%20单引号‘编码为%27。admin%27%20union%20select%201,2,3--%20但聪明的WAF会统一解码后再检测所以可能依然被拦。双重URL编码这是关键。对%20再进行编码%变成%25于是%20变成了%2520。admin%2527%2520union%2520select%25201,2,3--%2520如果WAF只做一次解码它看到的是admin%27%20union...其中的%27和%20可能不会被识别为关键词。而应用服务器如Apache/PHP可能会进行第二次解码还原出admin‘ union select...成功注入。实战心得双重编码在针对老旧WAF或自定义过滤逻辑时非常有效。使用Burp Suite的Decoder模块可以轻松进行多次编码解码操作。3.2 十六进制与Unicode编码绕过主要用于处理关键字和字符串值。十六进制绕过MySQL中字符串可以用十六进制表示0x开头。例如select可以写成selselectect然后通过十六进制替换中间被过滤的select不更直接的是用十六进制表示整个查询值。假设我们要注入的字段值是admin可以写成0x61646D696Eadmin的十六进制。在注入时admin‘ and password0x...可以绕过对字符串‘admin‘的过滤检查。更高级的可以将整个SQL语句部分进行十六进制编码配合EXECUTE执行。Unicode编码在某些上下文如JSON、宽字节注入环境中有效。例如单引号‘的Unicode编码是%u0027或%u02b9等变体。著名的“宽字节注入”就是利用了GBK等字符集下%df%27%df和%27会被数据库解析为一个汉字字符从而“吃掉”反斜杠转义符\%5c的原理。虽然这不完全是Unicode但属于字符集编码层面的绕过。关键点需要准确知道目标应用处理输入时使用的字符集。3.3 注释符与空白符替代空格是SQL注入中最常用的分隔符也是最常被过滤的。我们需要找替代品。MySQL注释符/**/是多行注释但在注入中常被当作可插入的“空白”使用。/*! ... */是内联注释其中的代码在MySQL中会被执行。空格绕过union/**/select/**/1,2,3内联注释妙用/*!union*/ select/*!1,2,3*/。某些WAF的规则可能不会匹配/*!和*/中间的内容。其他空白符%09(Tab)%0a(换行)%0b(垂直制表符)%0c(换页)%0d(回车)%a0(不换行空格)这些符号在SQL解析时大多被视为空白但一些简单的正则表达式\sunion\sselect可能只匹配标准的空格或%20。括号绕过在特定语法中括号可以用于分隔而不需要空格。例如在select之后直接跟括号包裹的字段。union(select(1),(2),(3))from(users)这在一些极端的过滤环境下可能有效。实操心得不要只尝试一种替代。用Burp Intruder加载一个包含各种空白符和注释符的字典对疑似注入点的参数进行模糊测试Fuzzing观察哪些符号能被系统接受且返回正常这是快速探测过滤规则的最佳实践。4. 利用SQL语法特性进行高级绕过当编码变形效果有限时我们需要更深入地利用数据库引擎自身的“宽容度”。4.1 大小写与关键字拆分大小写绕过最简单的UnIoN SeLeCT。对于不区分大小写的数据库如MySQL默认或不进行大小写归一化检测的WAF有效。关键字拆分用注释或空白将关键词拆开。uni/**/on sel/**/ectu%0bnion s%0belect(利用换行)更隐晦的U/*!00000NION*/ SE/*!00000LECT*/利用内联注释中的特定数字MySQL中/*!50001 ... */表示在MySQL版本5.00.01时执行这些数字和注释符本身构成了干扰。4.2 字符串拼接与等价函数替换字符串拼接如果union和select被整体过滤尝试用拼接构造它们。MySQL:concat(‘u‘, ‘nion‘)得到union。但注意这通常需要在已经可以执行SQL函数的环境下用于构造查询内容而非关键字本身。对于关键字更常用的是CHAR()函数。CHAR()函数将ASCII码转换为字符。union可以写成CHAR(117, 110, 105, 111, 110)即u117, n110, i105, o111, n110那么注入语句可能变成admin‘ and 11 and (CHAR(117, 110, 105, 111, 110) select ...)。这能绕过纯文本关键字匹配。等价函数/运算符替换and 11被过滤试试and 1 like 1、and 1 regexp 1、and true、and 1 in (1)。or ‘1‘‘1‘被过滤试试or ‘1‘ like ‘1‘、or ‘1‘ between ‘0‘ and ‘2‘。substring()被过滤试试mid()、substr()。*4.3 内联注释/*! .../的深度利用MySQL的内联注释是绕过利器因为它对数据库是“可见”的代码但对许多文本过滤器却是“注释”。版本特异性/*!50001 select * from users */只有在MySQL版本大于等于5.00.01时才会执行。这本身可以用于探测数据库版本也可以作为干扰。包裹整个语句可以将整个恶意SQL段包裹起来特别是当WAF以分号;或--作为语句结束标志进行分段检测时。id1/*!union/*!select/*!1,2,3*/;*/这种嵌套和分散的注释可能会破坏检测引擎的语法分析。4.4 利用数据库解析特性非常规语法浮点数表示法在MySQL中1‘1会被解释为浮点数1.1。这可以用于绕过对整数和字符串的简单类型判断。例如id1‘1‘可能被解析为id1.1如果字段是数值型可能会触发类型转换错误从而用于报错注入。科学计数法1e0表示数字1可以用于混淆。反引号与引号MySQL中可以使用反引号来包裹标识符如表名、字段名当单引号被过滤时可以尝试在特定上下文使用反引号但这通常用于字段名而非字符串值。5. 逻辑层与协议层绕过手法剖析这类手法跳出了SQL语句本身的变形从更上层寻找WAF或应用逻辑的漏洞。5.1 HTTP参数污染HPP原理当同一个参数名在HTTP请求中出现多次时不同的服务器端技术PHP、ASP.NET、J2EE等解析获取的参数值可能不同。WAF可能只检测第一个或最后一个值而应用程序实际使用的却是另一个。场景注入点在参数id上。正常请求GET /page.php?id1‘ and ‘1‘‘1HPP攻击请求GET /page.php?id1‘ and ‘1‘‘1id1PHP/Apache环境下通常取最后一个id值即1所以WAF检测第一个id恶意但应用使用第二个id正常攻击失败不这里需要策略。更有效的方式GET /page.php?id1id1‘ and ‘1‘‘1某些WAF可能只检查第一个id1干净就放行了整个请求。而PHP在$_GET[‘id‘]时如果收到多个同名参数行为取决于配置可能是第一个也可能是最后一个或者是数组。在$_REQUEST中顺序可能受request_order影响。通过模糊测试确定服务器行为是关键。实战技巧使用Burp Suite的“Param Miner”等扩展可以帮助自动探测HPP的可能性。在测试时要同时观察WAF的拦截日志和应用程序的实际响应判断哪个参数值真正生效。5.2 请求方法转换与参数隐藏GET/POST互换有些应用同时接受GET和POST方式传递参数但WAF可能只严格检查了其中一种通常是GET。如果一个注入点在GET请求中被拦截尝试将相同的参数和值放到POST Body中提交。参数置于非常规位置Cookie有些应用会将Cookie中的某些值用于数据库查询如会话标识、用户偏好。WAF对Cookie的检测可能弱于对Query String或Body的检测。HTTP Headers如X-Forwarded-For,User-Agent,Referer。这些头部信息有时会被记录到数据库如果过滤不严就可能成为注入点。测试时可以尝试在这些头部中插入探测载荷。JSON/XML参数注入现代API常使用JSON或XML传输数据。WAF可能配置了针对这些格式的解析器但如果解析配置不当攻击者可以通过破坏JSON/XML结构如未闭合的引号、多余的逗号将注入载荷“逃逸”到被解析的字符串中。例如提交{id”: “1‘ and ‘1‘‘1}如果后端直接拼接“1‘ and ‘1‘‘1”到SQL中且WAF未深入解析JSON值则可能绕过。5.3 分块传输编码Chunked Transfer Encoding这是一种HTTP协议特性允许客户端将请求体分块发送。有些WAF为了性能可能不会完整地重组和检查分块传输的请求体而是直接拦截或放行。通过构造特殊的分块数据可以将恶意payload隐藏在某个分块中以期绕过检测。实施此攻击需要手动构造复杂的HTTP请求通常借助Burp Suite的插件如“Chunked”插件来完成。5.4 慢速攻击Slow HTTP Attack严格来说这不完全是SQL注入绕过而是一种消耗WAF资源的攻击。通过极慢的速度发送HTTP请求例如每次只发送一个字节间隔很长可能使WAF的连接池耗尽或超时从而让后续的恶意请求在WAF“疲惫”或超时后直接到达应用服务器。这种手法更适用于混合攻击的场景。6. 混淆变形与自动化绕过思路面对越来越智能的WAF手动构造一个复杂的绕过payload效率低下。我们需要掌握一些系统性的混淆方法和自动化工具的思路。6.1 注释与空白混淆这是最基础的混淆目的是增加payload的“噪音”干扰基于正则表达式的检测。随机插入注释在SQL语句的各个位置随机插入/**/、/*!12345*/等。u/*random*/ni/*xyz*/on se/*aaa*/le/*bbb*/ct 1,2,3混合使用多种空白符不要只用%20或/**/混合使用%09,%0a,%0b,%0c,%0d,%a0。换行分割将一条完整的SQL语句分成多行发送。某些WAF可能按行检测而数据库的SQL解析器会忽略换行符。admin‘ and 11 union select database(),2,3 --6.2 语法等价替换与嵌套使用不常见的语法结构用SELECT * FROM (SELECT 1)a代替SELECT 1。用CASE WHEN ... THEN ... END代替if或and条件判断。用LIKE ‘%‘代替‘%‘。嵌套查询与别名大量使用子查询和别名增加语句复杂度。SELECT (SELECT column_name FROM (SELECT 1)a)6.3 利用数据库预编译语句的动态执行这是非常高级的绕过方式适用于已经有一定注入能力能执行多语句或特定函数的环境。MySQL PREPARE/EXECUTESET sql CONCAT(‘S‘,‘ELECT * FROM users WHERE id ‘, ‘1‘); PREPARE stmt FROM sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;在这个例子中恶意的SELECT语句是通过CONCAT函数在运行时拼接的然后通过PREPARE准备EXECUTE执行。在静态分析或简单匹配下CONCAT的参数是分散的字符串极难被检测为SQL注入。6.4 自动化工具与模糊测试手动尝试所有组合是不现实的。安全研究人员通常会借助工具SQLMap Tamper脚本SQLMap内置了大量tamper脚本如space2comment.py,between.py,charencode.py它们能自动对payload进行各种编码和混淆。你可以组合使用多个tamper脚本例如sqlmap -u “target.com/page?id1“ --tamperspace2comment,charencode --level3 --risk3自定义模糊测试Fuzzing使用Burp Suite Intruder或自定义Python脚本针对一个已知的注入点用包含各种绕过技巧的字典如不同的编码、空白符、注释组合、语法变体去轮询测试观察哪些payload能返回正常的响应即未被过滤或拦截从而反推出过滤规则。WAF指纹识别与规则推测首先识别目标使用的WAF如Cloudflare, ModSecurity, 阿里云盾等。然后通过发送一些边缘case的payload如union select、union all select、union distinct select观察其拦截响应可以推测WAF规则的大致模式是匹配unionselect的组合还是匹配union后跟空格和select的特定模式从而有针对性地设计绕过。7. 实战案例串联与综合绕过思路让我们通过一个虚构但综合的场景将上述手法串联起来。假设目标URL为https://vuln.com/news.php?id1存在数字型注入但部署了某品牌WAF。7.1 初步探测与规则分析正常访问id1返回正常新闻。基础探测id1 and 11被WAF拦截。返回403或特定拦截页面。尝试编码id1%20and%2011同样被拦截。说明WAF解码后检测。尝试注释绕过空格id1/**/and/**/11成功页面正常。说明WAF对/**/的识别可能有问题或者其规则是匹配and后面紧跟空格和数字的模式。探测关键字过滤id1/**/union/**/select/**/1,2,3被拦截。说明union select作为组合被识别。7.2 逐步绕过拆分union selectid1/**/uni/**/on/**/sel/**/ect/**/1,2,3可能成功也可能失败。取决于WAF是否有关键字碎片检测。尝试大小写混合id1/**/UnIoN/**/SeLeCt/**/1,2,3被拦截。说明WAF做了大小写归一化。尝试内联注释id1/*!union*//*!select*/1,2,3被拦截可能/*!和*/本身被列入特征。尝试HPPid1id1/*!union*//*!select*/1,2,3。观察响应。如果WAF检查第一个id1干净就放行且应用使用第二个id值则可能绕过。假设这里应用使用了第一个id值攻击无效。换一种HPP方式id1/*!union*//*!select*/1,2,3id1。这次将恶意负载放在前面。如果WAF只检查最后一个参数则可能绕过。需要测试。结合编码与HPPid1%252f%252a%252a%252funion%252f%252a%252a%252fselect%252f%252a%252a%252f1,2,3id1。这里对/**/进行了双重URL编码/是%2f,*是%2a。%252f%252a%252a%252f解码一次后是%2f%2a%2a%2f即/**/。WAF如果只解码一次看到的是%2f%2a%2a%2f可能不将其识别为注释符。而应用服务器解码两次后得到/**/被数据库解析为空格。使用等价函数与CHAR()如果以上都失败考虑终极手段用CHAR()构造关键字。但前提是已经能执行函数。我们可以先测试函数是否可用id1/**/and/**/substring(‘abc‘,1,1)‘a‘。如果正常说明函数调用未被过滤。 然后尝试构造id1/**/and/**/(CHAR(117,110,105,111,110)/**/CHAR(115,101,108,101,99,116)/**/1,2,3)。这相当于union select 1,2,3。这个payload非常隐蔽但构造复杂。7.3 自动化工具辅助在手动找到一些有效载荷如/**/可替代空格后可以借助SQLMap的tamper脚本进行深度利用。使用space2comment.py脚本将空格转为/**/。结合randomcase.py对字母进行随机大小写变换。使用charencode.py进行URL编码。sqlmap -u “https://vuln.com/news.php?id1“ --tamperspace2comment,randomcase,charencode --level5 --risk3 --batchSQLMap会自动组合这些变形技术尝试绕过防护。8. 防御视角与总结反思作为一名渗透测试人员精通绕过的目的是为了更好地防御。从防御方来看如何构建难以绕过的SQL注入防护呢根本措施使用参数化查询预编译语句。这是唯一从根源上杜绝SQL注入的方法。将用户输入始终作为参数传递而非SQL语句的一部分。无论输入如何变形都无法改变查询结构。严格的输入验证与规范化在参数化查询的基础上实施白名单验证。对于已知类型如数字、特定枚举值进行严格匹配。对字符串进行规范化处理统一字符编码过滤或转义所有非预期字符。最小权限原则数据库连接账户应仅具有应用所需的最小权限如只有SELECT无DROP、UPDATE等。这样即使注入成功危害也有限。WAF的深度防御WAF规则需要不断更新并采用多层检测机制语义分析不仅仅匹配关键字而是尝试理解SQL语句的语法结构识别异常。规范化解码对输入进行多次、多种编码的解码直到最底层的形式再进行检测。行为分析监测异常的数据库查询模式如短时间内大量报错、异常的UNION查询、尝试访问information_schema等系统表。代码审计与安全测试定期进行白盒代码审计和黑盒渗透测试模拟攻击者的绕过手法主动发现漏洞。个人实操体会绕过的过程就像一场攻防博弈。没有永远有效的绕过技巧也没有绝对安全的防御。最重要的不是记住所有payload而是掌握其背后的思维模式寻找差异与盲点。差异存在于编码、解析、逻辑的各个环节盲点存在于规则覆盖不到的地方。在测试中保持耐心系统性地从简单到复杂进行尝试并善用工具进行模糊测试和辅助往往能发现意想不到的突破口。同时时刻从防御角度思考才能让你的安全技能更加全面和深入。真正的安全始于对攻击的深刻理解。