CTF命令注入实战:绕过空格与关键词过滤的Shell技巧

发布时间:2026/7/20 14:06:07

CTF命令注入实战:绕过空格与关键词过滤的Shell技巧
1. 项目概述一次典型的命令注入挑战在CTFCapture The Flag夺旗赛的Web安全赛道上命令注入Command Injection是经久不衰的经典题型。它模拟了攻击者如何通过Web应用接口将恶意系统命令“注入”到后端服务器执行的过程。最近我在一个靶场里遇到了一个名为“Level7”的关卡它的防护机制很有意思不仅过滤了“flag”这个关键词还过滤了空格。这直接堵死了新手最常用的cat flag.txt或ls -la这类命令。乍一看好像路被堵死了但恰恰是这种限制逼着我们深入理解Shell解释命令的底层逻辑去挖掘那些平时被忽略的“语法糖”——Shell通配符和命令分隔符。这个关卡的核心就是考察选手在命令执行上下文受限时如何灵活运用Shell本身的特性来绕过过滤。它不只是一个简单的技巧罗列更是一次对Shell元字符Metacharacters和单词分割Word Splitting机制的实战演练。无论是准备CTF比赛还是想在渗透测试中应对更严格的WAFWeb应用防火墙规则掌握这些绕过技巧都至关重要。接下来我就结合Level7的实战场景把这几种“真香”的技巧掰开揉碎了讲清楚让你不仅能解出这道题更能理解其背后的原理举一反三。2. 环境与挑战深度解析2.1 靶场场景与过滤机制模拟假设我们面对的是一个简单的Web应用它有一个输入框允许用户输入一个主机名或IP地址进行Ping测试。后端PHP代码可能如下所示?php $host $_POST[host]; // 关键过滤逻辑 if (preg_match(/flag| /i, $host)) { die(非法输入); } // 拼接命令并执行 system(ping -c 1 . $host); ?代码逻辑非常清晰用户输入的$host变量经过过滤后被直接拼接进system()函数执行。过滤规则/flag| /i使用了正则表达式其中flag匹配任何位置的“flag”字符串不区分大小写i修饰符。空格匹配空格字符。|表示“或”的关系。这意味着任何包含“flag”或空格的输入都会被拦截。我们的目标就是在这种过滤下成功执行系统命令例如cat /flag或find / -name *flag*来读取目标文件。2.2 绕过思路的核心理解Shell的解析过程要绕过过滤我们不能和过滤规则硬碰硬而是要思考Shell是如何理解我们输入的一串字符的当system(‘ping -c 1 ‘ . $host)执行时PHP会将拼接好的字符串交给系统的Shell通常是/bin/sh去解释执行。Shell在解析命令时会经历几个关键步骤词法分割TokenizationShell会根据特定的分隔符元字符将命令行字符串分割成一个个独立的“单词”token。最常用的分隔符就是空格和制表符。展开Expansion在分割后Shell会对每个token进行各种展开例如通配符展开*,?,[]、变量替换$VAR等。命令执行将展开后的第一个token作为命令后续的作为参数去执行。我们的绕过技巧就围绕“如何在不使用空格的情况下让Shell正确分割命令与参数”以及“如何在不直接输入‘flag’的情况下定位到目标文件”这两个核心问题展开。3. 绕过空格过滤分隔符的魔法空格被过滤了我们就需要寻找Shell认可的、能替代空格功能的其他分隔符。这些字符在Shell解析的早期阶段起作用将命令和参数区分开。3.1 利用大括号{}构造命令大括号{}在Shell中是一个强大的构造工具它可以生成字符串列表。在命令执行的上下文中它可以巧妙地“包裹”命令其内部的逗号或未被转义的空格有时能起到分隔作用但更常用的技巧是结合其他方法。一个更直接利用{}进行无空格连接的方法是将命令和参数作为一个整体字符串然后通过Shell的字符串拼接特性来执行。但更经典的是使用{cmd,arg}的形式不过注意这通常需要后续的展开。在简单的命令注入中我们可以这样尝试原型的思路如果过滤了空格但没过滤{和}我们可以尝试构造如{cat,/flag}。然而这并不直接执行需要配合其他技巧。实际上更常见的用法是作为命令的一部分进行通配符测试。对于空格绕过下面这些是更直接有效的分隔符。3.2 使用IFS内部字段分隔符变量IFS是Shell的一个特殊环境变量它定义了用于单词分割的字符列表。默认值是空格、制表符和换行符。我们可以通过引用IFS变量来替代空格。方法一直接使用$IFScat$IFS/flag当Shell解析cat$IFS/flag时会先进行变量替换将$IFS替换成默认的分隔符空格等。由于替换发生在词法分割之后不这里需要澄清一个关键点在大多数Shell中变量替换发生在词法分割之后实际上顺序是1.分词基于原IFS2.变量替换3.再次分词如果替换结果包含IFS字符。但当我们使用$IFS时如果它没有被引号包裹且其值包含空格那么在变量替换后这个空格会成为一个分词点。因此cat$IFS/flag在替换后变成cat /flag从而成功分割。方法二使用{IFS}或IFS的字符串表示有时$符号也可能被过滤我们可以尝试用其他方式表示空格。但更直接的是使用其ASCII码或十六进制值。cat${IFS}/flag${IFS}是变量替换的标准形式和$IFS效果类似但有时能绕过对$后接特定字符的简单过滤。实操心得在实战中$IFS是绕过空格过滤的首选方案之一因为它非常短且通用。但需要注意有些靶场或WAF可能会将$IFS作为一个整体字符串进行过滤。此时可以尝试变体如$IFS$9$9通常是一个空的位置参数用于拼接或者使用{IFS}。3.3 使用重定向符或作为“隐形”分隔符这是一个非常巧妙且容易被忽略的技巧。Shell在解析命令时重定向符号,,,及其后面的文件名是一个独立的token。更重要的是重定向符号本身就可以作为命令与参数之间的分隔符即使后面没有紧跟空格。cat/flag这行命令的意思是将/flag文件作为标准输入stdin重定向给cat命令。Shell在解析时会将cat、和/flag识别为三个独立的token从而在没有空格的情况下成功将/flag作为参数实际上是重定向的文件传递给cat。cat命令会从标准输入读取内容而标准输入被重定向到了/flag文件于是文件内容就被打印出来。同理你也可以使用读写方式打开cat/flag注意事项这个方法要求你对目标文件有读取权限。它完美避开了空格因为语法本身就不需要空格虽然我们习惯性会加上。在许多简单的字符串匹配过滤中和常常不被列入黑名单。3.4 利用命令替换$()或反引号 “ 产生空格命令替换会将一个命令的输出结果嵌入到当前命令行中。如果替换的结果包含空格那么这个空格是在变量替换阶段之后产生的有可能绕过早期的字符串过滤。例如我们可以构造一个输出为空格的命令cat$(echo)/flag$(echo)执行echo命令但echo不带参数时默认输出一个空行严格来说是输出一个换行符但可能不产生空格。这个方法不太稳定。一个更可靠的方法是使用printfcat$(printf$IFS )/flag # 或者更直接的 X$(echo$IFS );cat${X}/flag但这样构造略显复杂且可能引入更多被过滤的字符。在Level7这种简单过滤下通常不是最优解但它展示了思路的多样性。3.5 使用Tab键%09 URL编码或换行符在Web输入中空格通常被编码为%20或。如果后端只过滤了字面空格 那么制表符TabASCII码9URL编码为%09或换行符\nURL编码为%0a可能可以充当分隔符。Tab%09在Shell中Tab和空格一样是默认的IFS分隔符。cat%09/flag在Burp Suite或浏览器地址栏中需要输入%09换行符%0a换行符也是默认的IFS并且会终止当前命令开启下一条命令。这可以用于执行多条命令但要注意上下文。cat%0a/flag这可能会被解析为两条命令cat和/flag后者会报错“/flag: 没有那个文件或目录”因为/flag被当作命令执行了。更常用的方式是;cat%0a/flag # 或者利用换行符直接注入新命令 ping%0acat /flag常见问题使用Tab或换行符绕过时务必注意后端接收参数的方式。如果使用$_GETURL编码会自动解码如果使用$_POST且代码未做特殊处理可能需要直接插入原始字符在Burp中修改原始请求体。此外一些过滤逻辑可能会用\s匹配所有空白字符来正则匹配这样Tab和换行符也会被过滤。4. 绕过“flag”关键词过滤通配符的智慧现在我们已经能在命令中插入“空格”了但直接输入cat /flag还是会被“flag”这个词拦住。这时就需要请出Shell通配符Wildcards了。通配符在Shell进行路径名展开Pathname Expansion时使用发生在命令执行之前。4.1 问号?匹配单个字符?代表任意一个字符。如果我们知道flag文件的完整路径和名称比如就是/flag那么?用处不大。但很多时候flag文件可能叫flag.txt、flag.php、.flag或者放在一个包含“flag”的目录里。假设我们不确定文件名但知道它在根目录且文件名类似flagcat /fla?这可以匹配/flag如果它存在的话。如果flag文件是flag.txt则需要cat /fla?.txt。?的优势是精确匹配一个字符适合知道大致文件名但有一两个字符不确定的情况。4.2 星号*匹配任意数量字符*是最强大、最常用的通配符代表零个或多个任意字符。场景一直接匹配目标文件如果flag文件就在当前目录或指定目录且名称中包含“flag”cat /fl*这行命令会展开为所有以/fl开头的文件。如果根目录下只有/flag这一个匹配项那么命令就等价于cat /flag。如果有多个如/flag、/flashcat会依次读取所有文件flag内容也会被打印出来可能夹杂其他文件内容。场景二结合路径模糊查找如果不知道flag在哪可以用*进行递归查找虽然效率低但在CTF靶场里目录通常不深find / -name *flag* 2/dev/null这里*flag*会匹配路径名中任意位置包含“flag”的文件。2/dev/null是为了将错误信息如权限不足丢弃让输出更干净。找到文件后再用cat命令读取。场景三无字面“flag”读取这是绕过过滤的关键。既然不能出现“flag”我们就用纯通配符来匹配它。cat /f*如果根目录下唯一的以/f开头的文件就是/flag那么这条命令就成功了。同理可以尝试cat /fla* cat /*lag cat /fl?g你需要根据目标系统的实际情况来猜测。在CTF中出题人往往会设置一个相对孤立的文件让这种模糊匹配能够成功。4.3 方括号[]指定字符范围[]用于匹配方括号内的任意一个字符。它可以用来绕过对特定字符的过滤或者进行更精确的匹配。例如假设过滤了字母g我们可以尝试cat /fla[f-h] # 或 cat /fla[abcdefghijklmnopqrstuvwxyz]这看起来有点傻但展示了可能性。更实用的场景是当我们知道flag文件名是“flag”但不确定某个字母的大小写虽然Linux通常区分大小写时可以用[fF][lL][aA][gG]。不过在绕过关键词过滤时[]通常不如*和?直接有效。4.4 利用Shell变量和展开绕过如果通配符也被部分过滤例如过滤了*我们可以考虑更高级的技巧。例如利用Shell的参数展开来拼接字符串。afl;bag;cat /$a$b这里我们将“fl”和“ag”分别赋值给变量a和b然后通过$a$b拼接成“flag”。这完全避免了在命令行中直接出现“flag”字符串。同理也可以使用子Shellcat /$(echo fl)$(echo ag)核心技巧在Web命令注入中使用变量拼接通常很有效因为输入是一整条命令字符串。你可以将 payload 构造为host;afl;bag;cat /$a$b。注意这里用分号分隔了多条命令。5. 组合拳实战攻克Level7现在我们将空格绕过和“flag”关键词绕过的技巧组合起来形成完整的攻击链。假设Level7的输入点就是上文提到的host参数。攻击链设计思路终止预期的ping命令。注入我们自己的命令该命令需要读取flag文件。新命令中不能包含空格和“flag”字面量。Payload 构造示例方案一使用$IFS和*通配符host127.0.0.1;cat$IFS/fl*127.0.0.1;首先ping一下127.0.0.1满足原程序逻辑分号;用于结束前一条命令开始下一条命令。cat$IFS/fl*cat命令用$IFS代替空格用/fl*匹配根目录下以fl开头的文件假设flag文件是/flag。方案二使用重定向符和通配符host127.0.0.1;cat/fl*这里甚至不需要任何形式的分隔符变量直接利用的语法特性。/fl*会被Shell解析为重定向操作/fl*展开为目标文件。方案三使用Tab%09和变量拼接在Burp Suite的Repeater模块中修改HTTP请求体POST /level7.php HTTP/1.1 ... host127.0.0.1;cat%09/fl$u$v$w$x$y$z这里我假设过滤了“ag”但我们可以用一堆无关变量来“稀释”。更实际的变量拼接是host127.0.0.1;ffl;gag;cat$IFS/$f$g方案四综合运用使用命令替换生成空格和路径host127.0.0.1;cat$(printf$IFS )/fl*这个payload略显复杂但展示了在极端情况下组合各种技巧的可能性。实战步骤信息收集首先尝试正常输入127.0.0.1观察返回确认命令注入点是否存在如返回时间延迟、报错信息等。测试分隔符尝试输入127.0.0.1;ls$IFS/或127.0.0.1;ls%09/查看是否能列出根目录确认空格绕过方法是否有效。测试通配符尝试输入127.0.0.1;ls$IFS/fl*查看返回结果中是否包含疑似flag的文件名。构造最终Payload确认绕过方法有效后组合分隔符和通配符构造读取文件的命令如127.0.0.1;cat$IFS/fl*。获取Flag提交Payload在响应中查找flag字符串。6. 防御视角与进阶思考从攻击中学习防御。作为开发者如何防止这种绕过白名单校验对于主机名、IP地址这类输入最有效的是白名单校验或严格的正则匹配如IP地址格式只允许预期的字符集。避免命令拼接绝对不要将用户输入直接拼接到系统命令中。使用安全的API如PHP的escapeshellarg()或escapeshellcmd()但要注意它们并非银弹在复杂场景下仍可能有问题。最佳实践是使用语言提供的特定功能库如PHP的filter_var($ip, FILTER_VALIDATE_IP)验证IP。使用参数化接口如果必须执行系统命令应使用能够将参数与命令分离的接口如Python的subprocess.run([‘ping’, ‘-c’, ‘1’, host])而不是拼接字符串。深度过滤与过滤顺序如果不得不使用黑名单过滤规则需要非常全面。不仅要过滤空格还要过滤$IFS、、、;、|、、$()、反引号、*、?、[、]等所有Shell元字符。并且过滤应在转义或编码处理之后进行且最好进行多次、多层次的检查。最小权限原则运行Web服务的进程应使用最低必要的权限避免使用root权限。这样即使被注入攻击者能造成的破坏也有限。从CTF选手角度看遇到更复杂的过滤怎么办例如同时过滤了空格、$、{、}、、等。这就需要更奇技淫巧比如利用未初始化的变量在某些Shell中未定义的变量展开为空。可以尝试cat${x}/flag如果x未定义则${x}为空但语法上可能造成分割这通常不行。更可行的是利用$或$*等特殊参数。利用引号如果过滤了空格但没过滤引号可以cat”/flag”但这通常需要空格实际上cat”/flag”会被认为是一个单词。可以尝试cat””/flag或cat’‘/flag利用空字符串连接在某些Shell中可能被解析为两个词这并不总是有效强烈依赖于Shell的解析器。编码绕过将命令进行Base64或Hex编码然后通过解码执行。例如echo$IFSY2F0IC9mbGFnCg|base64$IFS-d|sh其中Y2F0IC9mbGFnCg是cat /flag的base64编码。这需要系统中有base64和sh命令。这些进阶技巧就像是你的“武器库”了解的越多在面对不同“防御工事”时你就有越多的破解思路。Level7这样的关卡正是训练你灵活运用这些基础武器的最佳沙场。掌握它们你不仅能解决这一道题更能建立起应对未来更复杂Web安全挑战的底层思维模型。

