Detect BITS Jobs in Microsoft Sentinel
Adversaries may abuse Windows Background Intelligent Transfer Service (BITS) jobs to persistently execute code and perform background tasks such as downloading malicious payloads, executing arbitrary programs on job completion or error, and cleaning up artifacts. BITS is a COM-based file transfer mechanism built into Windows, commonly used by Windows Update and software installers. Adversaries exploit it via bitsadmin.exe or PowerShell BITS cmdlets to download tools from external infrastructure, achieve persistence using /SetNotifyCmdLine to invoke arbitrary executables when a job completes or errors (including after reboots), and exfiltrate data. BITS jobs are stored in a binary database (%ALLUSERSPROFILE%\Microsoft\Network\Downloader\) rather than in registry or filesystem, making them resistant to many persistence-focused detections. Active threat groups including APT39, APT41, Leviathan, Patchwork, and Wizard Spider have leveraged BITS for payload delivery and persistence.
MITRE ATT&CK
- Tactic
- Defense Evasion Persistence
- Technique
- T1197 BITS Jobs
- Canonical reference
- https://attack.mitre.org/techniques/T1197/
KQL Detection Query
let SuspiciousDestinations = dynamic([
"\\AppData\\Local\\Temp\\", "\\AppData\\Roaming\\",
"\\Users\\Public\\", "\\ProgramData\\",
"\\Windows\\Temp\\", "C:\\Temp\\"
]);
let SuspiciousExtensions = dynamic([
".exe", ".dll", ".ps1", ".bat", ".cmd", ".vbs", ".js", ".hta"
]);
let BitsBinaryPatterns = dynamic([
"/transfer", "/create", "/addfile", "/SetNotifyCmdLine",
"/SetNotifyFlags", "/resume", "/complete", "/reset",
"Start-BitsTransfer", "New-BitsTransfer", "Add-BitsFile"
]);
// Branch 1: bitsadmin.exe execution with suspicious arguments
let BitsAdminExec = DeviceProcessEvents
| where Timestamp > ago(24h)
| where FileName =~ "bitsadmin.exe"
| extend HasNotify = ProcessCommandLine has_any ("/SetNotifyCmdLine", "/SetNotifyFlags")
| extend HasTransfer = ProcessCommandLine has_any ("/transfer", "/addfile")
| extend HasReset = ProcessCommandLine has "/reset"
| extend SuspiciousDest = ProcessCommandLine has_any (SuspiciousDestinations)
| extend SuspiciousExt = ProcessCommandLine has_any (SuspiciousExtensions)
| extend DownloadFromExternal = ProcessCommandLine matches regex @"https?://(?!.*\.microsoft\.com|.*\.windowsupdate\.com|.*\.windows\.com)[^\s]+"
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine,
InitiatingProcessFileName, InitiatingProcessCommandLine,
HasNotify, HasTransfer, HasReset, SuspiciousDest, SuspiciousExt, DownloadFromExternal,
DetectionBranch = "BitsAdmin"
| where HasNotify or HasTransfer or (SuspiciousDest and SuspiciousExt) or DownloadFromExternal;
// Branch 2: PowerShell BITS cmdlets
let PowerShellBits = DeviceProcessEvents
| where Timestamp > ago(24h)
| where FileName in~ ("powershell.exe", "pwsh.exe")
| where ProcessCommandLine has_any ("Start-BitsTransfer", "New-BitsTransfer", "Add-BitsFile", "Get-BitsTransfer", "Set-BitsTransfer")
| extend SuspiciousDest = ProcessCommandLine has_any (SuspiciousDestinations)
| extend SuspiciousExt = ProcessCommandLine has_any (SuspiciousExtensions)
| extend DownloadFromExternal = ProcessCommandLine matches regex @"https?://(?!.*\.microsoft\.com|.*\.windowsupdate\.com|.*\.windows\.com)[^\s]+"
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine,
InitiatingProcessFileName, InitiatingProcessCommandLine,
HasNotify = tobool(ProcessCommandLine has_any ("SetNotifyCmdLine", "Notify")),
HasTransfer = true, HasReset = false,
SuspiciousDest, SuspiciousExt, DownloadFromExternal,
DetectionBranch = "PowerShellBITS"
| where SuspiciousDest or DownloadFromExternal or SuspiciousExt;
// Union both branches
union BitsAdminExec, PowerShellBits
| sort by Timestamp desc Detects BITS job abuse via two branches: (1) bitsadmin.exe executions with /SetNotifyCmdLine (persistence), /transfer or /addfile with suspicious destinations or extensions, and downloads from non-Microsoft external URLs; (2) PowerShell BITS cmdlets (Start-BitsTransfer, New-BitsTransfer) writing to writable temp/user directories or downloading from external sources. Uses regex to identify external non-Microsoft download URLs and dynamic arrays to flag suspicious destination paths and executable extensions.
Data Sources
Required Tables
False Positives & Tuning
- Windows Update and Microsoft patching infrastructure using bitsadmin.exe or BITS service legitimately — typically originating from TrustedInstaller or SYSTEM account downloading from *.windowsupdate.com
- Software deployment tools (SCCM/ConfigMgr, Intune) using BITS for package distribution — parent process is usually CcmExec.exe or IntuneManagementExtension.exe
- Third-party software updaters (e.g., antivirus updates, browser updaters) that leverage BITS for bandwidth-friendly background downloads
- IT automation scripts using Start-BitsTransfer for legitimate large file transfers to user-accessible shares or deployment directories
- Developer workstations where CI/CD pipelines or build tools invoke bitsadmin.exe for artifact retrieval
Other platforms for T1197
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.
- Test 1BITSAdmin Download from External URL
Expected signal: Sysmon Event ID 1: Process Create with Image=bitsadmin.exe, CommandLine containing '/transfer' and 'http://127.0.0.1:8080/test.exe' and '%TEMP%\df00tech-test.exe'. Microsoft-Windows-Bits-Client EventID 3 (job created with name 'df00tech-test'). EventID 60 (job error, since no HTTP server is listening at 127.0.0.1:8080 — but job creation telemetry still fires). Security Event ID 4688 (if command line auditing enabled).
- Test 2BITS Persistence via SetNotifyCmdLine
Expected signal: Sysmon Event ID 1: Four separate bitsadmin.exe Process Create events — for /create, /addfile, /SetNotifyCmdLine (CommandLine contains 'cmd.exe /c calc.exe'), and /SetNotifyFlags. Microsoft-Windows-Bits-Client EventID 3 (job creation). If the job errors (no HTTP server), the notify command fires: Sysmon EventID 1 for cmd.exe spawned by svchost.exe (BITS service) with ParentCommandLine containing BITS service context.
- Test 3PowerShell Start-BitsTransfer to Suspicious Location
Expected signal: Sysmon Event ID 1: Process Create with Image=powershell.exe, CommandLine containing 'Start-BitsTransfer' and '$env:APPDATA' and 'payload.exe'. Microsoft-Windows-Bits-Client EventID 3 (job created programmatically). PowerShell ScriptBlock Log EventID 4104 with full Start-BitsTransfer cmdlet parameters. Sysmon EventID 3: Network connection attempt from svchost.exe (BITS service) to 127.0.0.1:8080.
- Test 4BITSAdmin Upload for Exfiltration Simulation
Expected signal: Sysmon Event ID 1: bitsadmin.exe Process Create with '/upload' in CommandLine. Microsoft-Windows-Bits-Client EventID 3 (job created with upload type). Sysmon EventID 3: Outbound network connection from svchost.exe to 127.0.0.1:8080. EventID 60 (job error, connection refused) with upload direction noted in event data.
References (10)
- https://attack.mitre.org/techniques/T1197/
- https://www.secureworks.com/blog/malware-lingers-with-bits
- https://researchcenter.paloaltonetworks.com/2017/11/unit42-uboatrat-navigates-east-asia/
- https://www.elastic.co/blog/hunting-for-persistence-using-elastic-security-part-1
- https://learn.microsoft.com/en-us/windows/win32/bits/background-intelligent-transfer-service-portal
- https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/bitsadmin
- https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1197/T1197.md
- https://github.com/SigmaHQ/sigma/tree/master/rules/windows/process_creation
- https://www.mandiant.com/resources/blog/fin12-ransomware-intrusion-actor-targeting-healthcare-sector
- https://unit42.paloaltonetworks.com/atoms/backconfig/
Unlock Pro Content
Get the full detection package for T1197 including response playbook, investigation guide, and atomic red team tests.