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.

Get-ChildItem \\.\pipe\
try {
$pipeName = "bad_pipe"
$pipe = New-Object system.IO.Pipes.NamedPipeServerStream($pipeName)
Write-Host "Listening on \\.\pipe\$pipeName"
$pipe.WaitForConnection();
$sr = new-object System.IO.StreamReader($pipe);
$msg= $sr.ReadLine()
Write-Host "I received a message: ", $msg
}
catch {
Write-Host "Pipe Creation Failed..."
$_
return 0
}
echo "Sending data to pipe" >\\.\pipe\bad_pipe

How Cobalt Strike uses Named Pipes

There is heaps of existing research on how Cobalt Strike utilises named pipes:

Including from the Cobalt Strike blog:

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 bad_pipe.

LET pipeRegex = 'bad_pipe'
LET processes = SELECT Pid AS ProcPid, Name AS ProcName, Exe
FROM pslist()
WHERE ProcPid > 0
SELECT * FROM foreach(
row=processes,
query={
SELECT ProcPid, ProcName, Exe, Type, Name, Handle
FROM handles(pid=ProcPid)
WHERE Name =~ pipeRegex
})