Network traffic is one of the richest detection data sources available to a SOC — and one of the most underutilized. Endpoint detections catch what happens on a machine. Network detections catch what the machine is talking to, and that's often the only signal available for attacks that live entirely in memory, use legitimate tools, or evade endpoint controls.
This post covers the network traffic patterns that matter most for SOC detection — DNS anomalies, C2 beaconing, lateral movement over SMB, and data exfiltration — with production detection queries for each.
Log Sources Required
Network traffic analysis in a SIEM depends on which log sources are being ingested. The detection queries in this post require one or more of these:
- DNS logs — from Windows DNS Server, Infoblox, Umbrella, or endpoint DNS events from CrowdStrike or Sysmon (Event ID 22)
- Firewall/proxy logs — outbound connection attempts, blocked traffic, URL categories from Palo Alto, Fortinet, Zscaler, or similar
- NetFlow/IPFIX — connection metadata without payload — source IP, destination IP, port, bytes transferred, duration
- CrowdStrike network events — NetworkConnectIP4, DnsRequest event types from the Falcon sensor
- Defender network events — DeviceNetworkEvents table in Sentinel
1. DNS Anomaly Detection
DNS is the most abused protocol in enterprise networks. C2 frameworks use DNS tunneling to communicate through firewalls. Attackers use algorithmically generated domains (DGA) that rotate automatically. Data can be exfiltrated byte by byte through DNS query strings. And because DNS is essential infrastructure, it's rarely blocked at the perimeter.
High-volume DNS queries to a single domain
DeviceNetworkEvents | where TimeGenerated > ago(1d) | where ActionType == "DnsQueryResponse" | extend Domain = tostring(RemoteUrl) // Extract registered domain (last two parts) | extend RegDomain = extract( @"([^.]+\.[^.]+)$", 1, Domain) | where isnotempty(RegDomain) // Exclude known-good domains | where RegDomain !in( "microsoft.com", "windows.com", "office.com", "windowsupdate.com" ) | summarize QueryCount = count(), UniqueSubdomains = dcount(Domain), AvgQueryLength = avg(strlen(Domain)) by DeviceName, RegDomain, bin(TimeGenerated, 1h) | where QueryCount > 100 or UniqueSubdomains > 50 or AvgQueryLength > 50 | order by QueryCount desc
Three signals together are a near-certain DNS tunnel: high unique subdomain count, long average query length (over 50 chars), and consistent query intervals. Any one alone might be benign — a CDN with many subdomains, a long hostname, periodic software checks. All three together almost always means data is being encoded into DNS query strings.
DGA domain detection — high entropy domain names
index=dns_* earliest=-24h | rex field=query "(?P<domain>[^.]+)\.[^.]+\.[^.]+$" | eval domain_len=len(domain) /* Calculate consonant ratio — DGA domains have few vowels */ | eval vowels=len(replace(domain, "[aeiouAEIOU]", "")) | eval consonant_ratio=round(vowels/domain_len, 2) | where domain_len >= 12 AND consonant_ratio > 0.75 | stats count as QueryCount values(query) as Domains by src_ip | where QueryCount > 5 | sort - QueryCount
2. C2 Beaconing Detection
C2 beaconing is the regular check-in traffic from a compromised host to attacker infrastructure. Most C2 frameworks implement a beacon with a configurable sleep interval and some degree of jitter to evade detection. The signal is a host making connections to an external IP or domain at suspiciously regular intervals — often every 30, 60, or 300 seconds — that don't match any known application behavior.
DeviceNetworkEvents | where TimeGenerated > ago(6h) | where ActionType == "ConnectionSuccess" | where RemoteIPType == "Public" // Group connections by host and destination | summarize ConnectionTimes = make_list(TimeGenerated), ConnectionCount = count(), BytesSent = sum(SentBytes) by DeviceName, RemoteIP, RemotePort | where ConnectionCount > 10 // Calculate variance in connection intervals | extend SortedTimes = array_sort_asc(ConnectionTimes) | mv-expand with_itemindex=i SortedTimes | extend SortedTimes = todatetime(SortedTimes) | serialize | extend PrevTime = prev(SortedTimes) | where isnotnull(PrevTime) | extend IntervalSeconds = datetime_diff('second', SortedTimes, PrevTime) | summarize AvgInterval = avg(IntervalSeconds), StdDevInterval = stdev(IntervalSeconds) by DeviceName, RemoteIP, RemotePort, ConnectionCount // Low standard deviation = regular interval = beaconing | where StdDevInterval < 30 and AvgInterval between (20 .. 3600) | order by StdDevInterval asc
This query will catch legitimate software that beacons regularly — Windows Update, antivirus, monitoring agents. Build an allowlist of known-good destination IPs and add a NOT IN exclusion before deploying. Run it first in hunt mode to understand your environment's baseline before making it a scheduled alert.
3. SMB Lateral Movement
SMB — Server Message Block — is the Windows file sharing protocol and one of the primary channels for lateral movement. Pass-the-hash, PsExec, WMI, and many other lateral movement techniques use SMB. The detection focuses on workstation-to-workstation SMB connections, which are almost never legitimate in a well-segmented network.
DeviceNetworkEvents | where TimeGenerated > ago(1d) | where RemotePort == 445 | where ActionType == "ConnectionSuccess" // Exclude servers connecting to servers // Focus on workstations (typically non-server naming) | where DeviceName !startswith("SRV") and DeviceName !startswith("SVR") and DeviceName !startswith("DC") | summarize ConnectionCount = count(), TargetHosts = dcount(RemoteIP), TargetList = make_set(RemoteIP) by DeviceName, InitiatingProcessAccountName | where TargetHosts > 3 | order by TargetHosts desc
4. Large Data Transfer Detection
Data exfiltration doesn't always use exotic protocols — sometimes it's just a large HTTPS upload to a cloud storage service. The signal is volume: a host transferring significantly more data outbound than its baseline over a short window.
#event_simpleName=NetworkConnectIP4 RemotePort IN [80, 443, 8080, 8443] | groupBy([ComputerName, RemoteAddressIP4], function=[ sum(field=BytesSent, as=TotalBytesSent), count(as=ConnectionCount) ]) // Flag transfers over 500MB to single destination | where TotalBytesSent > 524288000 | eval(GBSent = TotalBytesSent / 1073741824) | sort(TotalBytesSent, order=desc)
DNS tunneling detection, beaconing queries, SMB lateral movement — network-based detections appear regularly alongside endpoint rules. Every issue includes the full detection with required log sources, false positive guidance, investigation steps, and MITRE mapping.
Join — $14.99/mo See a Sample Issue