相关新闻

终极指南:如何使用HackBrowserData跨平台提取与解密浏览器数据

终极指南:如何使用HackBrowserData跨平台提取与解密浏览器数据

2026/7/20 14:06:07

终极指南:如何使用HackBrowserData跨平台提取与解密浏览器数据 【免费下载链接】HackBrowserData Extract and decrypt browser data, supporting multiple data types, runnable on various operating systems (macOS, Windows, Linux). 项目地址: https://gitco…

如何快速实现渐进式图片加载:vue-progressive-image与Vue 3 Composition API的完美结合

如何快速实现渐进式图片加载:vue-progressive-image与Vue 3 Composition API的完美结合

2026/7/20 13:56:07

如何快速实现渐进式图片加载:vue-progressive-image与Vue 3 Composition API的完美结合 【免费下载链接】vue-progressive-image Vue progressive image loading plugin 项目地址: https://gitcode.com/gh_mirrors/vu/vue-progressive-image 在现代Web开发中…

【2026年】伺服减速机背隙是什么意思?

【2026年】伺服减速机背隙是什么意思?

2026/7/20 13:56:07

一、引言在伺服驱动系统的选型和技术交流中,"背隙"(Backlash)是一个出现频率极高的参数。它直接影响到设备的定位精度、换向响应和加工质量,但不少工程师对这个概念的理解停留在"越小越好"的层面,…

