前言
在很多攻击活动中,我们都能看到 CobaltStrike 的身影,所以,对于防御者,了解其在各个攻击阶段的行为特征是非常有必要的
上篇文章——《威胁狩猎的最佳实践》里提过一些检测方法,本文正好以CS为例,介绍下behavior-based的检测手段
全文结构参考ATT&CK攻击框架展开,主要涉及CS内置或者常用的使用姿势,检测思路仅供参考
攻击阶段
Execution
CS中有很多用于后渗透的攻击模块,它们的加载通常是借助调用Windows DLL的方式来实现
这意味着攻击者在使用这些内置工具的时候,CS会临时拉起一个进程并使用rundll32.exe实现恶意代码注入
更重要的是,为了传递输出信息,这些攻击模块会通过命名管道(named pipe)的形式与beacon产生通信
通常情况下,CS会采用以下默认的风格给管道进行命名:
- \postex_*
- \postexssh*
- \status_*
- \msagent_*
- \MSSE-*
- *-server
当然,攻击者能够自行修改命名方式,不过这一点容易被很多人忽视,大家也可以检视下自己平上时有没有这样的习惯,更多内容请参考官方文章
那么站在防御者的视角,我们可以使用 sysmom 等日志采集工具观测到以下行为:
除了关注管道的命名风格,CS在利用rundll32.exe进行代码注入的过程中,也有一定的行为特征,比如下图中的父子进程关系和参数调用:
虽然我们的操作系统在日常活动中也会经常用到rundll32.exe,但这里有所不同的是——它被调用时不带任何参数,这种调用过程同样值得防守方加以关注
对于windows上这类常见的系统进程,日后我会再专门写些文章去深入分析它们的行为基线,此处留个坑先…
Defense Evasion
在这一攻击阶段,CS中最常用的手法就是进程注入(process injection)
例如通过远程代码注入伪装成svchost.exe,或者注入lsass.exe后从内存中提取访问凭证
要想达到优秀的检测效果,我们最好双管齐下,一是理解攻击原理,二是理解日志记录的原理
关于CS实现进程注入的过程,可以参考官方的这段说明,这里我拿其中的配置文件为例:
process-inject {
# set how memory is allocated in a remote process
set allocator "VirtualAllocEx";
# shape the memory characteristics and content
set min_alloc "16384";
set startrwx "true";
set userwx "false";
transform-x86 {
prepend "\x90\x90";
}
transform-x64 {
# transform x64 injected content
}
# determine how to execute the injected code
execute {
CreateThread "ntdll.dll!RtlUserThreadStart";
SetThreadContext;
RtlCreateUserThread;
}
}
参考上述执行流程,我们可以将其分解成四步:
- 获取远程进程的句柄
- 在远程进程中开辟内存空间
- 将shellcode复制到远程进程
- 在远程进程中执行shellcode
结合sysmon的监测能力,先拿两类日志为例吧:EID 8 和 EID 10
在上述流程的第一步,使用OpenProcess获取进程句柄的活动会被sysmon记录成EID为10的日志
而该日志类型有两个字段值得我们关注——TargetImage和GrantedAccess
前者就是目标进程,后者与访问权限相关,不同位掩码代表的权限关系如下:
Access | Mask |
---|---|
PROCESS_CREATE_PROCESS | 0x0080 |
PROCESS_CREATE_THREAD | 0x0002 |
PROCESS_DUP_HANDLE | 0x0040 |
PROCESS_SET_INFORMATION | 0x0200 |
PROCESS_SET_QUOTA | 0x0100 |
PROCESS_QUERY_LIMITED_INFORMATION | 0x1000 |
SYNCHRONIZE | 0x00100000 |
PROCESS_QUERY_INFORMATION | 0x0400 |
PROCESS_SUSPEND_RESUME | 0x0800 |
PROCESS_TERMINATE | 0x0001 |
PROCESS_VM_OPERATION | 0x0008 |
PROCESS_VM_READ | 0x0010 |
PROCESS_VM_WRITE | 0x0020 |
拿mimikatz使用过程中涉及到的权限为例:
Command | Sysmon 10 | Security 4663 Kernel Object |
---|---|---|
lsadump::lsa /patch | GrantedAccess 0x1438 | AccessMask 0x10 |
lsadump::lsa /inject | rantedAccess 0x143a | AccessMask 0x10 |
lsadump::trust /patch | GrantedAccess 0x1438 | AccessMask 0x10 |
misc:memssp | GrantedAccess 0x1438 | AccessMask 0x10 |
Procdump mimidump | GrantedAccess 0x1fffff | AccessMask 0x10 |
Task Manage minidump | GrantedAccess 0x1400, 0x1000, 0x1410 and 0x1fffff | AccessMask 0x10 |
sekurlsa::* | GrantedAccess 0x1010 | AccessMask 0x10 |
这其中,0x1fffff 较为惹人注目,其意味着被赋予了所有权限,而我们的CS在代码注入活动中正是这样表现的:
到了进程注入的最后一步时,CS经常会调用 Win32 API CreateRemoteThreat,而这又会引起sysmon中日志类型ID为8的注意
这类日志不仅会记录API调用过程中的源进程和目标进程,还会记录新线程的起始地址和起始函数等信息
针对这一类行为的检测,同样可以从两方面入手,一是建立行为基线
生产环境中会调用 CreateRemoteThreat 的进程不多,常见的有反病毒程序和svchosts.exe、services.exe、wininit.exe等
参考 sysmonconfig.xml 等配置文件,可以维护一份白名单,对基线外的异常行为加以关注
另一方面,日志中的 StartAddress 等字段同样能起到一些辅助作用,Olaf Hartong 以前针对这一检测点专门写过<a href=”https://medium.com/@olafhartong/cobalt-strike-remote-threads-detection-206372d11d0f”>文章
尽管在后续版本中有所变化,但是这一思路仍然能应用在检测技巧中提高相关进程行为的风险暴露程度
当然,进程注入的方式非常多样,而EID 8只关注 CreateRemoteThreat(),所以这一监测方式并不总能奏效
但是该检测点仍然不失为一道重要的防线,通过下图可以较为直观地理解我们的布防位置:
除了进程间访问和远程线程创建之外,被注入的进程可能会产生新的会话,与C2进行通信,这时还会有EID 22(DNS query)的记录
从整个执行流程来看,就是 EID 10 -> EID 8 -> EID 22,其中每个阶段还会或多或少有些特征
讲到这里,我又想给自己挖个坑了,这一攻击手法其实可以拆解成多个风险行为,结合适当的算法计算出多条风险路径,从而大幅提高告警精确性和置信度
除了传统检测方法中的 Clustering、Grouping 和 Stack Counting 等,其实还有很多技巧可以结合使用,往往能达到更优的效果
Privilege Escalation
提权阶段,最常用的手法可能是借助 getsystem
命令,其原理和Meterpreter的getsystem命令类似
本质上都是通过命名管道实现令牌模拟(named pipe impersonation),想要了解细节的小伙伴可以参考下这篇文章
这种方式依赖于 SeImpersonatePrivilege 的特权,因此前提是你的beacon已经具备Admin权限,而UAC Bypass的方式由于太过多样,这里就先暂且不表
还有一种方法是通过elevate svc-exe [listener]
创建服务运行一个二进制的payload,从而获得 SYSTEM 权限
这一过程涉及到可执行文件的创建、系统服务的创建、注册表的修改、文件和服务的清除等步骤,检测点比较多,可以按照下列截图依次分解:
- 创建管道 EID 17,注意进程路径(Image)和管道命名方式(PipeName)
- 释放文件 EID 11,注意用户权限(SYSTE<)、进程名称(Image)和文件名称(TargetFilename)
- 创建服务,注册表行为 EID 12&13,注意注册表位置和键值
- 进程创建 EID 1,注意进程路径与命令参数(无参数)
- 文件删除
文件删除这一行为我在实验过程中没能采集到相应日志,期待有相关发现的小伙伴们可以Twitter私信我
但是理论上该可执行文件的执行后自删除行为也是非常有价值的一个检测点,尤其是结合文件路径和签名状态等信息
Credential Access
当攻击者获取目标系统的高权限之后,往往需要透过lsass.exe进程获取访问凭证
这一阶段中更多的攻击手法就不再赘述了,仅以使用CS的 hashdump
命令从进程内存中窃取凭证为例
首先,我们需要对以 lsass.exe 为目标进程的相关行为加以关注:
很显然,以 0x1fffff 权限访问 lsass.exe 的行为都应该引起我们的高度警惕
接着,我们可以通过源进程的GUID看看它还干过些什么,结合前文在Execution阶段的分析,我猜它至少创建过命名管道
果然如此,不仅是创建管道,还有进程间的调用特征(rundll32无参数),甚至还涉及到注册表相关的行为
这一阶段,结合攻击方要窃取的目标,防守方往往可以把注意力重点集结在 lsass.exe 等关键进程上,尤其会涉及到高权限的访问行为
只要做好数据采集和质量管理,在相关的必经之路上其实是易守难攻,这时的防守方反而能占据一些优势
小结
受限于篇幅,其他攻击阶段譬如横向渗透、C2通信和内网探测之类的就不再展开举例了
目前网上关于 CobaltStrike 的检测大多集中在流量侧,关于后渗透阶段在主机侧的行为表现,希望本文能起到抛砖引玉的作用
尽管攻击方的绕过姿势花样迭出,但是一些关键行为路径仍然难以避免或者容易忽视,还有很多宝藏trick亟待挖掘
最后,本文中大部分技术细节都是浅尝辄止,感兴趣的朋友可以通过我个人主页上的 Twitter 联系我,欢迎同好交流~~