追踪Cobalt Strike:利用数据挖掘与可视化实现威胁狩猎

本文详细介绍了如何利用JARM哈希、RiskIQ和Microsoft技术识别Cobalt Strike团队服务器,提取信标配置,并通过Azure Data Explorer进行时间序列分析,以检测网络中的潜在威胁。

追踪Cobalt Strike:挖掘与绘图,乐趣与收益并存

引言

Cobalt Strike是由Helpsystems开发的商业命令与控制(C2)框架。您可以在MITRE ATT&CK页面上了解更多关于Cobalt Strike的信息。但它也可能被真正的对手使用。在本文中,我们描述了如何使用RiskIQ和其他Microsoft技术来检查您的网络中是否存在Cobalt Strike负载(也称为“信标”)。

在大型环境中追踪Cobalt Strike信标对威胁狩猎团队来说可能是一个挑战。但这也带来了大量的创造性和机会。在这篇博客文章中,Microsoft安全响应中心(MSRC)的威胁狩猎团队旨在通过探索Cobalt Strike命令与控制(C2)流量的狩猎方法,提高我们环境的可见性,既为内部安全,也为我们的客户。

查找Cobalt Strike团队服务器

2021年1月,RiskIQ发布了一篇博客文章,讨论了在其平台上利用JARM哈希来识别互联网上的恶意基础设施。自那时起,越来越多的威胁狩猎团队和安全运营中心(SOC)在其组织内使用JARM哈希来检测恶意活动。同年晚些时候,在SANS威胁狩猎峰会与培训2021上,José Hernandez和Michael Haag向社区提出了一个出色的框架,利用互联网扫描服务结合JARM哈希来提取潜在的Cobalt Strike团队服务器列表。然后使用Wade Hickey和Zach Stanford的开源NMAP脚本探测这些IP的信标配置。您可以在此处了解更多关于JARM的信息。

正如José Hernandez和Michael Haag在SANS威胁狩猎峰会演讲中所解释的,利用Microsoft Defender威胁情报等扫描服务来识别Cobalt Strike服务器有几个好处。主要的一点是我们避免了扫描整个互联网,这可能会带来问题。我们还可以利用他们收集的多种数据类型来变化我们识别团队服务器的能力。三种这样的数据类型是JARM模糊哈希、横幅和TLS序列/哈希。

关于使用JARM哈希的一点需要注意的是,它们并不总是为查找Cobalt Strike团队服务器提供确切的答案。正如Raphael Mudge在HelpSystems网站上所演示的,JARM指纹可以根据服务器配置进行更改。因此,利用互联网扫描数据集中的其他数据类型可能会产生丰硕的成果。

在我们对José Hernandez和Michael Haag框架的分叉中,我们利用了JARM模糊哈希、横幅和TLS序列/哈希。我们有一个使用RiskIQ模块进行JARM和TLS哈希的公开示例实现,可以在此处找到。

下面重点介绍了一个利用RiskIQ社区API的SSL证书类来提取所有匹配默认Cobalt Strike团队服务器SHA1哈希的IP地址的Melting-Cobalt框架模块实现示例: 6ece5ece4192683d2d84e25b0ba7e04f9cb7eb7c

我们可以通过在Azure中的虚拟机或使用无服务器解决方案(如Azure Functions)来运行此扫描器。然后,我们可以开始从我们的扫描服务API中提取IP地址,并探测它们以获取Cobalt Strike信标。如果返回了Cobalt Strike信标,我们将数据存储起来,准备摄入到我们的数据库中。

既然我们已经讨论了识别Cobalt Strike团队服务器并提取信标配置的方法,我们需要一个地方来摄入数据以开始狩猎。

由于我们在Microsoft拥有大量基础设施,我们喜欢利用快速且可扩展的数据分析平台来支持我们的狩猎,例如Microsoft Sentinel和Azure Data Explorer。在后续的博客文章中,我们将讨论如何使用Microsoft Sentinel在您的SIEM环境中利用这些数据进行狩猎。要了解如何将此类馈送集成到您的Sentinel实例中,请前往Microsoft文档,您可以在那里了解如何将STIX/TAXII馈送摄入到Sentinel中。将提取的Cobalt Strike信标摄入到您的Sentinel实例中,可以是在您的SIEM中关联网络数据的一种快速有效的方法。

但现在,我们将讨论如何在Azure Data Explorer中利用这些数据。这使我们能够对流数据、时间序列分析有深入的了解,并拥有高级查询语言来构建模型以检测我们网络数据中的模式。

摄入和绘图数据

作为一个狩猎团队,我们喜欢使用Kusto查询语言(KQL)来构建狩猎查询并产生信号。Azure Data Explorer(以及像Sentinel这样的产品)根据您的数据所在位置提供了出色的狩猎场地。要使用Python将数据摄入到Azure Data Explorer,我们有一个简单易用的应用程序可以帮助您入门:azure-kusto-python/quick_start at master · Azure/azure-kusto-python (github.com)

