T1041 Microsoft Sentinel · KQL

Detect Exfiltration Over C2 Channel in Microsoft Sentinel

Adversaries may steal data by exfiltrating it over an existing command and control channel. Stolen data is encoded into the normal communications channel using the same protocol as command and control communications. This technique is particularly challenging to detect because exfiltration traffic is indistinguishable from regular C2 beaconing — adversaries embed collected data inside HTTP POST bodies, DNS query labels, custom binary protocol frames, or other C2 protocol fields. Detection requires correlating large outbound data volumes, repeated connection patterns, and sensitive file access rather than inspecting payload content. Real-world actors observed using this technique include Scattered Spider (VMware vCenter via Teleport), OilRig/APT34 (OneDrive-based C2), and malware families PoetRAT, Machete, Shark, StrelaStealer, BeaverTail, SLOTHFULMEDIA, Sagerunex, and Bandook. The technique spans Windows, Linux, macOS, and ESXi platforms and commonly exploits encrypted C2 channels (HTTPS, DNS-over-HTTPS) to blend with legitimate traffic.

MITRE ATT&CK

Tactic
Exfiltration
Technique
T1041 Exfiltration Over C2 Channel
Canonical reference
https://attack.mitre.org/techniques/T1041/

KQL Detection Query

Microsoft Sentinel (KQL)
kusto
let TimeWindow = 24h;
let MinBytesSent = 1048576; // 1 MB threshold — tune up for high-data environments
let MinConnectionCount = 20; // Repeated connections indicating active C2 with embedded data
let SuspiciousProcesses = dynamic([
    "powershell.exe", "pwsh.exe", "cmd.exe", "wscript.exe", "cscript.exe",
    "mshta.exe", "rundll32.exe", "regsvr32.exe", "certutil.exe",
    "python.exe", "python3.exe", "ruby.exe", "perl.exe",
    "curl.exe", "wget.exe", "bitsadmin.exe", "nc.exe"
]);
// Step 1: Identify processes with high outbound byte volume or high connection frequency to public IPs
let HighVolumeOutbound = DeviceNetworkEvents
| where Timestamp > ago(TimeWindow)
| where ActionType == "ConnectionSuccess"
| where RemoteIPType == "Public"
| where InitiatingProcessFileName has_any (SuspiciousProcesses)
    or BytesSent > MinBytesSent
| summarize
    TotalBytesSent = sum(BytesSent),
    TotalBytesReceived = sum(BytesReceived),
    ConnectionCount = count(),
    UniqueRemoteIPs = dcount(RemoteIP),
    RemoteIPs = make_set(RemoteIP, 5),
    RemotePorts = make_set(RemotePort, 5),
    FirstSeen = min(Timestamp),
    LastSeen = max(Timestamp)
    by DeviceName, AccountName, InitiatingProcessFileName, InitiatingProcessId, InitiatingProcessCommandLine
| where TotalBytesSent > MinBytesSent or ConnectionCount > MinConnectionCount;
// Step 2: Correlate with sensitive file reads (collect-then-exfil pattern)
let SensitiveFileReads = DeviceFileEvents
| where Timestamp > ago(TimeWindow)
| where ActionType == "FileRead"
| where FileName has_any (dynamic([".doc", ".docx", ".pdf", ".xlsx", ".xls", ".csv",
    ".zip", ".7z", ".tar", ".gz", ".kdbx", ".pfx", ".pem", ".key",
    ".db", ".sqlite", ".rdp", ".config", ".conf"]))
| summarize FilesRead = count(), SensitiveFileNames = make_set(FileName, 10)
    by DeviceName, InitiatingProcessId;
// Step 3: Join and score
HighVolumeOutbound
| join kind=leftouter SensitiveFileReads on DeviceName, InitiatingProcessId
| extend ExfilRatio = iff(TotalBytesReceived > 0,
    round(todouble(TotalBytesSent) / todouble(TotalBytesReceived), 2), 999.0)
| extend IsHighVolume = TotalBytesSent > MinBytesSent
| extend IsHighFrequency = ConnectionCount > MinConnectionCount
| extend IsSingleDestination = UniqueRemoteIPs == 1
| extend HasSensitiveFileAccess = isnotnull(FilesRead) and FilesRead > 0
| extend HighExfilRatio = ExfilRatio > 5.0
| extend ExfilScore = tolong(IsHighVolume) + tolong(IsHighFrequency)
    + tolong(IsSingleDestination) + tolong(HasSensitiveFileAccess) + tolong(HighExfilRatio)
