【技术分享】如何利用Office 365的任务功能搭建Cobalt Strike C2通道

http://p0.qhimg.com/t01f4633e267d0a3abc.png

译者:興趣使然的小胃

预估稿费:200RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


一、前言

在定制化、创新化命令与控制(C2,Command and Control)通道方面,人们已经做了许多研究工作,然而已公开的研究成果通常只是独立的理论概念,没有集成到现有的攻击工具包中。Cobalt Strike最近添加了一个新的扩展功能,可以在保持工具兼容性的前提下,创造隐蔽的C2通道。

Cobalt Strike新添加的扩展名为“External C2”,为了最大化挖掘该扩展的潜能,MWR团队开发了一个定制版的C2通道,使用Office 365作为通信媒介。本文介绍的主要内容如下:

1、利用Office 365服务中Outlook的“任务(tasks)”功能,演示如何搭建Cobalt Strike的C2通道。

2、分析定制化Cobalt Strike C2通道时会碰到的一些困难,并介绍了解决这些困难的一种方法。


二、External C2接口

Cobalt Strike是一个渗透平台,广泛应用于面向目标的操作场景,用来模拟特定威胁来源。Cobalt Strike包含许多重要功能,比如beacon植入体(implant)以及“可拓展的C2”通道。可扩展的C2功能可以用来定制C2请求以及响应消息的具体结构。比如,我们可以定制HTTP头部、正文中的数据结构,以及C2数据在这些结构中的存储方法。利用这种功能,我们可以设计弹性化C2通道,将C2通信流量隐藏在正常的流量中。虽然可扩展C2提供了丰富的定制化选项,但仍然存在几个限制条件,需要我们注意:

1、该功能仅支持Cobalt Strike支持的某些协议,即:HTTP/HTTPS以及DNS协议。

2、与使用这些协议的“外部”服务通信本身就是比较有难度的一个过程,并且大多数情况下都难以成功。

3、对于HTTP/HTTPS而言,该功能仅限于客户端-服务器应用场景,这种情况下,客户端(即植入体)会向服务器(Cobalt Strike团队服务器(team server))发布请求,服务器会直接返回响应数据。

作为Cobalt Strike的创始人,Raphael Mudge最近发布了一个概念验证功能型扩展,可以使用任意C2通道,这个功能也就是我们今天要介绍的“External C2”接口。

我们可以将该接口与传统的Cobalt Strike用法做对比,来理解这个接口的工作原理。简单起见,这里我们只会分析HTTP/HTTPS场景。在这个场景中,通常情况下,(内存中或磁盘上的)某个植入体会使用HTTP/HTTPS协议作为通信协议,直接与Cobalt Strike团队服务器通信,更多情况下,植入体会使用重定向器(redirector)与团队服务器通信,重定向器负责将通信流量转发给团队服务器。典型的使用场景如下图的左图所示。其他植入体可以使用与C2相同的通信协议来传播,或者也可以使用SMB协议进行分发。使用SMB协议时,新的植入体与源植入体之间需要使用命名管道(named pipe)来通信,而源植入体负责中继原始C2通道的通信流量。

http://p3.qhimg.com/t01486b3d0186c5b95d.png

“External C2”支持在传统的Cobalt Strike C2模型中使用中间人(man-in-the-middle)技术。在这种情况下,客户端代码包含一个第三方客户端以及一个SMB植入体。第三方客户端不需要负责Cobalt Strike功能,相反,它负责生成SMB植入体,然后通过命名管道与SMB植入体通信。通过命名管道收到流量后,第三方客户端可以将这些流量再次封装,然后通过任意C2通道传输。服务端要搭建一个第三方控制端,以接收并解封装C2流量,然后使用简单的TCP套接字将经过处理的C2流量转发给团队服务器。Cobalt Strike通过“aggressor script”启动“External C2”接口,团队服务器通过“External C2”接口来监听数据(“aggressor script”是Cobalt Strike的脚本引擎)。“External C2”接口可以在任意端口上监听,与现有的“监听器(listeners)”功能类似(listeners为接收特定协议连接的端点)。通信数据的回连路径与发送路径相同。