下面是一个用于摄入我们的Cobalt Strike信标数据的Kusto配置示例,其中我们将数据摄入到一个名为“CobaltStrikeActiveDiscovery”的表中:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
 "kustoUri" : "https://YOURADXCLUSTER.kusto.windows.net",
 "ingestUri" : "https://ingest-YOURADXCLUSTER.kusto.windows.net",
 "databaseName" : "ThreatHunting",
 "tableName" : "CobaltStrikeActiveDiscovery",
 "useExistingTable": false,
 "alterTable": true,
 "queryData": true,
 "ingestData": true,
 "tableSchema" : "(TIMESTAMP:datetime, nmap_cmd:string, ip:string, port:string, protocol:string, service:string, hostnames:string, x64_sha1:string, x64_sha246:string, x64_md5:string, x86_sha1:string, x86_sha256:string, x86_md5:string, x64_config_method_1:string, x64_config_method_2:string, x64_config_port:string, x64_config_spawn_to_x64:string, x64_config_spawn_to_x86:string, x64_config_jitter:string, max_dns:string, dns_idle:string, dns_sleep:string, user_agent:string, watermark:string, c2_host_header:string, x64_config_polling:string, x64_config_c2_server:string, x64_config_beacon_type:string, x64_config_http_method_path_2:string, x64_uri_queried:string, x86_config_method_1:string, x86_config_method_2:string, x86_config_port:string, x86_config_spawn_to_x64:string, x86_config_spawn_to_x86:string, x86_config_jitter:string, x86_config_polling:string, x86_config_c2_server:string, x86_config_beacon_type:string, x86_config_http_method_path_2:string)",
 "data" :
 [
  {
   "sourceType": "localFileSource",
   "dataSourceUri": "results.json",
   "format": "MULTIJSON",
   "useExistingMapping": false,
   "mappingName": "CobaltStrikeMapping",
   "mappingValue": "[{\"Properties\":{\"Path\":\"$.TIMESTAMP\"},\"column\":\"TIMESTAMP\",\"datatype\":\"datetime\"}, {\"Properties\":{\"Path\":\"$.nmap_cmd\"},\"column\":\"nmap_cmd\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.ip\"},\"column\":\"ip\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.port\"},\"column\":\"port\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.protocol\"},\"column\":\"protocol\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.service\"},\"column\":\"service\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.hostnames\"},\"column\":\"hostnames\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x64_sha1\"},\"column\":\"x64_sha1\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x64_sha246\"},\"column\":\"x64_sha246\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x64_md5\"},\"column\":\"x64_md5\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x86_sha1\"},\"column\":\"x86_sha1\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x86_sha256\"},\"column\":\"x86_sha256\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x86_md5\"},\"column\":\"x86_md5\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x64_config_method_1\"},\"column\":\"x64_config_method_1\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x64_config_method_2\"},\"column\":\"x64_config_method_2\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x64_config_port\"},\"column\":\"x64_config_port\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x64_config_spawn_to_x64\"},\"column\":\"x64_config_spawn_to_x64\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x64_config_spawn_to_x86\"},\"column\":\"x64_config_spawn_to_x86\",\"datatype\":\"string\"},  {\"Properties\":{\"Path\":\"$.x64_config_jitter\"},\"column\":\"x64_config_jitter\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.max_dns\"},\"column\":\"max_dns\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.dns_idle\"},\"column\":\"dns_idle\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.user_agent\"},\"column\":\"user_agent\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.watermark\"},\"column\":\"watermark\",\"datatype\":\"string\"},  {\"Properties\":{\"Path\":\"$.c2_host_header\"},\"column\":\"c2_host_header\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x64_config_polling\"},\"column\":\"x64_config_polling\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x64_config_http_method_path_2\"},\"column\":\"x64_config_http_method_path_2\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x64_config_beacon_type\"},\"column\":\"x64_config_beacon_type\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x64_uri_queried\"},\"column\":\"x64_uri_queried\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x86_config_method_1\"},\"column\":\"x86_config_method_1\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x86_config_method_2\"},\"column\":\"x86_config_method_2\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x86_config_port\"},\"column\":\"x86_config_port\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x86_config_spawn_to_x64\"},\"column\":\"x86_config_spawn_to_x64\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x86_config_spawn_to_x86\"},\"column\":\"x86_config_spawn_to_x86\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x86_config_jitter\"},\"column\":\"x86_config_jitter\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x86_config_polling\"},\"column\":\"x86_config_polling\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x86_config_c2_server\"},\"column\":\"x86_config_c2_server\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x86_config_beacon_type\"},\"column\":\"x86_config_beacon_type\",\"datatype\":\"string\"}, {\"Properties\":{\"Path\":\"$.x86_config_http_method_path_2\"},\"column\":\"x86_config_http_method_path_2\",\"datatype\":\"string\"}]"
  }
 ]
}

