RCE关键词绕过实战指南:从过滤原理到Payload构造

发布时间:2026/10/20 23:10:50
RCE关键词绕过实战指南:从过滤原理到Payload构造 直接说结论在授权渗透测试和CTF里遇到RCE漏洞却因为关键字过滤打不出shell或者命令执行结果出不来是最常见的“卡壳”场景。所谓RCE绕过之关键词绕过本质不是跟过滤规则硬碰硬而是摸清目标过滤逻辑的边界再用命令解析器本身的语言特性找出路。这篇文章我把关键词绕过的完整思路拆开讲从过滤规则的实现原理、绕过手法的分类到真实案例的构造过程以及踩坑记录全部分享出来给正在做Web安全研究、打CTF比赛或者做代码审计的朋友提供一个可以直接参考的路线图。1. 先把问题说清楚关键词过滤到底拦住了什么1.1 一个典型场景命令执行点就在那里但参数被卡死了很多人在实战里都遇到过这种页面输入框提交一个参数后端直接拼进了系统命令里执行比如通过system()、exec()这类函数调用了系统命令业务功能可能是一个ping测试工具或者一个在线转换器。按理说这是一个标准的命令注入点但当你尝试输入ls或者id的时候返回结果却是空的甚至直接报错。继续测试你会发现后台大概率做了关键词过滤。比较常见的过滤写法是黑名单把ls、cat、id、whoami这类高危命令直接禁掉或者把|、、;这些命令分隔符替换成空字符串。更严格一点的还会用正则表达式做匹配只要请求参数里命中敏感词就拒绝执行。这就是“关键词绕过”要解决的典型问题命令注入的入口是通的但载荷payload被卡住了必须想办法让载荷在绕过过滤规则的同时仍然能被执行器正确解析。1.2 过滤规则的实现方式决定了绕过空间有多大理解绕过之前要先理解过滤逻辑是怎么写的。我见过太多防御方把过滤当成“查字典”写一个黑名单数组再拿用户输入去in_array或者str_replace。这种过滤的逻辑缺陷非常明显——它只能挡掉开发者预先想到的写法而命令解释器本身支持的语法特性远超普通开发者的认知范围。常见的过滤实现有这几种字符串替换型比如把|替换成空把替换成空但只替换一次或者不区分大小写。正则匹配型用preg_match做黑名单匹配但正则写法本身可能存在漏洞比如没有加i修饰符就漏掉了大小写绕过或者没有用^和$做锚定导致匹配范围出现偏差。白名单型只允许特定格式的输入这个最麻烦但也最不常见因为业务功能一般很难做到这么严格。我在实际的代码审计中观察到一个规律过滤规则越复杂反而越容易出现绕过。原因很简单复杂的过滤逻辑往往叠加了多层转换比如先urldecode再str_replace如果替换顺序和解析顺序不一致就会产生时间差这个时间差就是绕过空间。说到这必须先强调一句下面所有技巧请务必用于授权测试、CTF竞赛、自建靶场或漏洞研究任何未经授权对真实系统的探测都是违法行为。1.3 绕过思路的内核找到“等价输入”关键词绕过的核心不是“骗过正则”而是找到一种目标命令解析器能理解、但过滤规则不认识的等价表达。就好比你跟门禁保安说“我是员工”被拦下来但你说“我是技术部的王工”他就放行了——同一个意思不同的表达方式而门禁系统只认了他预设的那几个关键词。这个“等价表达”从哪里来答案藏在系统命令解释器的语法特性里。Linux的Shell和Windows的CMD各自都有大量的语法糖、转义机制、变量展开规则、通配符匹配规则。这些规则不是为了绕过过滤而存在的它们是系统原本就提供的正常功能。过滤规则在关键词层面做匹配却没有在语法层面做解析两者之间天然存在认知差。所以做关键词绕过的第一步是先判断目标环境是Linux还是Windows。这直接决定了你能用哪一类语法特性。比如Linux下可以用$IFS代替空格可以用通配符匹配命令名而Windows下可以用脱字符^、百分号变量展开两种环境的绕过路径完全不同。2. 命令分隔符与空格的绕过把“一条命令”拆成“多条等效命令”2.1 分隔符被过滤之后命令拼接还有没有戏最常见的过滤是禁掉命令分隔符比如|、、;、||、。很多初学者到这里就卡住了觉得命令注入必须有分隔符才能拼接第二条命令。实际上思路不该停留在“拼接命令”而应该考虑“让同一段输入被解析成多条命令”。先看Linux环境。除了常见的;、|、之外还有两个容易被忽视的换行符%0a和回车符%0d。在URL里提交参数时如果后端没有过滤换行符%0a可以让Shell把输入当成多条命令执行。比如注入点原本拼的是ping -c 1 {input}提交127.0.0.1%0aidShell执行完ping之后接着执行id效果等同用分号分隔。再看Windows环境。CMD的分隔符家族包括、、|、||其中是最宽松的不管前一条命令成功失败都会执行后一条。如果过滤规则只禁了|和却漏了单独的那绕过就很简单了。还有一个冷门的CMD里可以用for /f封装整段命令执行这个在绕过层不太好用但在构造复杂payload时很实用。2.2 空格被过滤Linux的$IFS、截断符号和Windows的特殊处理比分隔符更常见的过滤是空格因为大多数命令注入的payload都要靠空格来分隔命令和参数。过滤规则如果只删空格很多人会直接放弃实际上Linux Shell提供了至少三种替代方案。第一种是$IFS。Shell的字段分隔符环境变量默认包含空格、Tab、换行在命令行里可以用$IFS直接代替空格。比如cat /etc/passwd写成cat$IFS/etc/passwd。注意要小心$IFS后面如果直接跟字母Shell会把变量名解析成IFSxxx所以更稳妥的写法是${IFS}。第二种是Tab。如果过滤规则只处理了空格字符没有处理%09Tab那cat%09/etc/passwd也能执行。第三种是Linux的路径通配符加参数拼接这个后面在通配符部分细讲。Windows环境下的空格替换相对麻烦一点CMD没有$IFS这种变量。但有一个思路用CMD的变量解析特性把空格拆进变量里比如set a;copy file1 %a%file2这种。还有一个更常见的做法是用%Path:~x,y%这种子串截取的语法来构造出空格字符原理稍后在变量拼接部分展开。2.3 分隔符过滤的漏网之鱼编码与URL双重解码很多过滤逻辑只处理了原始请求里的文本却忽略了Web服务器和中间件的解码机制。比如你提交%26后端如果先做了一次URL解码再交给过滤函数那过滤看到的还是但如果过滤函数在解码之前执行就会漏掉这个编码后的分隔符。这种场景在真实环境里特别多见。很多框架的过滤逻辑是写在业务代码里的而URL解码是Web容器层的动作两者之间存在时间顺序差。我遇到过一个系统过滤逻辑放在$_POST取值之后但某些接口接受JSON格式的Content-TypeJSON里的\u0026会被解析成直接绕过了前面的字符串替换。所以做绕过测试时第一件事不是构造复杂payload而是试一遍各种编码方式URL编码、二次编码、Unicode编码、HTML实体编码。有时候过滤规则并不弱只是它的执行时机晚于解码时机整个防线就漏了。3. 命令与参数的关键词绕过变量、拼接、通配符、引号的组合拳3.1 大小写、引号与反斜杠最容易被忽略的基础手法如果过滤规则只是简单匹配了命令字符串没有加大小写不敏感修饰符那Linux下的cat可以写成CAT、Cat、cAt因为Linux的文件系统区分大小写但命令名本身是由Shell去PATH路径里查找的PATH路径下的命令大小写固定所以CAT不一定能执行。不过在部分BusyBox环境或某些工具里命令解析对大小写的容忍度不同值得一试。Windows则完全相反CMD不区分命令大小写所以直接改成CaT或者CAT就能绕过低级的大小写过滤。引号也是一个好工具。在Shell中cat、cat、c\at最终都会被解析成cat因为引号会被Shell剥掉但过滤规则如果直接在原始字符串里搜索cat就搜不到cat。这种方法的优点是不会改变命令本身执行结果和原命令完全一致。反斜杠更巧妙因为反斜杠是Shell的转义符c\at里反斜杠转义的是a但转义一个普通字母不会改变其本身含义最终命令名仍然是cat。在Windows的CMD里脱字符^也有类似的“转义普通字符不改变含义”的能力所以c^at也可以。3.2 变量拼接把关键词拆成碎片再组合这是实战里最实用的一类思路。原理很简单如果直接写cat被拦那就先给变量赋一部分值再用变量拼接出完整命令。Linux下可以写成ac;bat;$a$b /etc/passwd但需要注意这种写法在普通的Shell命令注入里不一定能直接执行因为ac;bat;$a$b /etc/passwd里用了分号和空格如果分隔符也被过滤就不行了。另一个更隐蔽的方式是用环境变量截取$0: # 取出当前Shell的名称常用于获取/bin/sh的路径比如/???/???写法配合$0去拼接命令。这里不展开太多。更常见的变量拼接场景是在Windows里。CMD的%变量:~起始位置,长度%语法可以从环境变量中截取任意子串比如%PATH:~0,1%取的就是PATH环境变量的第一个字符。如果目标环境是Windows可以用这个方式拼出空格、字母甚至构造完整命令set awho set bami %a%%b%这个思路的核心价值在于过滤规则匹配的是原始输入文本但执行器解析的是变量展开之后的结果。两者看到的内容完全不同。3.3 通配符模糊匹配不写关键字也能命中命令通配符绕过是我个人非常喜欢的一种手法因为它在某些场景下几乎是无解的——除非过滤规则把*、?、[这些字符也都禁掉但禁掉之后业务功能往往就废了。Linux Shell的通配符有三种*匹配任意长度字符?匹配单个字符[...]匹配字符组。假设过滤规则禁掉了cat这个字符串你可以写/bin/c?t /etc/passwdShell在解析时会自动匹配到/bin/cat并执行。如果/bin/也被禁了可以写成/???/? ?t这种风格前提是你得清楚目标系统的标准路径结构。经典案例是cat /etc/passwd写成/bin/c?t /etc/passwd如果.,/,;这些符号没有被完全过滤甚至可以写成???/???/????但这种方式风险很大因为通配符匹配可能命中多个文件比如???可以匹配bin、dev、etc等等导致命令行为不可控。所以我更推荐有明确路径前缀的写法先缩小匹配范围再让通配符只匹配需要变化的那个字母。3.4 编码绕过八进制、十六进制与Base64编码绕过的思路完全不一样不是改变命令的书写方式而是让Shell或CMD自己“解码”出一段命令再执行。Linux下最直接的是$\x68...这种ANSI-C引号转义可以在bash里构造任意字符串。例如$\x63\x61\x74就是cat。这种手法的特点是过滤规则搜索的是原始文本里的ASCII字符串而转义序列在文本层面完全不包含目标关键字。Windows下常见的是使用certutil或powershell -enc来执行Base64编码的命令但这两个工具本身可能被列入黑名单。不过还有一个小众思路CMD的for /f配合type读文件内容然后当命令执行相当于把payload写进文件再让系统去读。Base64思路的本质是“把命令执行过程拆成两段先解码后执行”。但要注意很多过滤规则已经意识到Base64是重灾区所以base64命令名、-d参数、|分隔符这些都会连坐过滤。遇到这种情况可以尝试把base64命令本身也做一次变量拼接或通配符匹配。3.5 正则缺陷绕过利用匹配边界的空隙还有一种情况是过滤规则用了正则表达式但正则本身写得不严谨。举例来说黑名单正则/ls|cat|id/i没有加单词边界那写在cat两边的任意字符都不影响匹配这个没法绕。但如果写法是/\bls\b|\bcat\b|\bid\b/i看似加了边界却可能漏掉了以特殊字符作为分隔的payload比如${IFS}cat$IFS/etc/passwd中间用了空格或变量边界依然会命中。真正能绕过的是利用正则的回溯或者字符类特性比如宽字节、超长字符串导致正则引擎拒绝服务从而跳过检查——这个在真实环境里不常见但CTF里偶尔能碰到。这里说一个实际可用的思路如果过滤正则只匹配了纯字母命令那就把命令名和参数之间加入Shell支持的特殊字符例如cat${IFS}/etc/passwd、cat$IFS$1/etc/passwd其中$1表示位置参数值为空但Shell语法上它隔断了命令名与参数过滤正则如果只按“命令名字符串”匹配可能就把cat单独摘出来了不会命中cat /etc/passwd这种完整字符串。这个思路和单引号类似但更隐蔽。4. 实操案例复现从过滤规则到payload的完整构造过程4.1 模拟靶场环境介绍以下所有案例都在本地自建的模拟项目X靶场里验证不要在未经授权的系统上测试。靶场是一个简单的PHP页面接收cmd参数并传给system()执行前端是一个ping测试功能?php $cmd $_GET[cmd]; if (preg_match(/ls|cat|id|whoami|;||\|| /i, $cmd)) { die(forbidden); } echo shell_exec(ping -c 1 . $cmd); ?这个示例模仿了最常见的过滤逻辑正则匹配黑名单同时禁掉了常见的分隔符和空格。4.2 案例一空格被过滤用$IFS完成命令执行直接测试发现输入127.0.0.1 id会被拦因为正则里的/ /匹配到了空格。尝试127.0.0.1$IFS id发现$IFS后面的空格还是触发了正则。这里要说明$IFS只是替代了命令参数之间的空格但如果你在$IFS后面又手写了一个空格那还是会被匹配。正确写法是127.0.0.1$IFS$IFSid注意两个$IFS之间不能再有多余空格。这个payload在靶场上能成功执行id原因很简单过滤正则匹配的是原始输入字符串原始输入里没有空格字符Shell展开变量后却产生了空格。如果目标接口在URL传输层把$过滤了可以换一种思路用Tab字符的URL编码%09提交127.0.0.1%09id同样能避开空格过滤。4.3 案例二命令名被过滤用引号切割绕过当前过滤正则禁了cat和ls等命令名字符串。需要读取/etc/passwd但cat /etc/passwd里的cat会被拦截。构造如下127.0.0.1$IFS$IFScat$IFS/etc/passwd执行时Shell把cat解析成cat但原始输入里并没有连续的cat子串。实测下来正则不命中命令正常执行。原理上Shell的单引号不是用来界定字符串的它只是告诉Shell“引号内的字符不要做特殊解释”当引号被剥离后单个字符自然拼接成了cat。同样的方式可以推广到任意被禁命令包括id写成id、whoami写成whoami。这个方法在Linux Shell和很多PHP的system()调用场景下都有效因为底层用的都是/bin/sh。4.4 案例三分隔符被过滤用换行符绕过在上面的靶场里分号、管道符、都被禁了。这种情况下想连续执行多条命令可以试换行符。URL编码的换行是%0a提交127.0.0.1%0aidPHP的shell_exec执行ping -c 1 127.0.0.1之后Shell会把换行当作命令分隔符继续执行id。实测结果中执行完ping之后会多输出一段id的结果。这个手法的前提是过滤正则里没有包含\n或者\r的匹配很多基于字符串数组的黑名单确实不会处理换行符。4.5 案例四过滤规则做了全局替换用变量拼接绕过再换个示例。假设后端不是正则拦截而是用类似str_replace的方式把cat替换成空$cmd str_replace(cat, , $cmd); echo shell_exec(ping -c 1 . $cmd);这种过滤比正则更容易绕过因为替换是一次性的、可预测的。构造127.0.0.1$IFS$IFScatt原始输入里有cat被替换后剩下的字符串是cat因为catt去掉中间cat四个字符后正好剩下cat。这种“替换一次之后正好拼出命令”的思路遇到只替换一次的黑名单非常有效。如果替换逻辑不区分大小写还可以写成cATt或者CatT替换后剩余部分一样能凑出关键字。这个案例提示一个防守方很容易犯的错过滤的次数、方向、上下文没有考虑周全导致替换结果本身成了可被利用的注入源。4.6 实操中的参数构造细节这里补充几个实际构造payload时容易忽略的细节URL传参时$、/、?、都可能被前端框架或WAF拦先用curl直接构造请求绕过浏览器层面的干扰。如果目标运行在Windows上$IFS完全无效改用%Path:~0,1%构造空格或^转义。过滤规则禁了空格但没禁Tab时URL编码的%09是好东西。如果输出回显被过滤可以通过sleep这类时间延迟命令做盲注判断比如127.0.0.1$IFS$IFSsleep$IFS5观察响应时间是否延长5秒。5. 常见问题排查与防护视角5.1 排查清单payload没生效时该往哪个方向查绕过失败的时候大多数人第一反应是“换个更复杂的payload”但更高效的做法是先定位卡点。根据我的经验按下面这个顺序排查能在五分钟内找到八成的问题第一确认执行环境。同一个payload在Linux和Windows下的表现完全不同先确认目标是什么系统再看用的是/bin/sh还是/bin/bash还是cmd.exe。可以通过提交echo $0或者whoami的变体来指纹识别。第二确认过滤发生在哪一层。请求先经过Web应用防火墙WAF还是业务代码层面的正则还是两者都有判断方法很简单提交一个明显不合法的输入观察拦截面返回的报错格式。如果返回的是统一拦截页面多半是WAF如果返回的是业务逻辑报错或拼接后的命令执行报错就是业务代码层过滤。第三确认是否有二次解码。把payload做两层URL编码再提交一次如果这次绕过了说明前面有一层decode发生在过滤之前编码后的内容没有进入过滤匹配的文本流。这个现象特别常见。第四确认特殊字符是否被HTML实体化转义。有些框架会对用户输入做htmlspecialchars处理单引号、双引号、都变成了实体Shell自然解析不了。5.2 从绕过视角反推什么样的过滤规则才是真正有效的说了半天怎么绕最后还是回到防御视角。我做过不少代码审计发现很多开发者的过滤逻辑是“抄来的”没有理解过滤的本质。真正有效的关键词过滤要满足三个条件首先是白名单优先。如果业务只需要IP参数那就严格校验输入必须匹配IP格式所有其他输入一律拒绝。这是当前最可靠的做法。黑名单无论如何完善都只能挡住已知的绕过方式而Shell和CMD语法特性极多黑名单很难穷尽。其次是语义解析而不是字符串匹配。也就是说不要只检查“输入里有没有cat”而要解析“这段输入最终会执行哪些命令”。这类做法在单机上可以用命令解析器模拟执行在Web层可以用沙箱执行一次来验证结果。很多WAF的检测引擎已经朝这个方向演进但业务代码层的过滤往往还在用最原始的字符串匹配。最后是纵深防御。就算过滤逻辑再强也不要指望它百分百拦得住。把Web服务的系统权限降低、把命令执行的函数替换成更安全的调用方式、启动行为检测监控异常命令执行这些措施比一个更长的黑名单更有价值。5.3 个人经验总结做RCE关键词绕过的研究其实最能提升的是对命令解析机制的理解。很多技巧在真实渗透测试里未必用得上因为真实环境有WAF、有纵深防御、有各种业务限制但理解这些绕过路径能让你知道一道防线是怎么被突破的反过来写防护方案的时候就不会再写那种形同虚设的黑名单了。我在自己搭的靶场里把过滤规则从简单到复杂加了好几轮每加一层过滤就会催生新的绕过方式。这个过程很像下棋一方出招另一方拆招真正有价值的是你逐渐摸清了对手命令解析器的完整规则集。最后分享一个小技巧搭建自己的本地靶场把不同的过滤逻辑写成插件每研究出一种新的绕过方式就加进笔记里长期积累下来再遇到真实场景时你根本不需要背payload看一眼过滤规则就能大概猜到哪条路能走通。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询