Raphael Mudge所实现的External C2接口中包含aggressor script以及一个简单的第三方客户端。第三方客户端与控制端之间使用基本的TCP套接字进行通信。Raphael Mudge没有实现任何第三方控制端,然而由于整条C2路径仅用到了TCP套接字,在测试场景中,我们可以使用TCP端口转发来模拟其功能。


三、与Office 365同步“任务”

只要攻击者的想象力足够丰富,他就可以利用“External C2”接口来选择使用各种类型的C2通道。本文使用C++语言写了段PoC代码,简单实现了“External C2”的第三方客户端以及控制端组件,利用这些组件,配合Office 365服务中Outlook的“任务(tasks)”功能来搭建一个C2通道。随着越来越多的组织选择使用Office 365服务,利用这种方式构建的C2通道也显得更加隐蔽,难以与合法的流量区分开来。

3.1 与Office 365交互

Office 365中的Outlook由Microsoft Exchange来提供功能支持是非常正常的一件事情,令人惊讶的是,我们也可以通过Office 365来使用Exchange内部实例所支持的许多功能。

Exchange提供了一个非常重要但又不太知名的功能,那就是Exchange Web Services(EWS)功能。EWS是一个SOAP Web服务,客户端可以通过该服务与Exchange进行交互。EWS默认处于启用状态,与Outlook Web App(OWA)地址处于同一级别,具体地址为:“https://<domain>/EWS/”。我们发现Office 365的确提供了EWS服务,具体地址为:“https://outlook.office365.com/EWS/”。

许多客户端应用程序会用到EWS服务,比如桌面版Outlook中的“加载项(add-ins)”功能;Outlook本身会使用MAPI/RPC来与Exchange进行交互,无需依赖EWS服务。然而,EWS支持MAPI/RPC所提供的大部分功能,只有某些情况除外(例如,EWS无法创建“有风险”的某些Outlook规则,如“启动应用程序”规则)。

EWS支持各种功能,比如创建、修改以及删除邮件、日历、联系人、任务等Outlook支持的功能。这些操作都会同步到Exhcange上,因此也可以用作C2媒介加以使用。

出于演示目的,在本文的PoC中,我们选择使用其中的“任务”功能。与电子邮件一样,每个任务项目都可以包含非常大的数据量。之所以选择任务功能作为目标,原因是现有的安全控制机制主要针对的是电子邮件(比如自动扫描邮件中包含的恶意软件),因此,任务功能可以成为更为隐蔽也更为安全的使用媒介。

我们可以使用Office 365 EWS服务来创建一个任务,以此为例展示该技术在实际环境中的应用场景。任务的内容由“主题(Subject)”以及“正文(Body)”标签来表示。这两个特征可以用来构建C2通道,如下文所述。我们还使用了“截止日期(DueDate)”标签,其他可用标签的使用方法与该标签类似。任务中包含的许多标签可以用于C2通信,比如,某些标签可以作为信令标志加以使用(例如,我们可以将“非常重要(high importance)”标签的值设为“启用(enabling)”,以表示C2通道处于阻塞状态)。然而,我们的PoC代码并没有用到所有标签,仅用到了其中的“Subject”以及“Body”标签。

http://p5.qhimg.com/t01853365c04973d28e.png

将这个请求发送给Office 365会得到什么结果?这正是本文要介绍的重点。

http://p1.qhimg.com/t0162e92546ce91cefb.png

利用EWS服务,我们可以通过Office 365来创建及删除任务。本文的PoC代码中会覆盖到这两个操作。从攻击角度来看,这些操作的结果是会生成大量流量,发往已知的、合法的且信誉度较高的域名。从防御角度来看,我们很难将这些流量标记为非法流量,特别是当正常业务中Office 365的使用场景越来越普遍时,这些恶意流量会更加难以识别。

3.2 消息格式

现在我们已经有办法与Office 365交互,这一节中,我们会讨论如何把这种方法应用于Cobalt Strike C2通道中,也会探讨实际工具中使用这种方法会遇到的一些困难。