如何用Python自动化工具实现B站会员购抢票:终极完整指南

如何用Python自动化工具实现B站会员购抢票:终极完整指南

2026/7/21 8:07:14

如何用Python自动化工具实现B站会员购抢票:终极完整指南 【免费下载链接】biliTickerBuy b站会员购购票辅助工具 项目地址: https://gitcode.com/GitHub_Trending/bi/biliTickerBuy B站会员购抢票总是一票难求?手动操作总是慢人一步?今…

基于STM32单片机智能无线点餐物联网餐厅菜谱无线WiFi/蓝牙/视频监控APP设计DIY-T168

基于STM32单片机智能无线点餐物联网餐厅菜谱无线WiFi/蓝牙/视频监控APP设计DIY-T168

2026/7/21 8:07:14

本系统由STM32F103C8T6单片机核心板、无线蓝牙/WIFI模块-可选、TFT1.44寸彩屏液晶显示电路、蜂鸣器报警驱动电路、按键电路及电源电路。注意视频监控及WIFI套餐才拥有视频监控(含WIFI功能)!【1】硬件相当于服务员手持终端点餐器,上位机APP(即手机)相当于饭店结算下单…

Windows Hello生物识别技术解析与配置指南

Windows Hello生物识别技术解析与配置指南

2026/7/21 8:07:14