一旦摄入到Kusto,您的Azure Data Explorer数据集应该看起来像这样:

您可以看到,我们能够将有价值的数据流式传输到此数据库,准备让我们在其上构建数据分析。使用https://dataexplorer.azure.com/,我们可以在支持威胁狩猎活动的仪表板中使用Kusto查询语言绘制数据的一些洞察方面。以下是一些使用Data Explorer仪表板中添加磁贴时可用的多种可视化类型的示例:

为了构建更高级的仪表板,我们可以利用Kusto查询语言(KQL)中内置的多种数据分析功能。我们可以开始利用这些数据来与其他数据源(如我们的内部网络数据)进行关联。

在网络中狩猎潜在威胁

Azure Data Explorer的一个伟大之处在于,您可以将多个数据集结合在一起,并构建高效的时间序列分析。一个关键的重要注意事项是,我们的数据收集通过允许我们获取互联网上信标配置的指标来支持我们的狩猎,从而获得回报。在网络数据中狩猎的两个关键数据点是轮询(或睡眠)和抖动。这些由操作员确定或保留为默认值以设置以下配置:

  • 轮询或睡眠时间:每个信标回调之间的睡眠时间,以毫秒为单位
  • 抖动:轮询时间上的抖动百分比。默认设置为0。以下屏幕截图中的配置是一个很好的例子:如果轮询时间设置为25000毫秒,即25秒,抖动率设置为37%(25的37% = 9.25),则信标将在回调之间睡眠 anywhere between 15.75 and 34.25 seconds。

如果我们查看我们的扫描器数据的一个样本集,我们可以评估参与者正在使用的配置。在下面的快照中,我们可以看到最常见的抖动和轮询配置是默认配置,抖动设置为0,轮询速率设置为1分钟。

绘制我们的轮询配置,我们可以看到80.1%的数据将默认轮询速率设置为1分钟。30秒是第二常见的。平均为51959毫秒或51.959秒。

进一步地,如果我们绘制我们的抖动配置,如图11所示,我们可以看到86%的配置设置为0%抖动。使用Kusto中的Avg函数,我们计算数据集中的平均值, resulting in an average Jitter percentage of 4%。这应该使我们能够更好地了解网络数据中频率的方差。

这为我们提供了一些有趣的见解,当将我们的C2数据与我们的网络数据关联时。由于平均轮询时间为51.95秒,平均抖动时间为4%,平均而言,我们可能会在我们的数据中看到信标流量,显示回调平均在49.87秒和54.03秒之间。这当然是对采样数据集的平均计算,但为我们作为威胁猎人提供了在狩猎Cobalt Strike时可能看到的情况的概念。

为了进一步利用这一点,让我们将我们获得的C2数据与我们的网络数据关联起来。您可以使用多种网络数据来执行此狩猎,例如捕获Zeek或netflow。

使用Azure Logic Apps,我们创建了与我们扫描器数据中捕获的C2s通信的网络数据的每日快照。我们可以通过构建Azure Logic App以每日节奏运行,使用Run async控制命令来摄入一个数据集,其中我们的任何网络流量具有我们Cobalt Strike数据集中C2的目的地地址。这应该为我们提供一个每日馈送,包含所有与C2s相关的网络流量,我们可以用它来构建时间序列数据。

我们可以使用make-series来创建一个过去7天内每小时聚合请求的系列。这将为我们提供我们可以在此网络中观察到的任何信标流量的指示。以下是一个示例查询:

1
2
// 示例查询:创建过去7天内每小时聚合请求的系列
make-series requests=count() on TimeStamp from ago(7d) to now() step 1h

结果可能看起来像这样:

在我们上面显示的示例中,我们可以在绘制的绿线中立即看到数据中的一个异常值。我们看到一台机器在过去的7天内频繁地与Cobalt Strike C2从我们的内部流量通信。这为我们提供了一个立即开始狩猎威胁的地方,因为这台机器以如此频繁的速率外部通信,它作为一个主要的异常值脱颖而出。上面显示的数据总体显示每小时与我们的Cobalt Strike C2s的交互量非常小。由于低体积,它们不太可能是受感染的机器。

注意:在此示例中,我们使用的网络数据是采样的,这导致计数低于约51.959秒的轮询速率。

使用全保真网络数据,您可能会看到每小时大约50-70个流的平均计数,但这不包括在攻击者与受感染机器交互期间可能捕获的额外网络数据,这将创建更高的流量计数。在您看到流量计数高于平均轮询速率的情况下,您可能正在看到攻击者与受感染机器交互的示例。这提供了关于威胁

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计