Beacon is my payload for low and slow control of a compromised system. Recently, I added peer-to-peer communication to Beacon. When two Beacons are linked, the child Beacon will get its tasks from and send its output through its parent. Linked Beacons use SMB pipes to communicate. This is a big win for stealth. If a workstation Beacon communicates with a domain controller Beacon over SMB, who would notice?
I invested in this feature for several reasons: I wanted the ability to control an internet isolated host with Beacon. I also wanted to control many compromised systems through one or two egress hosts. And, I thought it would be really cool to tunnel a Meterpreter session over SMB. These things are all doable now.
Cobalt Strike‘s Beacon isn’t the only offensive tool to use named pipes in this way. The Red October malware (see the Kaspersky report) has this feature. The Duqu malware that Symantec analyzed has this ability too. If you want to replicate the C&C styles of advanced threats, Cobalt Strike has you covered.
SMB Named Pipes
Let’s go through how this communication mechanism works. It’s actually pretty easy. A named pipe is an inter-process communication mechanism on Windows.
The CreateNamedPipe function will set up a named pipe. The PIPE_ACCESS_DUPLEX flag makes the named pipe into a bi-directional channel.
server = CreateNamedPipe("\\\\.\\pipe\\crack", PIPE_ACCESS_DUPLEX, ...);
The CreateFile function connects to a named pipe.
client = CreateFile("\\\\.\\pipe\\crack", GENERIC_READ | GENERIC_WRITE, ...);
Use the ReadFile and WriteFile functions to read data from and send data through a named pipe.
Named pipes become interesting when they communicate between processes on separate hosts. Change the period in the pipe name to an IP address. Now the client will communicate with the pipe on the remote system.
client = CreateFile("\\\\192.168.95.18\\pipe\\crack", GENERIC_READ | GENERIC_WRITE, ...);
Named pipe communication between hosts is encapsulated in SMB. Here’s what it looks like in Wireshark.
This communication method is not without its constraints. Any system I link to must have port 445 open. If I use a Beacon peer to control a key server, like a domain controller, this isn’t unreasonable. Any Beacon that connects to another Beacon must have an access token or it must establish an SMB session with the target first. This is because Beacon does not create an anonymous pipe. An anonymous pipe would require a change in the registry.
For Beacon users, this peer-to-peer technology isn’t just a new data channel. It’s also an opportunity to use Beacon as an in-memory backdoor for Windows hosts.
Once you deliver a Beacon peer to a host (or use mode smb to turn a Beacon into a peer), it creates a named pipe and waits for a connection from another Beacon. You may link to it right away. You don’t have to though. After you link to a Beacon, you may unlink it at any time. When you unlink a Beacon peer, it waits for a connection from another Beacon.
Tunneling traffic through linked Beacons works like you’d expect. If I create a Meterpreter session, tunneled through a Beacon peer, that traffic will reach Cobalt Strike through the peer’s parent Beacon.
Let’s say I unlink a Beacon peer while tunneling a Meterpreter session through it. Then I quickly link that Beacon peer to another Beacon. What happens to my tunneled session? Nothing. My tunneled session will continue to work. Its traffic will go through the new parent Beacon. This is quite neat. You’re redefining a tunnel’s egress host, on the fly.
There’s a lot of possibility here.