1. Windows Hello生物识别技术解析Windows Hello是微软在Windows 10中引入的生物特征认证系统,它彻底改变了传统密码验证方式。作为系统级的身份验证框架,它通过三种主要方式实现安全登录:指纹识别、面部识别和PIN码。这项技术并非简单的硬件…

C++实现MFCC特征提取:从原理到工程实践

C++实现MFCC特征提取:从原理到工程实践

2026/7/21 8:07:14

1. 项目概述:从声音到数字的桥梁做语音相关的项目,无论是识别、合成还是分类,第一步永远绕不开特征提取。你把一段原始音频波形直接扔给模型,效果通常不会太好,因为波形数据包含了太多冗余信息,比如环境噪音…

数据恢复工具选择与实战技巧指南

数据恢复工具选择与实战技巧指南

2026/7/21 8:07:14

1. 文件恢复工具的核心价值与选择逻辑 当你在深夜赶工的重要文档被误删,或是清理磁盘时不小心格式化了存有珍贵照片的分区,那种头皮发麻的窒息感我深有体会。作为经历过数十次数据抢救的老手,可以明确告诉你:90%的误删文件都能完整…

嵌入式系统高速启动:GPIO与XINTF并行引导模式深度解析

嵌入式系统高速启动:GPIO与XINTF并行引导模式深度解析

