RCE-labs(Level6-13):从字符绕过到无字母命令执行的实战演进

张开发
2026/4/11 5:17:06 15 分钟阅读
RCE-labs(Level6-13):从字符绕过到无字母命令执行的实战演进
1. RCE靶场Level6-13通关指南最近在RCE-labs靶场练习时我发现Level6-13这一系列关卡特别有意思。从基础的字符过滤绕过到高级的无字母命令执行技术每个关卡都像在玩一场精心设计的解谜游戏。虽然难度不算特别高但确实需要一些巧妙的思路和技巧。如果你是刚开始接触RCE远程命令执行漏洞利用的新手这个靶场系列绝对是个不错的起点。我打靶场时发现作者在每个关卡都埋下了关键提示只要细心观察代码过滤规则就能找到突破口。下面我就详细分享下每个关卡的解题思路和实战技巧。2. Level6通配符的艺术2.1 分析过滤规则先来看Level6的代码关键过滤规则是这样的if(preg_match(/[b-zA-Z_#%^*:{}\-\|;\[\]]/, $cmd)){ die(WAF!); }这个正则表达式过滤了几乎所有字母除了小写a和大部分特殊字符。但仔细观察会发现数字0-9、问号?和斜杠/等字符没有被过滤。这就是我们的突破口。2.2 构造通配符payload在Linux系统中问号?可以匹配任意单个字符。结合未被过滤的字符我们可以这样构造命令/???/?a? /??a?这个payload相当于/bin/cat /flag解释一下/???/ 匹配 /bin/?a? 匹配 cat/??a? 匹配 /flag通过这种通配符替换我们成功绕过了字母过滤的限制。输入这个payload后成功获取到了flag。3. Level7空格过滤的绕过技巧3.1 理解空格过滤Level7的过滤规则很简单if(preg_match(/flag| /, $cmd)){ die(WAF!); }这里直接过滤了flag字符串和空格字符。但Linux命令中空格是必不可少的我们需要找到替代方案。3.2 使用替代分隔符在Linux终端中空格本质上是由$IFS变量控制的。$IFS的默认值包含空格、制表符和换行符。因此我们可以用以下两种方式绕过使用制表符的URL编码%09?cmdcat%09/f*直接使用$IFS变量?cmdcat$IFS/f*这两种方法都能成功执行命令其中/f*用通配符匹配flag文件避免了直接输入flag字符串。4. Level8重定向的截断技巧4.1 理解重定向过滤Level8的代码如下system($cmd./dev/null 21);这会把命令输出重定向到/dev/null导致我们看不到执行结果。这里的关键是理解重定向符号的工作原理。4.2 两种绕过方法方法一二次重定向/?cmdcat /flag 1.txt;然后直接访问1.txt文件查看结果。方法二命令截断?cmdcat /flag;分号;会截断后面的重定向部分使系统只执行前面的命令。我实测下来第二种方法更简单直接不需要额外步骤。5. Level9八进制编码的艺术5.1 严格的过滤规则Level9的过滤非常严格if(preg_match(/[A-Za-z\%*,-.\/:;?[\]^|]/, $cmd)){ die(WAF!); }几乎过滤了所有字母和大部分特殊字符只留下了数字和少数符号。5.2 八进制编码绕过这里需要用到bash的一个特性$\xxx可以将八进制ASCII码解析为字符。比如c - $\143a - $\141t - $\164使用作者提供的BashFuck工具我们可以生成如下payloadcmd$\143\141\164 $\57\146\154\141\147这个payload相当于执行cat /flag。注意命令和参数需要用空格分开因为八进制编码无法包含空格本身。6. Level10二进制编码的妙用6.1 更严格的数字过滤Level10在Level9基础上又过滤了数字2-9if(preg_match(/[A-Za-z2-9\%*,-.\/:;?[\]^|]/, $cmd)){ die(WAF!); }现在只剩下0、1和少数符号可用了。6.2 二进制编码构造bash支持$((2#binary))的语法来解析二进制数。比如143的二进制是10001111 - $((2#10001111))使用BashFuck工具生成的payload如下$0$0\\\\$\\\$(($((11))#10001111))\\$(($((11))#10001101))...\由于#在URL中有特殊含义需要对其进行编码。最终payload会比较长但原理就是用二进制表示每个字符的ASCII码。7. Level11数字1的替代方案7.1 过滤所有数字Level11的规则更加严格if(preg_match(/[A-Za-z1-9\%*,-.\/:;?[\]^|]/, $cmd)){ die(WAF!); }现在只剩下0和少数符号可用了而且这次是POST请求。7.2 使用${##}替代1在bash中${##}的值是1。利用这个特性我们可以用${##}来替代所有需要1的地方。BashFuck生成的payload如下$0$0\\\\$\\\$(($((${##}${##}))#${##}000${##}${##}${##}${##}))...\这个payload虽然看起来复杂但原理和Level10类似只是用${##}替代了数字1。8. Level13取反构造任意数字8.1 终极过滤挑战Level13过滤了几乎所有字母数字if(preg_match(/[A-Za-z0-9\%*,-.\/:;?[\]^|]/, $cmd)){ die(WAF!); }8.2 取反运算构造数字这里需要用到一个巧妙的技巧通过取反运算构造数字。在bash中$(()) 等于0$((~$(()))) 等于-1$((~$(())))$((~$(())))) 等于-2通过组合这些表达式可以构造出任意需要的数字。BashFuck生成的payload会非常长因为它需要用这种方式构造每个字符的ASCII码。最终payload大致形式如下__$(())${!__}${!__}\\\\$\\\$((~$(($((~$(())))$((~$(())))))))...\由于包含特殊字符需要URL编码后才能正确传输。这个关卡确实很有挑战性但理解原理后就会发现其精妙之处。

更多文章