There is much research into customised and novel Command and Control (C2) channels, although typically the public outputs of such research are standalone proof-of-concepts rather than being integrated into exisiting offensive toolkits. Recent extensions to the functionality of Cobalt Strike, however, have created opportunities for deploying esoteric C2 channels while maintaining tooling compatibility.
To explore the potential that Cobalt Strike's newly added “External C2” extension offers offensive teams, MWR have developed a customized C2 channel that uses Office 365 as the communications path. The key objectives of this post are as follows:
Cobalt Strike is a framework widely used within goal oriented engagements to simulate targeted threat actors. Notable features include its beacon implant and “malleable C2” channels. Malleable C2 provides a means of customizing the request and response structure of C2 messages. For example, by being able to specify HTTP header and body structure and how C2 data is contained within it. Such capability is integral to designing a resilient C2 channel, as it allows it to be designed to blend in with legitimate traffic. Although malleable C2 provides extensive customisation options, there are a few marked limitations on what it is capable of:
Raphael Mudge the creator of Cobalt Strike has recently released a proof-of-concept functionality extension which allows the use of arbitrary C2 channels. This functionality is known as the “External C2” interface.
In order to understand how this interface works, it is useful to contrast it against the traditional use case for Cobalt Strike. For simplicity, only the HTTP/HTTPS scenario is considered here. Typically this would involve an implant (either in memory or on disk) that would leverage HTTP/HTTPS for communication directly to the Cobalt Strike team server (or as is more commonly the case, through a redirector that would forward the traffic to the team server). This is shown on the left of the following diagram. Additional implants can be spawned which leverage the same protocols for C2, or instead use SMB. For SMB, named pipes are used for communication between the “new” implant and the spawning implant, with the latter then taking responsibility for relaying traffic over the original C2 channel.
“External C2” effectively allows a man-in-the-middle approach to the traditional Cobalt Strike C2 model. In this case the client side code involves the combination of both a third party client and an SMB implant. The third party client handles no Cobalt Strike specific functionality. Instead, it is responsible for spawning an SMB implant which it communicates with over a named pipe. The traffic it receives over this named pipe can be then packaged and transmitted over arbitrary C2 channels. On the server side, a third party controller is also required to receive and unpackage the C2 traffic, and then forward it on to the team server, which is done using simple TCP sockets. The team server is configured to listen for these connections through the “External C2” interface, which is started through an “aggressor script” (a means of defining extensions for Cobalt Strike). The “External C2” interface listens on an arbitrarily defined port number, and functions similar to how “listeners” (endpoints for receiving connections of a particular protocol) would normally be defined. The same process is used for communication on the reverse path.
The proof-of-concept implementation of External C2 provided by Raphael Mudge contains the aggressor script along with an implementation of a basic third party client. The third party client to controller communication is performed over basic TCP sockets. No third party controller implementation was available; however, as the C2 path only uses TCP sockets, for initial testing, its functionality can be mimicked by using TCP port forwarding.
Through the use of “External C2” the choice of C2 channel is limited only by an attacker’s imagination. The remainder of this post will introduce a C++ proof-of-concept implementation of the “External C2” third party client and controller components, which allow C2 through “tasks” within Outlook on Office 365. As organisatons increasingly opt to use Office 365, by also leveraging it for C2 the malicious traffic becomes indistinguishable from what is legitimate.
It will likely come as no surprise that Outlook for Office 365 is powered by Microsoft Exchange. It may however surprise that much of the functionality provided by an on-premise instance of Exchange is also available through Office 365.
One notable, but less well known feature of Exchange is Exchange Web Services (EWS). EWS is a SOAP web service, which allows client applications to interact with Exchange. EWS is enabled by default and is available at a URL that parallels the more commonly known Outlook Web App (OWA): “https://<domain>/EWS/”. EWS can also be found available on Office 365 at the following URL: “https://outlook.office365.com/EWS/”.
Examples of client applications that make use of EWS include “add-ins” for desktop versions of Outlook; MAPI/RPC is used by Outlook itself to interact with Exchange and has no reliance on EWS. However, much of the functionality available through MAPI/RPC is also available through EWS, although there are notable exceptions (e.g., creating certain types of “risky” Outlook rules such as “start application”).
The functionality provided by EWS includes the ability to create, modify and delete emails, calendar items, contacts, tasks, and a multitude of other aspects of the functionality provided by Outlook. Each of these “items” gets synchronised to Exchange, and therefore, can also be leveraged for use as a C2 medium.
For the purposes of this proof-of-concept, “tasks” were chosen. Tasks along with emails provide the greatest capacity per item (i.e., in terms of the content they can contain). Tasks were favoured in large because security controls are arguably more likely to be directed towards email (e.g., automatic scanning for malware), and therefore, tasks provide a potentially more covert, and less detectable medium.
In order to demonstrate how this might work in practical terms, an example is shown below of the creation of a task through the Office 365 EWS web service. The task itself is considered an “Item” of type “Task”. The content of the task is provided through the “Subject” and “Body” tags. Both of these features could conceivably be used for C2 – and are, as shown later in this post. A “DueDate” is also set, mostly to demonstrate one of the many other forms of tags that can be set. Many of these could also be used within C2 traffic, such as to act as a signaling mechanism (e.g., using the “enabling” of the “high importance” flag to indicate a blocking condition). This, however, was not implemented as part of this proof-of-concept, and only “Subject” and “Body” are used.
The result of this request to Office 365? Just another thing on the to do list – the topic of this post.
By leveraging EWS it is therefore possible to easily create and delete tasks through Office 365. Both of these actions are leveraged within this proof-of-concept. From an offensive perspective the result is a large amount of traffic to a HTTPS service on a known legitimate and reputable domain. From a defensive perspective, it would be challenging to flag this as illegitimate, especially given the increasing use of Office 365 as part of normal business operations.
Now that we have a means of interacting with Office 365, this section will discuss how this was leveraged as a medium for Cobalt Strike C2 traffic, along with how the inherent challenges within this for practical tooling were addressed.
For this proof-of-concept, it was decided to make two key design decisions. First, to have separate communication channels depending on whether traffic flow is server-to-client (S2C) or client-to-server (C2S). This allows both the controller and client to rapidly identify relevant tasks for processing. Second, to allow multiple tasks per channel to improve transmission rates. An alternative to this would have been to, for example, use a small number of draft tasks or emails that are repeatedly modified; however, this has significant performance consequences, and introduces complexity for queueing and signalling. The result of these design decisions is a C2 architecture that looks as follows:
For each task, the core “payload” of data being sent to or received from the Cobalt Strike team server or implant is contained within the task’s body in base64 encoded form. Each of these tasks then requires certain characteristics that distinguish it others, and indicate how it is intended to be processed. This information is contained within the subject using a colon delimited list. The individual components of information transmitted within the subject are:
An example of C2 traffic in this form flowing through Office 365 is shown below.
The main challenges for implementing this “External C2” implementation arose from the requirement for supporting multiple client connections. This is largely due to the process for identifying and tracking the state of each client connection, and then ensuring C2 traffic is forwarded and retrieved appropriately. To explain how this was addressed within this proof-of-concept, the control flow for both the client and the controller is discussed below.
The following figure demonstrates the control flow of the client. The proof-of-concept implementation caters for both staged and full staged payloads and so verifies which approach is being used (1). The staged method (2) follows the same message structure as with Raphael Mudge’s original proof-of-concept, which involves a series of four messages of particular identifiers: the architecture (“arch=<value>”), the name to use for the named pipe (“pipename=<value>”), the number of milliseconds between “no-op” frames (“block=<value>”), and a trigger to start a connection to the team server (“go”). A randomly generated alphanumeric string is generated for both the pipename and the connection identifier. The messages are then packaged and transferred through Office 365. A staged implant is then returned through Office 365 (at around 200KB). Its integrity is validated (3) with a failure leading to the stage being requested again. The stage is then copied into memory and a CreateThread() is called to trigger the start of the implant (4). A client with a fully staged implant moves directly from (1) to (4). In this case, a static pipename is used based on the one used to generate the fully staged implant binary. This implant creates the named pipe and the client attempts to connect to it; if this fails, for resilience, the stage is requested again with a new named pipe name. Fully staged implants are not formally supported in the current “External C2” implementation, and workarounds are required to enable it. In order to receive connections from implants through the “External C2” interface a “go” trigger must be received by the team server; it is not possible to simply load the implant and expect it to be able to talk to the team server. Although the trigger can be sent in isolation from the other parameters, it still results in a staged implant response that uses default values (e.g., “pipename=externalc2”). This response, however, can be safely dropped.
A cyclical process then begins, whereby the client checks if data is available on the named pipe, and if it is it reads that information (5). This is then packaged as a task and sent to Office 365 (6). Office 365 is then checked for tasks (7), which are then unpackaged and processed to identify tasks relevant to the client (8). If tasks are available, they are sorted by the controller’s message sequence number to ensure they are processed in order, before being written to the named pipe, and finally deleted from Office 365 (9). The logic of this cyclical process allows the poll time to Office 365 to be determined by the implant and therefore dynamically controllable through “sleep” commands.
The control flow of the controller is also shown below. In this case, the process begins by immediately checking Office 365 for client communication tasks (1). If tasks are available they are retrieved and split by client (2). If there are tasks from previously unseen clients, a class to handle client-specific variables and methods is instantiated (3). The resulting object contains a method that handles the per-client TCP socket to the Cobalt Strike team server (6), which is started in its own thread. The tasks received from Office 365 are then sorted by sequence number (4), and dispatched to the team server over the established TCP socket identified in the appropriate client object (each client is required to have its own connection) (5). Once dispatched the tasks are deleted from Office 365. Any responses from the team server (7) are immediately dispatched to Office 365 as tasks using the relevant client information (8). The approach for sending and retrieving tasks allows a simple means of controlling poll rates. The primary thread that handles the receiving process can be configured to process tasks from Office 365 in batches for all clients (e.g., to prevent a constant polling of the server), while the per-client threads automatically receive data from the team server and send them as tasks to Office 365 as required.
The following video shows the operation of a controller and three clients. In the example, the clients are using a fully staged implementation.
As can be seen, the response speed is reasonable despite the reliance on an external service, and the latency that this introduces from requiring request and response cycles on both the controller and clients. Despite the latency the proof-of-concept has been found to be able to support per-client download speeds of around 2MB per minute without efforts (so far) to improve efficiency. This is largely due to how a task can support a significant amount of data within its body. In future implementations other features of Office 365 could also be leveraged to increase speed, such as those that provide bulk upload of data.
This post has introduced the “External C2” interface for Cobalt Strike, and a proof-of-concept implementation that allows C2 traffic to traverse Office 365 using “tasks” within Outlook.
It should be noted that while the focus has fallen heavily on Office 365, this same approach is viable on any internet facing Exchange service, of which there are many commercial options available. One interesting example of this, for example, could be using a targeted organisation’s own Exchange service. In this case, the initial phase of the C2 communication (client to Exchange) would remain entirely inside an organisation’s network, with the only external traffic being that of the controller connecting to the organisation’s instance of Exchange. The downside (as an attacker) is that the defensive team would have access to Exchange's logs, which they would not do if an attacker-controlled Office 365 tenant is used.
The “External C2” interface is currently in its early stages and many challenges must be resolved before it can be used in a production setting; however, it is a clear marker of new opportunities for offensive teams for dynamic C2, and the dawn of exciting times for C2 research opportunities.