2026/7/21 7:57:14

1. 项目概述与引导模式核心价值 在嵌入式系统开发中,Bootloader(引导加载程序)是系统上电后运行的第一段代码,其重要性不亚于应用程序本身。它就像一位尽职尽责的“系统唤醒师”,负责在CPU从复位状态苏醒后&#xff0c…

微服务进阶:服务网格与Istio

微服务进阶:服务网格与Istio

2026/7/21 5:45:57

541|微服务进阶:服务网格与Istio 上篇文章我们聊了微服务的基本概念和拆分方法。 但微服务多了,问题也多了: 服务之间怎么通信? 怎么监控每个服务的调用链路? 熔断、限流、重试怎么做? 安全认证怎么统一? 以前这些都靠SDK库(比如Hystrix、Feign),每个服务都要集成…

零售超级终端全域协同:ShareKit 碰一碰商品流转业务落地案例

零售超级终端全域协同:ShareKit 碰一碰商品流转业务落地案例

2026/7/20 2:33:13

一、零售门店全域协同业务背景与行业痛点 1.1 门店超级终端设备矩阵(连锁便利店/商超标准配置) 自助收银Kiosk一体机:顾客结算、自助核销优惠券、商品素材预览;运营折叠平板:店长后台商品上新、图片录入、活动配置、…