在PoC代码中,我们采用了两个关键设计理念。首先,我们会根据具体的流量模式(即server-to-client(S2C)还是client-to-server(C2S))来使用不同的通信通道,这样控制端及客户端就能快速识别相应的任务以便后续处理。其次,每个通道可以使用多个任务,这样就能提高传输速率。当然我们还可以使用其他可选方法,比如我们可以使用经常修改的一小部分原型任务或者邮件,然而这会大大降低整体性能,也会加大整体复杂性,比如我们需要考虑排队以及信令等复杂情况。根据这两个设计理念,最终我们使用的C2架构如下所示:

http://p5.qhimg.com/t01b4703b601a633f5f.png

对于每个任务,我们将Cobalt Strike团队服务器或植入体所使用的核心数据载荷(payload)以base64编码形式存储在任务的body区中。每个任务需要包含某些特征字符,以便各自能够相互区分。特征字符包含在任务的subject字段中,以冒号作为分隔符。subject中包含的特征字段如下所示:

1、通道模式(Channel):表明通信流的方向,为S2C或者C2S。

2、连接标识符(Connection identifier):随机生成的包含数字和字母的一个字符串,以标识C2通道上的每个“连接”。PoC代码使用这个字段以支持多客户端功能。客户端和控制端需要在各自的消息中包含这个字段。

3、消息序号(Message sequence number):一个递增整数,以标识创建的每个任务。这个字段用来确保接收端以正确的顺序处理收到的任务。

4、数据长度(Data length):一个整数,以表示任务body字段中的数据经过base64解码后所包含的字节数。

5、消息摘要(Message digest):用于完整性检查的一个值。我们根据未经base64编码的载荷计算出这个值,接收端收到载荷后,根据base64解码结果计算校验值,再跟原来的值对比。在本文所用的PoC代码中,这个值仅用来验证客户端连接开始时所使用的传输器(staged)植入体是否有效。

根据这些字段,在Office 365中传输的典型C2流量如下所示:

http://p4.qhimg.com/t013d779271b69433e5.png

3.3 C2组件控制流程

实现这种“External C2”方案的最大挑战在于如何支持多个客户端连接。原因主要在于我们需要花许多精力来识别并跟踪每个客户端连接的状态,还要确保能够正确发送和接收C2流量。我们在PoC代码中解决了这个难题,在下文中,我们会介绍客户端和控制端的控制流程,这是解决问题的关键点。

客户端的控制流程如下图所示。PoC代码可以支持传输器(staged)载荷(下文使用A来表示)以及完整版的传输器(full staged)载荷(下文使用B来表示),因此我们需要在流程(1)中识别载荷所使用的具体方法。在流程(2)中,A方法所使用的消息结构与Raphael Mudge所使用的结构一样,涉及如下四类消息:架构信息(“arch=<value>”)、命名管道的名字(“pipename=<value>”)、“no-op”帧之间间隔的毫秒数(“block=<value>”)以及用来与团队服务器建立连接的一个触发指令(“go”)。这个流程中会随机生成一个包含字母数字的字符串,作为命名管道以及连接的标识符。消息随后会被封装,然后经过Office 365进行传输。在流程(3)中,我们会接收Office 365返回的A类型植入体(大小约200KB),检查该植入体是否完整,如果完整性校验不通过,会再次请求这个植入体。在流程(4)中,我们将植入体载入内存,调用CreateThread()函数启动植入体。B类型客户端会从流程(1)直接跳到流程(4)。在这种情况下,我们需要使用静态管道名,与生成B类型植入体文件所使用的管道名一致。这类植入体会创建一个命名管道,然后客户端会尝试连接这个管道,为了保证稳定性,如果连接失败,我们会使用新的命名管道名称再次发起请求。目前我们的“External C2”方案尚未完全支持B类型植入体,需要添加其他代码以支持这个功能。为了通过“External C2”接口收到来自植入体的连接请求,团队服务器必须收到“go”触发指令。简单加载植入体并不能实现与团队服务器的通信。虽然我们可以使用其他参数来单独发送触发信令,但从结果上来看,我们还是会收到使用默认值(如“pipename=externalc2”)的传输器载荷响应。这个响应对我们来说有点多余。

