As a product vendor, I regularly receive suggestions from my users. It’s easy to break these suggestions up into different categories. One such category would be Beacon communication channels. I get requests that ask when I will look into various protocols or third-party services as communication channels.
I see communication options as very important. But, not all channels are created equal. In this blog post, I’d like to share the rubric I use to decide if a channel is right for Beacon.
Rule #1: A native Windows API must exist
When I build a channel into Beacon, I look for channels that I can implement with the APIs Windows provides. I like Windows APIs because they give me a lot for free. Right now, Beacon uses the WinINet API for its HTTP and HTTPS channel. This API provides a simple way to make RFC compliant HTTP requests to my web server. It also pulls the proxy settings for the system and transparently handles proxy authentication for me. The more I can offload to tried and true Windows APIs, the better.
Rule #2: Staging must be possible
Implementing a channel as a Windows API has the benefit of keeping my implementation simple and small. This plays directly into my next rule: Whichever channel I implement, it must be feasible to write position-independent assembly code to stage Beacon over that same channel.
Staging is an important part of Cobalt Strike’s workflow. Most payload stages, by themselves, are too big to pair well with most attacks. The work-around is to break payload delivery up into stages. The first stage (also called the stager) connects to the attacker and downloads the second stage (also called the payload stage). The stager creates a place in memory to store the payload stage and passes execution to the stage once the download is complete.
Small stagers embed well into Cobalt Strike’s built-in attack packages. Small stagers also allow me to use a PowerShell one-liner, during lateral movement, to bootstrap a payload into memory without putting a binary on disk. One of my favorite Cobalt Strike demos is the one where I embed a DNS TXT record stager for Beacon into a Word macro.
Staging isn’t important for all payloads. Some payloads are designed to persist on disk and maintain access over a long period of time. By the time you’re ready to drop tools on disk, it’s probably safe to assume that you have some other channel to upload your persistence payload and run its installer through. For Beacon, this isn’t the case. I assume that Beacon is the payload you will use for your first foothold into a network. Because of this assumption, staging matters a great deal.
Rule #3: No third-party services
A lot of folks like to demonstrate payloads that use Gmail, Twitter, and other social media tools as a communication intermediary. Great stuff! I don’t expect that I will build features into Beacon that rely on specific third-party services.
I worry that a third-party service could change in a way that breaks my payload. As the developer of a paid and supported product, this is not a headache I want to take on.
I don’t want to be too much of a curmudgeon on this topic. Third-party service-based C2 offers a red teamer [and adversary] many benefits. A well-executed implementation will make it hard for a network monitoring staff to pick out legitimate activity from malicious activity. Some environments use reputation-based indicators to allow users unhindered access to well-known sites, but to make it harder for malware to connect to controllers on the Internet. The use of third-party services is a way to deal with this pain.
Rule #4: Must work from a user-level context, without special rights
A persistent agent has the luxury of assuming SYSTEM-level rights. An agent designed for an initial foothold and post-exploitation does not. I very much see Beacon as a stable lifeline and a post-exploitation agent. Because of this assumption, it’s important that the communication options I implement will work from a user-level context.
Rule #5: The protocol must (commonly) egress, if it can’t, it’s a peer-to-peer protocol. The server component of peer-to-peer protocols must follow these rules.
Beacon has two types of channels. It has channels meant to egress (HTTP/S and DNS) and it has a channel meant for peer-to-peer communication. If a channel cannot egress (e.g., the SMB channel) then it’s a peer-to-peer channel. Peer-to-peer channels require that Beacon hosts the server component too. In these cases, the server component must meet these criteria before I consider the channel appropriate.
A good example is ICMP. Eventually, I will probably build an ICMP channel for Beacon. It fits these rules. There’s a Windows API to send ICMP echo requests and receive the response. This is something that I could build a stager for. It doesn’t depend on a third-party service. I can use the ICMP API without special rights. And, ICMP is a protocol that’s allowed to egress some situations. ICMP passes these tests.
Keep in mind, these are the rules I use for Beacon. These rules are not applicable to all payloads and all use cases. Beacon is a user-land lifeline and a post-exploitation payload. These use cases require that I meet their needs and constraints. The design decisions for these use cases are sometimes counter to the decisions I would make for a payload built for other purposes (e.g., persistence). When you look at payloads, it’s important to think about what the payload is originally built for and to use it in those contexts. This will help you get the most from the capability.