尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

SQLMap Tamper脚本:绕过WAF的Payload编码与混淆技术详解

SQLMap Tamper脚本:绕过WAF的Payload编码与混淆技术详解 1. 项目概述为什么我们需要Tamper脚本在渗透测试或者安全研究的过程中你肯定遇到过这种情况用SQLMap对一个看起来有注入点的URL一顿操作猛如虎结果返回的要么是“404 Not Found”要么是“检测到非法请求”甚至直接被目标网站的WAFWeb应用防火墙给拉黑了。这时候很多朋友的第一反应是“这站没注入”或者“SQLMap不行了”。其实问题很可能出在Payload上——你发送的SQL语句太“标准”、太“干净”了就像穿着正装去参加化装舞会一眼就被保安认出来并请了出去。SQLMap自带的Tamper脚本就是为你准备的一整套“伪装道具”。它的核心作用是在SQLMap生成的标准Payload基础上进行一层或多层的编码、混淆、变形从而绕过各种基于正则匹配或关键字过滤的防护机制。你可以把它理解为一个“Payload化妆师”把UNION SELECT这样的标准语句变成UnIoN/**/SeLeCt或者%55%4e%49%4f%4e%20%53%45%4c%45%43%54让WAF的规则引擎“脸盲”认不出它的真面目。我见过太多安全从业者包括一些有经验的朋友对Tamper脚本的使用还停留在“--tamperspace2comment”这种基础阶段或者干脆把所有脚本都堆上去碰运气。这不仅效率低下而且容易触发更高级别的防护规则。这篇指南的目的就是带你从“知道有这么个东西”到“理解它怎么工作”再到“能根据实际情况组合或编写自己的Tamper脚本”真正把Tamper脚本用活、用好。2. Tamper脚本的核心原理与工作机制要玩转Tamper脚本首先得明白SQLMap的注入流程和Tamper脚本在其中的位置。这能帮你理解为什么有时候脚本不生效以及如何更精准地使用它们。2.1 SQLMap的Payload生成与处理流程SQLMap的注入过程可以简化为以下几个核心步骤探测与指纹识别SQLMap首先会发送一些无害的探测请求判断目标是否存在注入点、数据库类型、版本等信息。Payload库匹配根据识别出的数据库类型如MySQL、MSSQL、OracleSQLMap会从其庞大的内置Payload库中选取适合当前注入类型布尔盲注、时间盲注、报错注入、联合查询等的模板。Payload渲染将模板中的占位符如[COLUMN]、[RANDNUM]替换为实际的值生成一个标准的、语法正确的SQL注入Payload。Tamper脚本处理关键环节如果用户指定了--tamper参数上一步生成的标准Payload就会依次传递给指定的Tamper脚本进行处理。每个脚本都是一个独立的Python模块其核心是一个tamper(payload, **kwargs)函数它接收原始Payload经过一系列字符串操作如替换、编码、插入后返回变形后的Payload。请求发送与结果判断将变形后的Payload嵌入到HTTP请求中可能是GET参数、POST数据、Cookie、HTTP头等发送给目标然后根据返回的HTTP响应内容、状态码、时间延迟等判断注入是否成功。注意Tamper脚本的处理是单向且链式的。假设你指定了--tamper “scriptA,scriptB”那么Payload会先经过scriptA处理其结果再交给scriptB处理。脚本的顺序非常重要错误的顺序可能导致Payload变得无效或更易被检测。2.2 Tamper脚本的两种主要绕过思路所有Tamper脚本的“魔法”都围绕着两种核心思路展开思路一绕过关键字过滤这是最常见的情况。WAF或应用程序的自定义过滤器会维护一个“黑名单”里面是SELECT、UNION、AND、OR、空格、引号等敏感词汇。Tamper脚本的任务就是用“障眼法”让这些词汇逃过检查。大小写变形randomcase.py脚本将SELECT随机变为SeLeCt或SELEct。对于仅进行简单大小写匹配的过滤器有效。关键字分割space2comment.py把空格变成/**/randomcomments.py在关键字中间插入/**/变成SEL/**/ECT。这利用了SQL解析器会忽略注释而字符串匹配规则可能要求连续匹配的特性。等价替换equaltolike.py把换成LIKEgreatest.py把换成GREATEST()函数。这需要目标SQL上下文支持这些等价写法。编码混淆base64encode.py、charencode.py对整个或部分Payload进行URL编码。这依赖于目标应用程序在将参数传递给SQL执行引擎前是否进行了URL解码。如果解码发生在WAF检查之后就能成功绕过。思路二绕过特定WAF的已知规则一些脚本是针对历史上某些WAF产品如ModSecurity、WebKnight、F5 BIG-IP的特定规则缺陷而编写的。它们更像是“特制武器”。利用解析差异apostrophemask.py用UTF-8全角引号‘代替ASCII半角引号。有些WAF的字符规范化处理可能漏掉全角字符而数据库却可能识别。添加“糖衣”sp_password.py在Payload末尾添加sp_password。这是针对MSSQL的因为MSSQL Server自身在记录日志时会对包含sp_password的语句进行模糊处理某些WAF可能模仿了这一行为而选择忽略。内联注释versionedmorekeywords.py、modsecurityversioned.py利用MySQL的特性在关键字前添加版本特定的注释如/*!50000SELECT*/。MySQL 5.0.0会执行注释中的内容而一些WAF可能不会解析这种复杂注释。理解这些原理后你就不会盲目堆砌脚本而是能像医生开药一样先“诊断”手工测试过滤了什么再“下处方”选择合适的Tamper脚本。3. 从入门到精通Tamper脚本实战使用全流程知道了原理我们进入实战环节。我将用一个模拟的、存在基础WAF的测试环境来演示完整流程。假设目标URL是http://test.vuln.com/product.php?id13.1 第一步手工探测与过滤分析关键在祭出SQLMap之前手工探测是必不可少的。这能帮你快速了解WAF的“脾气”。你需要一个能拦截和重放HTTP请求的工具比如Burp Suite。探测基础注入点发送id1正常返回。发送id1如果返回错误如500内部服务器错误或WAF拦截页面说明单引号被应用程序处理且可能触发SQL错误但也可能触发了WAF。发送id1 AND 11如果被拦截说明AND、或空格被过滤。发送id1 AND 12同样观察是否被拦截。识别被过滤的关键字符/词 这是选择Tamper脚本的依据。你需要系统地测试常见注入元素。空格尝试id1%201URL编码的空格。如果%20被拦截尝试、/**/、%0a换行、%0d回车、%09制表符。等号尝试id1 LIKE 1。引号尝试id1%27单引号、id1%22双引号。看看是否可以用%bf%27unmagicquotes.py的原理或十六进制编码绕过。关键字分别测试SELECT、UNION、FROM、WHERE、OR、AND。可以尝试大小写变体SeLeCt、内联注释/*!50000SELECT*/、拆分SEL/**/ECT。组合测试有时单个字符没事组合起来就被拦。例如单独SELECT和FROM可能没事但SELECT ... FROM这个模式就被拦了。实操心得我习惯在Burp Repeater里建一个列表把要测试的Payload逐个发送根据返回的HTTP状态码如403、200、响应长度和内容是否有“Blocked”、“Forbidden”等关键词来判断。记录下哪些被放行哪些被拦截。这个过程就像在绘制WAF的“安全地图”。3.2 第二步选择合适的Tamper脚本基于手工探测的结果我们可以有针对性地选择脚本。下面是一个快速选型指南过滤/拦截情况可能有效的Tamper脚本原理简述空格被过滤space2comment.py空格 -/**/space2plus.py空格 -space2hash.py空格 -#随机字符串%0Aspace2mssqlblank.py空格 - 其他空白符MSSQL等号被过滤equaltolike.py-LIKEgreatest.py-GREATEST()between.py-BETWEEN AND,-NOT BETWEEN 0 AND单引号被过滤apostrophemask.py-%EF%BC%87(UTF-8全角单引号)charencode.py/chardoubleencode.py对整个Payload进行URL编码unmagicquotes.py-%bf%27(宽字节注入)关键字被过滤randomcase.py随机大小写变换versionedmorekeywords.py在关键字前加MySQL版本注释randomcomments.py在关键字中插入/**/疑似特定WAFmodsecurityversioned.py针对ModSecurity的绕过bluecoat.py针对BlueCoat SGOS的绕过想增加混淆base64encode.pyBase64编码整个Payloadappendnullbyte.py在Payload末尾加空字节%00重要提示--identify-waf参数可以帮助识别WAF类型但并非100%准确。手工探测结合经验判断更可靠。3.3 第三步组合使用与调试单一脚本往往不够需要组合使用。组合的原则是先处理字符级过滤再处理关键字级过滤先进行编码混淆再进行结构变形。假设我们探测发现空格、等号、UNION和SELECT被过滤。一个可能的组合尝试是sqlmap -u http://test.vuln.com/product.php?id1 --tamperspace2comment,equaltolike,randomcase -v 3space2comment先把所有空格变成/**/。equaltolike再把其中的等号变成LIKE。randomcase最后对整体Payload进行随机大小写变换。使用-v 3详细等级3可以让SQLMap输出它发送的每一个Payload这是调试Tamper脚本组合是否有效的黄金手段。你可以在终端输出里看到类似这样的变形过程[14:20:33] [PAYLOAD] 1/**/AnD/**/11 [14:20:33] [PAYLOAD] 1/**/AnD/**/1 LIKE 1 [14:20:33] [PAYLOAD] 1/**/aNd/**/1 LiKe 1观察最终Payload是否符合你的预期是否绕过了手工测试时发现的过滤规则。常见问题如果组合脚本后注入仍然失败检查-v 3的输出。可能某个脚本把前一个脚本处理过的有效字符又改坏了。这时需要调整脚本顺序或者换用其他脚本。4. 高级技巧编写你自己的Tamper脚本当现有的Tamper脚本都无法满足需求或者你想针对某个特定的、奇葩的过滤规则时自己编写脚本就是终极解决方案。别担心编写一个基础的Tamper脚本比想象中简单。4.1 Tamper脚本的基本结构SQLMap的Tamper脚本都位于/tamper/目录下。每个脚本都是一个标准的Python文件。我们来看一个最简单的例子比如模仿space2comment.py#!/usr/bin/env python Copyright (c) 2006-2024 sqlmap developers (http://sqlmap.org/) See the file LICENSE for copying permission from lib.core.enums import PRIORITY __priority__ PRIORITY.NORMAL # 定义脚本优先级用于多个脚本时的默认排序 def dependencies(): pass # 这里可以定义脚本依赖比如需要某个特定的数据库类型 def tamper(payload, **kwargs): 这是核心函数接收原始payload返回处理后的payload。 kwargs 可能包含一些有用的上下文信息如 DBMS 类型。 if payload: # 最简单的替换将空格替换为注释符 /**/ retVal payload.replace( , /**/) else: retVal payload return retVal这就是一个完整可用的Tamper脚本了把它保存为my_space2comment.py放到SQLMap的tamper目录下就可以用--tampermy_space2comment来调用了。4.2 编写一个实用的自定义脚本绕过自定义关键字过滤假设我们遇到一个奇葩的WAF它把union select这个短语整体过滤了但单独过滤union或select。我们可以写一个脚本在union和select之间插入一个不起眼的、可被SQL解析器忽略的“脏数据”。#!/usr/bin/env python 自定义脚本在 UNION 和 SELECT 之间插入无效的数值表达式绕过整体短语匹配。 from lib.core.enums import PRIORITY import re __priority__ PRIORITY.NORMAL def dependencies(): pass def tamper(payload, **kwargs): if not payload: return payload # 使用正则表达式查找 union select (不区分大小写) # 并将其替换为 union/*123*/select其中/*123*/会被SQL解析为注释而忽略 # 注意这里使用 re.IGNORECASE 标志进行不区分大小写匹配 retVal re.sub(r(union)\s(select), r\1/*1337*/\2, payload, flagsre.IGNORECASE) # 为了更健壮也可以处理其他变体比如 UNION ALL SELECT retVal re.sub(r(union all)\s(select), r\1/*1337*/\2, retVal, flagsre.IGNORECASE) return retVal脚本解析import re导入正则表达式模块用于进行复杂的模式匹配和替换。re.sub(pattern, repl, string, flags)这是核心函数。patternr(union)\s(select)匹配“union”后面跟一个或多个空白字符再跟“select”。括号()用于创建捕获组。replr\1/*1337*/\2替换文本。\1代表第一个捕获组即union\2代表第二个捕获组即select。我们在它们之间插入/*1337*/。flagsre.IGNORECASE使匹配不区分大小写能匹配UNION SELECT、Union Select等。这个脚本将把union select user,pass from table变成union/*1337*/select user,pass from table。对于只匹配“union select”连续字符串的简单WAF规则这很可能就绕过去了。4.3 利用kwargs上下文信息编写更智能的脚本tamper函数接收的**kwargs参数包含一些执行上下文信息比如目标数据库类型kwargs.get(dbms)。我们可以利用这些信息让脚本针对不同数据库采取不同的混淆策略。#!/usr/bin/env python 智能脚本根据数据库类型采用不同的注释语法分割关键字。 from lib.core.enums import PRIORITY import re __priority__ PRIORITY.NORMAL def dependencies(): pass def tamper(payload, **kwargs): if not payload: return payload dbms kwargs.get(dbms, ).lower() retVal payload # 定义不同数据库的注释风格 comment_styles { mysql: /**/, # MySQL 多行注释 mssql: /**/, # SQL Server 也支持 /**/ oracle: --, # Oracle 单行注释 postgresql: --, # PostgreSQL 单行注释 } # 默认使用 /**/ style comment_styles.get(dbms, /**/) # 在常见SQL关键字后插入注释这里以SELECT为例 # 匹配 SELECT 后跟空格或括号等边界的情况 pattern r\b(select)\b(\s*) replacement r\1 style r\2 retVal re.sub(pattern, replacement, retVal, flagsre.IGNORECASE) return retVal这个脚本会根据目标数据库是MySQL还是Oracle自动选择使用/**/还是--作为插入的注释符使得生成的Payload更贴合目标数据库的语法提高绕过成功率。实操心得编写自定义脚本时一定要多用-v 3参数观察输出并用一个简单的本地测试环境比如DVWA、SQLi-Labs验证Payload的有效性。确保你的变形不会破坏SQL语句的原始语法逻辑。5. 实战案例绕过一个模拟的复合过滤WAF让我们通过一个综合案例串联前面所有知识。假设目标有如下过滤规则过滤select、union、from、where等关键字大小写不敏感。过滤空格和等号。过滤单引号。我们的绕过思路处理关键字使用randomcase.py进行大小写变形。但仅此可能不够因为有些WAF会做大小写归一化。我们可以结合versionedmorekeywords.py如果是MySQL用内联注释包裹关键字。处理空格使用space2comment.py将空格变为/**/。处理等号使用equaltolike.py将变为LIKE。处理单引号尝试charencode.py进行URL编码。如果不行尝试unmagicquotes.py针对开启了magic_quotes或类似转义的场景。构造SQLMap命令 由于versionedmorekeywords.py和randomcase.py都作用于关键字需要注意顺序。通常先进行结构性的注释包裹再进行大小写变换。sqlmap -u http://target.com/page?id1 \ --tamperversionedmorekeywords,space2comment,equaltolike,charencode,randomcase \ -v 3 \ --dbmsmysql \ --techniqueB \ # 假设使用布尔盲注 --batch命令解析versionedmorekeywords首先将SELECT等关键字变成/*!50000SELECT*/。space2comment将上述结果中的空格包括注释内的空格这里要注意脚本可能不会处理注释内的内容需要测试变成/**/。equaltolike将变成LIKE。charencode对整个字符串进行URL编码。这会编码所有字符包括注释符和关键字。randomcase最后对编码后的字符串进行大小写变换注意randomcase对已经URL编码的字符串大部分是%加两个十六进制数字作用有限因为%和数字不变只变字母。这个顺序可能不是最优的。可能需要调整顺序比如把randomcase放在charencode之前。通过-v 3观察Payload的演变如果发现某一步变形导致Payload无效就需要调整脚本顺序或更换脚本。这个过程是迭代和实验性的。6. 常见问题、排查技巧与高级注意事项即使掌握了所有技巧实战中依然会踩坑。下面是我总结的一些常见问题及解决方法。6.1 常见问题速查表问题现象可能原因排查步骤与解决方案使用Tamper脚本后注入完全没反应连初始探测都失败1. Tamper脚本破坏了Payload的基本SQL语法。2. 脚本执行顺序导致最终Payload格式错误。3. 目标对某种变形如特定编码本身就有过滤。1. 使用-v 3查看最终Payload复制到Burp Suite中手工测试验证其语法和是否被拦截。2. 尝试只使用一个最简单的脚本如space2comment逐步添加定位问题脚本。3. 检查目标是否对/**/、、%0a等替换字符本身有过滤。注入能探测到但无法提取数据Dump失败1. 关键字过滤不彻底SELECT、FROM等在数据提取阶段被过滤。2. Payload长度或复杂度触发了WAF的二次检测或速率限制。3. Tamper脚本导致某些函数如substring(),mid()变形后失效。1. 在数据提取阶段--dump使用-v 3观察Payload看是否有关键字被拦截。2. 使用--delay参数降低请求频率避免触发速率限制。3. 尝试使用--hex或--no-cast等参数改变数据提取方式。同一个Tamper脚本组合有时成功有时失败1. WAF可能有学习模式或动态规则多次相似请求触发升级防护。2. 脚本中的随机化因素如randomcase,space2hash中的随机字符串导致某些变体被拦。3. 目标服务器负载均衡不同后端节点的WAF策略略有差异。1. 在SQLMap中使用--random-agent和--proxy轮换IP或User-Agent模拟不同来源请求。2. 对于含随机化的脚本尝试固定随机种子需修改脚本源码或换用非随机化脚本。3. 使用--flush-session清除会话重新开始测试。手工测试Payload能绕过但SQLMap不行1. SQLMap注入的上下文如User-Agent、Cookie、其他参数触发了WAF。2. SQLMap默认使用更“激进”的Payload即使经过Tamper变形其模式仍被识别。3. Tamper脚本未应用到所有类型的Payload上SQLMap有多种注入技术。1. 使用--user-agent、--cookie等参数模拟手工测试时的请求头。2. 使用--level和--risk参数从最低级别开始测试。3. 指定--technique为手工测试成功的那种注入类型如--techniqueB布尔盲注。6.2 高级注意事项与心得不要过度依赖Tamper脚本Tamper脚本主要针对基于模式匹配的传统WAF。对于基于语义分析、机器学习或RASP运行时应用自保护的现代防护体系简单的字符串变形很难奏效。此时需要更高级的技巧如时间盲注、二阶注入、或者寻找WAF规则之外的攻击面。理解“混淆”与“有效性”的平衡越复杂的混淆越可能绕过WAF但也越可能破坏SQL语句的语法或者被目标应用程序的输入处理逻辑如多次解码、过滤意外“修复”成危险语句。务必在测试环境中验证混淆后Payload的有效性。善用SQLMap的其他参数Tamper脚本不是孤立的结合其他参数效果更好。--prefix和--suffix手动指定Payload的前缀和后缀有时能解决闭合问题。--tamper与--eval--eval允许你使用Python表达式在每次请求前动态修改参数比Tamper更灵活可以处理一些依赖上下文的复杂变形。--mobile、--random-agent模拟移动端或随机化User-Agent绕过一些基于客户端特征的简单封禁。保持脚本更新与社区学习WAF规则在更新绕过技术也在发展。多关注SQLMap的官方更新/tamper/目录会新增脚本以及安全社区如Seclists、Exploit-DB分享的新型WAF绕过技巧。理解这些技巧的原理你就能编写出属于自己的“武器库”。合法授权是前提所有技术都应在拥有明确书面授权的渗透测试或安全研究环境中使用。未经授权对他人系统进行测试是违法行为。Tamper脚本是SQLMap这把“瑞士军刀”上非常锋利的一个组件。从机械地使用到理解原理再到能自定义脚本解决问题这个过程本身就是对Web应用防火墙机制和SQL注入原理的深入理解。希望这篇指南能成为你从“脚本小子”迈向真正安全研究者的垫脚石。记住工具是死的人是活的最强大的Tamper脚本永远是你善于分析和思考的大脑。
返回列表