http://p6.qhimg.com/t0199dbcc947d38a4af.png

随后,我们会进入一个循环流程。在流程(5)中,客户端检查命名管道上是否有可用数据,如果可用则读取相应数据。流程(6)中,客户端将读取的数据封装成一个任务,然后发给Office 365。流程(7)中,检查并接收Office 365上的可用任务。流程(8)中,对收到的任务进行解封装,识别对应的客户端。流程(9)中,如果有可用任务,会根据控制端消息序号对这些任务进行排序,按顺序处理后再写入命名管道中,最后,从Office 365中删除这些任务。这种循环处理逻辑可以让植入体获得Office 365的轮询时间,因此可以通过“sleep”命令动态控制轮询请求。

控制端的控制流程如下图所示,流程(1)、(2)、(3)、(4)、(5)属于第一段控制流程,流程(6)、(7)、(8)属于第二段控制流程。流程(1)中,检查Offce 365上是否有可用任务用于客户端通信。如果有可用任务,流程(2)中客户端会获取并拆分这些任务。如果任务来自于以前没见过的客户端,流程(3)中会实例化一个类,专门处理客户端的变量及方法。在流程(6)中,生成的对象中包含一个特定方法,负责处理连接到Cobalt Strike团队服务器的每个客户端TCP套接字。流程(4)中,从Office 365收到的任务会根据序号进行排序。流程(5)中,从正确的客户端对象中识别已建连TCP套接字(每个客户端都应该有自己的套接字连接),通过TCP套接字将解码后的任务发给团队服务器。发送完毕后,从Office 365上删除这些任务。流程(7)中,团队服务器返回响应,使用相应的客户端信息将响应封装成任务,发给Office 365。通过这种工作流程来发送和接收任务,我们可以控制任务轮询速率。第一段控制流程负责接收任务,可以个性化配置,通过批处理方式让所有客户端处理来自Office 365的任务(比如,可以避免定时向服务器发起请求);在第二段控制流程中,每个客户端可以自动从团队服务器上接收数据,然后根据实际需求将数据以任务形式发送给Office 365。

https://p5.ssl.qhimg.com/t0181fa84551b79d3db.png

3.3 场景演示

我们搭建了一个演示场景,包含1个控制端以及3个客户,具体操作如下视频所示。在这个场景中,客户端使用的是全功能版的传输器载荷。

从视频中你可以看到,虽然依赖于外部服务,但整体的响应速度还是可以接受,而新增的延迟主要来自于控制端和客户端在请求及响应循环中的处理时间。尽管存在延迟,在不优化性能的情况下,利用这种方法每个客户端还是可以达到每分钟2MB左右的下载速度,主要原因是任务的body字段可以包含大量数据。后续我们可以考虑使用Office 365的其他功能来提升速度,比如,我们可以使用Office 365提供的批量数据上传功能。


四、总结

本文介绍了Cobalt Strike的“External C2”接口,提供了PoC实现方法,借助Office 365服务中Outlook的“任务(tasks)”功能搭建了一条C2通道。

需要注意的是,尽管本文侧重于Office 365服务,但我们给出的方法适用于使用Exhange服务的其他互联网产品,其中不乏许多商业产品。比如,我们可以将某个目标组织自己搭建的Exchange服务作为C2通道媒介加以使用 。在这种情况下,C2通信的初始阶段(即客户端与Exchange建连阶段)将完全停留在目标网络内部,只有控制端连接到目标组织的Exhcange实例时才会产生外部流量。对攻击者而言,这种方法的缺点在于目标安全团队可以访问Exchange的日志,如果我们使用的是Office 365,目标安全团队就难以做到这一点。

“External C2”接口目前仍处于早期试用阶段,需要解决许多问题才能在在实际生产环境中使用。对进攻发起方而言,“External C2”接口提供了动态C2通道功能,可以让C2研究工作大放异彩。

(完)