噗叽短视频界面分析

噗叽短视频界面分析

2026/7/21 3:09:32

1 和小红书类似,可以采用类似判断方法------------其实他比小红书好判断,因为他没有图片,控件位置几乎是固定的,都不用判断------------2 因为他没有点赞按钮------------而且几乎所有控件位置都是完全一样的,所以我就…

GraphRAG Local + Ollama:微软知识图谱本地化

GraphRAG Local + Ollama:微软知识图谱本地化

2026/7/21 0:06:35

普通 RAG 有个老毛病:你问它「这堆文档整体在讲什么」,它答不上来。因为它只会把问题切成向量,去几十个文本块里捞最相似的几段拼给模型看。可「整体讲什么」这种问题,答案根本不在任何单独一段里——它散在全篇的联系里。 微软的…

AI 数据产品化思考:让分析能力变成可售卖的数据服务

AI 数据产品化思考:让分析能力变成可售卖的数据服务

2026/7/21 0:06:35

AI 数据产品化思考:让分析能力变成可售卖的数据服务 大家好,我是朱大喜。这周一直在复盘具体的项目和技术,最后一篇聊点不一样的东西——数据产品化。做了这么多年数据分析,我发现一个规律:能卖出去的从来不是"分…

基于人机协作的 AI 研发新体系架构:从 Harness 工程到 Loop 工程实践

基于人机协作的 AI 研发新体系架构:从 Harness 工程到 Loop 工程实践

2026/7/21 0:06:35

本文完整呈现了企业级 AI Coding 落地的核心方法论:从 Harness 工程的微观/宏观定义,到 Loop 工程的六大构建模块,再到基于 SDD(规范驱动开发)的工程化落地路径。干货较多,建议收藏细读。 我从 22 年开始就…