ID: 0xFF-0222-Suspicious_Named_Pipes-Win
OS: WindowsEndpoint, WindowsServer
FP Rate: Low
Tactic | Technique | Subtechnique | Technique Name |
---|---|---|---|
TA0002 - Execution | T1559 | Inter-Process Communication | |
TA0005 - Defense Evasion | T1055 | Process Injection |
Log Provider | Event ID | Event Name | ATT&CK Data Source | ATT&CK Data Component |
---|---|---|---|---|
MicrosoftThreatProtection | NamedPipeEvent | Named Pipe | Named Pipe Metadata |
This rule looks for Named Pipe events that either contain one of the known IOCs or make use of patterns that can be linked to CobaltStrike usage.
User
CobaltStrike is used as a post-exploitation tool with various malware droppers responsible for the initial infection stage. Named pipes are used to send the output of the post-exploitation tools to the beacon. CobaltStrike is using default unique pipe names, which defenders can use for detection. However, CobaltStrike allows the operators to change the name of the pipes to any name of their choosing by configuring the malleable C2 profile accordingly.
None.
None expected.
Investigate this host immediately, when the pipe name and originating process look suspicious isolate the machine and validate where the file came from and where the host has been communicating.
Pipe names outside of the queried names.
- https://gist.github.com/MHaggis/6c600e524045a6d49c35291a21e10752
- https://labs.f-secure.com/blog/detecting-cobalt-strike-default-modules-via-named-pipe-analysis/
Language: Kusto
Platform: M365 Security
Query:
let timeframe = 2*1h;
let CobaltStrikeDefaults= dynamic([@"msagent_", @"MSSE-", @"postex_", @"status_", @"mypipe-f", @"mypipe-h",@"ntsvcs_",@"scerpc_", @"mojo.5688.8052."]);
let CobaltStrikeMallable= dynamic([@"win_svc", @"ntsvcs", @"scerpc", @"status_", @"SearchTextHarvester", @"DserNamePipe",@"wkssvc_",@"scerpc_", @"spoolss_",@"CatalogChangeListener",@"fullduplex_",@"demoagent_",@"PGMessagePipe",@"MsFteWds",@"postex_ssh_",@"windows.update.manager",@"\f4c3",@"\f53f",@"halfduplex_"]);
DeviceEvents
| where ingestion_time() >= ago(timeframe)
| where ActionType == "NamedPipeEvent"
| extend AdditionalFields=parse_json(AdditionalFields)
| extend ThreadId=tostring(AdditionalFields.ThreadId)
| extend PipeName=tostring(AdditionalFields.PipeName)
// Creating string based variants of the processIDs for matching several times later.
| extend InitiatingPID=tostring(InitiatingProcessId)
| extend InitiatingParentPID=tostring(InitiatingProcessParentId)
// Begin environment-specific filter.
// End environment-specific filter.
| where PipeName has_any (CobaltStrikeDefaults) or
// Mojo is generated by Chrome(ium) browsers and teams and have distinct pattern including the (parent)ProcessId and ThreadId plus a random character string, CobaltStrike generates hex.
(PipeName matches regex @"\\mojo\.\d+\.\d+\." and not(PipeName matches regex @"\\mojo\.\d+\.\d+\.\d+$" or PipeName has InitiatingPID or PipeName has InitiatingParentPID or PipeName has ThreadId)) or
// Chromium browsers sync processes have distinct pattern including the (parent)ProcessId and ThreadId plus a random character string, CobaltStrike generates hex.
(PipeName matches regex @"\\(edge|chrome)\.sync\.\d+\.\d+\." and not(PipeName matches regex @"\\(edge|chrome|edge\.sync|chrome\.sync)\.\d+\.\d+\.\d+$" or PipeName has InitiatingPID or PipeName has InitiatingParentPID or PipeName has ThreadId)) or
// PSHost is generated by PowerShell and has a distinct pattern including the (parent)ProcessId.
(PipeName matches regex @"\\PSHost\.\d+\." and not(PipeName matches regex @"\\PSHost\.\d+\.\d+\." or PipeName has InitiatingPID or PipeName has InitiatingParentPID)) or
// Crashpad pipes have a distinct pattern including the ProcessId and a string of upper case characters.
(PipeName matches regex @"\\crashpad_" and not(PipeName matches regex @"\\crashpad_\d+_[A-Z]+" or PipeName has InitiatingPID or PipeName has InitiatingParentPID)) or
// Firefox pipes have a distinct pattern including the ProcessId and 1-3 digits which are sequential for each new pipe.
(PipeName matches regex @"\\cubeb-pipe-" and not(PipeName matches regex @"\\cubeb-pipe-\d+_[0-9]{1-3}+" or PipeName has InitiatingPID)) or
// Based on a list of public mallable profiles and a suffix that is a random HEX string.
(PipeName has_any (CobaltStrikeMallable) and PipeName matches regex @"[a-fA-F0-9]{2,10}$") or
(PipeName matches regex @"\\pipe\\[0-9a-f]{7,10}" or PipeName matches regex @"\\pipe\\[0-9a-f]{8}")
Version | Date | Impact | Notes |
---|---|---|---|
1.2 | 2022-02-22 | minor | Use ingestion_time for event selection and include de-duplication logic. |
1.1 | 2022-01-14 | major | Additional pipe and big performance tweaks |
1.0 | 2021-12-24 | major | Initial version |