Command and Control (TA0011)
Sub-technique: T1071.001 - Web Protocols
Objective: Detect command and control (C2) communications using web protocols.
Detect Suspicious Web Traffic
DeviceNetworkEvents
| where RemotePort == 80 or RemotePort == 443
| summarize count() by RemoteIP, LocalIP
| where count() > 50
//Extended Search
DeviceNetworkEvents
| where RemotePort == 80 or RemotePort == 443
| summarize ConnectionCount = count() by RemoteIP, DeviceName
| where ConnectionCount > 50
| join kind=leftouter (
DeviceFileEvents
| where FileName endswith ".zip" or FileName endswith ".rar"
| summarize ArchiveFileCount = count() by DeviceName
) on DeviceName
| join kind=leftouter (
DeviceProcessEvents
| where ProcessCommandLine has_any ("curl", "wget", "POST")
| summarize ProcessCount = count() by DeviceName
) on DeviceName
| project RemoteIP, DeviceName, ConnectionCount, ArchiveFileCount, ProcessCount
| order by ConnectionCount desc
Purpose: Identify unusual web traffic patterns.
Monitor for Web Protocols Used by Malware
DeviceNetworkEvents | where RemotePort == 80 or RemotePort == 443 | where InitiatingProcessCommandLine has_any ("curl", "wget") | project Timestamp, DeviceName, RemoteIP, InitiatingProcessCommandLine
//Extended Search
DeviceNetworkEvents
| where RemotePort == 80 or RemotePort == 443
| join kind=leftouter (
DeviceProcessEvents
| where ProcessCommandLine has_any ("curl", "wget")
| summarize ProcessCount = count() by DeviceName, ProcessCommandLine
) on DeviceName
| summarize ConnectionCount = count() by RemoteIP, DeviceName, ProcessCommandLine
| where ConnectionCount > 50
| join kind=leftouter (
DeviceFileEvents
| where FileName endswith ".pcap" or FileName endswith ".cap"
| summarize FileCount = count() by DeviceName
) on DeviceName
| project RemoteIP, DeviceName, ProcessCommandLine, ConnectionCount, FileCount
| order by ConnectionCount desc
//Another Option for Search
DeviceNetworkEvents
| where RemotePort == 80 or RemotePort == 443
| join kind=leftouter (
DeviceProcessEvents
| where InitiatingProcessCommandLine has_any ("curl", "wget")
| summarize ProcessCount = count() by DeviceName, InitiatingProcessCommandLine
) on DeviceName
| summarize ConnectionCount = count() by RemoteIP, DeviceName, InitiatingProcessCommandLine
| where ConnectionCount > 50
| join kind=leftouter (
DeviceFileEvents
| where FileName endswith ".pcap" or FileName endswith ".cap"
| summarize FileCount = count() by DeviceName
) on DeviceName
| project RemoteIP, DeviceName, InitiatingProcessCommandLine, ConnectionCount, FileCount
| order by ConnectionCount desc
Purpose: Detect web protocols commonly used by malware.
Identify Outbound HTTP POST Requests
DeviceNetworkEvents
| where RemotePort == 80 or RemotePort == 443 and ProcessCommandLine has "POST"
| project Timestamp, DeviceName, RemoteIP, ProcessCommandLine
//Extended Search
DeviceNetworkEvents
| where RemotePort == 80 or RemotePort == 443
| join kind=leftouter (
DeviceProcessEvents
| where ProcessCommandLine has "POST" or ProcessCommandLine has_any ("curl", "wget")
| summarize ProcessCount = count() by DeviceName, ProcessCommandLine
) on DeviceName
| summarize ConnectionCount = count() by RemoteIP, DeviceName, ProcessCommandLine, InitiatingProcessAccountName, InitiatingProcessFileName
| where ConnectionCount > 50
| join kind=leftouter (
DeviceFileEvents
| where FileName endswith ".pcap" or FileName endswith ".cap"
| summarize FileCount = count() by DeviceName
) on DeviceName
| project RemoteIP, DeviceName, ProcessCommandLine, ConnectionCount, FileCount, InitiatingProcessAccountName, InitiatingProcessFileName
| order by ConnectionCount desc
Purpose: Monitor for outbound HTTP POST requests used for C2.
Detect Long-Lived HTTP Connections
DeviceNetworkEvents
| where RemotePort == 80 or RemotePort == 443
| extend DurationSeconds = toint(Timestamp - InitiatingProcessCreationTime) / 1000
| summarize avg_DurationSeconds = avg(DurationSeconds) by RemoteIP, DeviceName
| where avg_DurationSeconds > 600
| project RemoteIP, DeviceName, avg_DurationSeconds
| order by avg_DurationSeconds desc
Purpose: Identify long-lived HTTP connections that could indicate C2.
Monitor for Unusual DNS Queries
DeviceNetworkEvents
| where RemotePort == 53 and ActionType == "Query"
| summarize count() by RemoteIP
| where count() > 200
//Extended Search
DeviceNetworkEvents
| where RemotePort == 53 and ActionType == "Query"
| summarize QueryCount = count() by RemoteIP, DeviceName
| where QueryCount > 200
| join kind=leftouter (
DeviceFileEvents
| where FileName endswith ".zip" or FileName endswith ".rar"
| summarize ArchiveFileCount = count() by DeviceName
) on DeviceName
| join kind=leftouter (
DeviceProcessEvents
| where ProcessCommandLine has_any ("dns", "query", "lookup")
| summarize ProcessCount = count() by DeviceName
) on DeviceName
| project RemoteIP, DeviceName, QueryCount, ArchiveFileCount, ProcessCount
| order by QueryCount desc
Purpose: Detect excessive DNS queries.
Detect Use of Web Shells
DeviceFileEvents
| where FileName endswith ".aspx" or FileName endswith ".php"
| project Timestamp, DeviceName, FileName, FolderPath, InitiatingProcessAccountName, InitiatingProcessCommandLine
| order by Timestamp desc
//Extended Search
DeviceFileEvents
| where FileName endswith ".aspx" or FileName endswith ".php"
| summarize FileAccessCount = count() by DeviceName, FileName, FolderPath, InitiatingProcessAccountName, InitiatingProcessCommandLine
| join kind=leftouter (
DeviceProcessEvents
| where ProcessCommandLine has_any ("powershell", "cmd", "bash")
| summarize ProcessCount = count() by DeviceName
) on DeviceName
| join kind=leftouter (
DeviceNetworkEvents
| where RemotePort == 80 or RemotePort == 443
| summarize ConnectionCount = count() by DeviceName
) on DeviceName
| project DeviceName, FileName, FolderPath, InitiatingProcessAccountName, InitiatingProcessCommandLine, FileAccessCount, ProcessCount, ConnectionCount
| order by FileAccessCount desc
Purpose: Monitor for the presence of web shells on servers.
Identify HTTPS Traffic to Unusual Domains
DeviceNetworkEvents
| where RemotePort == 443 and RemoteIP !in ("known_good_ips")
| summarize count() by RemoteIP, LocalIP
| where count() > 20
//Extended Search
```kusto
DeviceNetworkEvents
| where RemotePort == 443 and RemoteIP !in ("known_good_ips")
| summarize ConnectionCount = count() by RemoteIP, DeviceName, InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessCommandLine
| where ConnectionCount > 20
| join kind=leftouter (
DeviceFileEvents
| where FileName endswith ".zip" or FileName endswith ".rar"
| summarize ArchiveFileCount = count() by DeviceName
) on DeviceName
| join kind=leftouter (
DeviceProcessEvents
| where ProcessCommandLine has_any ("curl", "wget", "POST")
| summarize ProcessCount = count() by DeviceName
) on DeviceName
| project RemoteIP, DeviceName, ConnectionCount, ArchiveFileCount, ProcessCount, InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessCommandLine
| order by ConnectionCount desc
Purpose: Detect HTTPS traffic to unusual or unknown domains.
Monitor for Suspicious User-Agents
DeviceNetworkEvents
| where RemotePort == 80 or RemotePort == 443
| where ProcessCommandLine has_any ("User-Agent: Mozilla", "User-Agent: curl")
| project Timestamp, DeviceName, RemoteIP, ProcessCommandLine
//Extended Search
DeviceNetworkEvents
| where RemotePort == 80 or RemotePort == 443
| join kind=leftouter (
DeviceProcessEvents
| where ProcessCommandLine has_any ("User-Agent: Mozilla", "User-Agent: curl")
| summarize ProcessCount = count() by DeviceName, ProcessCommandLine
) on DeviceName
| summarize ConnectionCount = count() by RemoteIP, DeviceName, ProcessCommandLine, InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessCommandLine
| where ConnectionCount > 50
| join kind=leftouter (
DeviceFileEvents
| where FileName endswith ".pcap" or FileName endswith ".cap"
| summarize FileCount = count() by DeviceName
) on DeviceName
| project RemoteIP, DeviceName, ProcessCommandLine, ConnectionCount, FileCount, InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessCommandLine
| order by ConnectionCount desc
Purpose: Detect unusual or spoofed user-agents in web traffic.
Detect Traffic to Known Malicious Domains
DeviceNetworkEvents | where RemoteIP in ("known_malicious_ips") | summarize count() by RemoteIP, LocalIP, InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessCommandLine
//Extended Search
DeviceNetworkEvents
| where RemoteIP in ("known_malicious_ips")
| summarize ConnectionCount = count() by RemoteIP, DeviceName, InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessCommandLine
| join kind=leftouter (
DeviceFileEvents
| where FileName endswith ".zip" or FileName endswith ".rar"
| summarize ArchiveFileCount = count() by DeviceName
) on DeviceName
| join kind=leftouter (
DeviceProcessEvents
| where ProcessCommandLine has_any ("curl", "wget", "POST")
| summarize ProcessCount = count() by DeviceName
) on DeviceName
| project RemoteIP, DeviceName, ConnectionCount, ArchiveFileCount, ProcessCount, InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessCommandLine
| order by ConnectionCount desc
Purpose: Identify traffic to known malicious IP addresses.
Identify Suspicious WebSocket Connections
DeviceNetworkEvents
| where RemotePort == 443
| join kind=leftouter (
DeviceProcessEvents
| where ProcessCommandLine has "websocket"
| summarize ProcessCount = count() by DeviceName, ProcessCommandLine, InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessCommandLine
) on DeviceName
| project Timestamp, DeviceName, RemoteIP, ProcessCommandLine, InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessCommandLine
| order by Timestamp desc
//Extended Search
DeviceNetworkEvents
| where RemotePort == 443
| join kind=leftouter (
DeviceProcessEvents
| where ProcessCommandLine has "websocket"
| summarize ProcessCount = count() by DeviceName, ProcessCommandLine, InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessCommandLine
) on DeviceName
| join kind=leftouter (
DeviceFileEvents
| where FileName endswith ".zip" or FileName endswith ".rar"
| summarize ArchiveFileCount = count() by DeviceName
) on DeviceName
| join kind=leftouter (
DeviceNetworkEvents
| where RemotePort == 80 or RemotePort == 443
| summarize ConnectionCount = count() by DeviceName
) on DeviceName
| project Timestamp, DeviceName, RemoteIP, ProcessCommandLine, InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessCommandLine, ArchiveFileCount, ConnectionCount
| order by Timestamp desc
Purpose: Monitor for WebSocket connections used for C2.
Last updated