| where ExfilScore >= 2
| project
    Timestamp = LastSeen,
    DeviceName,
    AccountName,
    InitiatingProcessFileName,
    InitiatingProcessCommandLine,
    TotalBytesSent,
    TotalBytesReceived,
    ExfilRatio,
    ConnectionCount,
    UniqueRemoteIPs,
    RemoteIPs,
    RemotePorts,
    FilesRead,
    SensitiveFileNames,
    IsHighVolume,
    IsHighFrequency,
    IsSingleDestination,
    HasSensitiveFileAccess,
    ExfilScore
| sort by ExfilScore desc, TotalBytesSent desc
high severity medium confidence

Detects data exfiltration over existing C2 channels by correlating high outbound data volumes, repeated connection frequency to public IPs, and sensitive file access from suspicious processes. Uses DeviceNetworkEvents to compute per-process outbound byte totals and connection counts, then joins with DeviceFileEvents to identify processes that both read sensitive files and make outbound connections (the collect-then-exfil pattern). A composite ExfilScore of 2 or higher triggers the alert, with higher scores indicating stronger exfiltration signals. BytesSent data may be sparse in some environments — if BytesSent is consistently 0, rely primarily on the ConnectionCount and file access correlation arms of the query.

Data Sources

Network Traffic: Network Connection CreationNetwork Traffic: Network Traffic FlowFile: File AccessMicrosoft Defender for Endpoint

Required Tables

DeviceNetworkEventsDeviceFileEvents

False Positives & Tuning

  • Backup agents (Veeam, Backup Exec, Azure Backup) performing scheduled backups generate large outbound transfers to cloud storage endpoints
  • Log shippers and telemetry agents (Splunk Universal Forwarder, Elastic Agent, Datadog) make frequent high-volume connections to their ingestion endpoints
  • Cloud sync clients (OneDrive, Dropbox, Google Drive) continuously upload large volumes of data using common scripting engines on managed endpoints
  • Software update and patch management clients (SCCM, Intune, WSUS) sending device inventory telemetry over HTTPS to Microsoft infrastructure
  • Security scanners and vulnerability assessment tools (Qualys, Nessus agent) making high-frequency outbound connections during scan cycles
Download portable Sigma rule (.yml)

Other platforms for T1041


Testing Methodology

Validate this detection against 4 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.

  1. Test 1PowerShell HTTP POST Exfiltration Over Simulated C2 Channel

    Expected signal: Sysmon Event ID 1: Process Create — powershell.exe with CommandLine containing Invoke-WebRequest, -Method POST, and http://127.0.0.1:8080/beacon. Sysmon Event ID 3: Network Connection — powershell.exe connecting to 127.0.0.1:8080. PowerShell ScriptBlock Log Event ID 4104 capturing the full script including the base64-encoded data construction. DeviceNetworkEvents in MDE: ConnectionSuccess or ConnectionFailed (depending on listener) with InitiatingProcessFileName=powershell.exe, RemoteIP=127.0.0.1, RemotePort=8080.

  2. Test 2curl Multi-Connection Data Exfiltration Beaconing Pattern

    Expected signal: 25x Sysmon Event ID 3: Network Connection events with Image=curl.exe (or full path), DestinationIp=127.0.0.1, DestinationPort=8080, Initiated=true. DeviceNetworkEvents: 25 ConnectionSuccess/ConnectionFailed records for curl.exe to 127.0.0.1:8080. The aggregate ConnectionCount of 25 crosses the MinConnectionCount=20 threshold in the KQL detection query. SPL ExfilScore increases as IsHighFrequency becomes 1 once count exceeds 20.

  3. Test 3DNS Data Exfiltration via Encoded Subdomain Labels

    Expected signal: Sysmon Event ID 22 (DNS Query): 10 DNS query events with QueryName containing 40-55 character first labels encoding the Base64 data, initiated by nslookup.exe. The DNS hunting query triggers on LongestLabel > 40 and QueryCount > 5 from the same process. Windows DNS Client Event Log may also record the queries. The queries will fail to resolve (no listener on 127.0.0.1:53) but the Sysmon Event ID 22 fires on the query attempt regardless.

  4. Test 4Linux curl Data Exfiltration via HTTP POST

    Expected signal: auditd: SYSCALL records for execve (curl), connect() calls to 127.0.0.1:8080, and read() on /etc/hostname and /proc. Sysmon for Linux Event ID 3: Network Connection events for curl process. Linux audit log (if auditd configured with network rules): socket()/connect() syscalls from curl with destination 127.0.0.1:8080. CommonSecurityLog or Syslog in Sentinel if auditd logs are forwarded: 15 connection records with consistent user-agent string indicating automated beaconing. The deceptive Windows user-agent string on a Linux process is itself anomalous.

Unlock Pro Content

Get the full detection package for T1041 including response playbook, investigation guide, and atomic red team tests.

Response PlaybookInvestigation GuideHunting QueriesAtomic Red Team TestsTuning Guidance

Related Detections