Guide to Named Pipes and Hunting for Cobalt Strike Pipes
Intro to Named Pipes
The way that helped me start to understand pipes is to think of them as like type of network socket that is created. It can be used to send and receive information between processes or even hosts.
As a rudimentary example, you can query the current pipes on your host:
Now lets try creating one. Below is a basic script to create a named pipe using PowerShell:
$pipeName = "bad_pipe"
$pipe = New-Object system.IO.Pipes.NamedPipeServerStream($pipeName)
Write-Host "Listening on \\.\pipe\$pipeName"
$sr = new-object System.IO.StreamReader($pipe);
Write-Host "I received a message: ", $msg
Write-Host "Pipe Creation Failed..."
Once running, it will listen for and data sent to it and write it to console. We can quickly test this by redirecting the stdout of a simple command:
echo "Sending data to pipe" >\\.\pipe\bad_pipe
See it in action here:
How Cobalt Strike uses Named Pipes
There is heaps of existing research on how Cobalt Strike utilises named pipes:
Detecting Cobalt Strike Default Modules via Named Pipe Analysis
During recent years, the Cobalt Strike framework has gained significant popularity amongst red teamers and threat…
Including from the Cobalt Strike blog:
Learn Pipe Fitting for all of your Offense Projects - Cobalt Strike Research and Development
Named pipes are a method of inter-process communication in Windows. They're used primarily for local processes to…
In this blog, Raphael Mudge (the creator of Cobalt Strike), notes some of the default pipe names. You can also customise the names of these pipes using Malleable C2 profiles.
See a sample of regexes for pipe names I put together from default and custom profiles below:
Using Velociraptor to Search for Malicious Named Pipes
When a process uses a named pipe, it creates a handle. Below is a sample of VQL that will walk through all running processes and pull the handles of the process. It will then search for any handles that match the regex
LET pipeRegex = 'bad_pipe'
LET processes = SELECT Pid AS ProcPid, Name AS ProcName, Exe
WHERE ProcPid > 0SELECT * FROM foreach(
SELECT ProcPid, ProcName, Exe, Type, Name, Handle
WHERE Name =~ pipeRegex
Using the example created before, I left the named pipe open and ran the VQL above in a notebook which returned the following result:
It recorded what process was using the pipe as well as the pipe name! Using the regex of some of the default named pipes lets put all this to the test.
In Cobalt Strike, the interface for creating a new SMB listener the default pipe name was
msagent_f8 which matches what we learnt before. I ran
jump psexec_psh to laterally move to a different host.
If we jump into Velociraptor, I created an artefact to search for any handles that match the regex outlined previously. You can see we have the process details as well as the pipe name of the SMB beacon.
This was a good start and found named pipes such as the SMB beacon that stay open for a long period of time, but it doesn’t catch the transient named pipes.
Of course, if you are lucky enough to have Sysmon deployed to the network already, you can easily monitor for these same named pipes as shown below:
Edit: I’m currently researching the possibility of monitoring named pipes with ETW and using Velociraptor further.