Scheduled tasks are a favourite persistence and privilege-escalation mechanism: they survive reboots, can run as SYSTEM, and can fire on a timer, at logon or on an event. Windows logs creation in two places, Security Event 4698 (which carries the full task XML) and the Task Scheduler Operational log. The gap most teams have is not detection logic but auditing: neither source is fully on by default.
Signals at a Glance
| Signal | Where | ATT&CK |
|---|---|---|
| Task created (4698), updated (4702) or deleted (4699) | Security log, needs Other Object Access auditing | T1053.005 |
| Task registered (106) or updated (140) in Task Scheduler Operational | Microsoft-Windows-TaskScheduler/Operational | T1053.005 |
| Task action runs a script host, LOLBin or file in a user-writable path | 4698 TaskContent XML | T1059 |
| schtasks.exe /create with /ru SYSTEM or a remote /s target | Sysmon 1, process creation | T1053.005 |
| Task key present under TaskCache\Tree with the SD value removed | Sysmon 12/13, registry audit | T1562 |
| Task created from a remote host over RPC or SMB | Network + 4698 correlation | T1021.002 |
Event 4698 and the Task XML
Enable Audit Other Object Access Events so that Event 4698 is written, and enable the Task Scheduler Operational log, which is disabled by default. The 4698 event carries the whole task definition in the TaskContent field, so you can inspect the action, the principal and the trigger without ever touching the host. This Splunk search extracts the command and flags the usual suspects:
index=wineventlog source="WinEventLog:Security" EventCode=4698
| rex field=TaskContent "(?s)<Command>(?<task_cmd>[^<]+)</Command>(\s*<Arguments>(?<task_args>[^<]*)</Arguments>)?"
| eval act=lower(task_cmd . " " . coalesce(task_args, ""))
| where match(act, "(powershell|cmd\.exe|mshta|wscript|cscript|rundll32|regsvr32|certutil|bitsadmin)")
OR match(act, "(\\\\appdata\\\\|\\\\temp\\\\|\\\\programdata\\\\|\\\\users\\\\public\\\\)")
| table _time host SubjectUserName TaskName task_cmd task_args
| sort - _time
`comment("tune/validate: field names such as TaskContent vary by TA version; baseline vendor updater tasks first")`
Most of the real signal is in who created the task and what it launches. A task created by a service account from a workstation, or one that runs a user-profile binary as SYSTEM, deserves immediate triage.
Hidden Tasks and Fleet Sweeps
Some actors make a task invisible to schtasks /query and the Task Scheduler UI by deleting the Security Descriptor (SD) value under the task’s TaskCache\Tree key. The task still runs, but standard enumeration misses it. Sweep for task entries that have an Id but no SD, and list task actions that point outside the usual install paths:
# PowerShell fleet-hunt: tasks missing an SD value, and tasks with unusual action paths
$tree = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree'
Get-ChildItem $tree -Recurse -ErrorAction SilentlyContinue |
Where-Object { $_.GetValueNames() -contains 'Id' -and $_.GetValueNames() -notcontains 'SD' } |
Select-Object Name
Get-ScheduledTask | ForEach-Object {
foreach ($a in $_.Actions) {
if ($a.Execute -and $a.Execute -notmatch '^(C:\\Windows\\|C:\\Program Files)') {
[pscustomobject]@{ Task = $_.TaskPath + $_.TaskName; User = $_.Principal.UserId
Execute = $a.Execute; Args = $a.Arguments }
}
}
}
# tune/validate: run against a clean reference host first and exclude known vendor tasks.
- Alert on registry deletions of the SD value under
TaskCache\Treeusing Sysmon Event ID 12 or 13; legitimate software essentially never does this. - Correlate 4698 with a preceding network logon (4624 type 3) from another host to catch remotely created tasks.
- Watch Task Scheduler Operational events 200 and 129 (action started, process created) for tasks that launch unsigned binaries.
- Include tasks that run once and delete themselves: a 4698 followed within minutes by a 4699 is a common execution pattern, not only persistence.
Use the SigmaHQ scheduled-task rules, Elastic’s scheduled-task creation detections, Splunk ESCU content for T1053.005, MITRE CAR analytics and Atomic Red Team tests to confirm each event fires in your environment. Autoruns and osquery’s scheduled_tasks table give a fleet inventory. Baseline your own environment, because backup, EDR and update agents create many tasks.
Build Detections That Fire
Mjolnir Security helps blue teams turn threat intelligence into high-fidelity detections across endpoint, network, identity and cloud telemetry.
- Detection Engineering We build and tune detections mapped to ATT&CK from your own telemetry.
- Threat Hunting as a Service Hypothesis-driven hunts for the behaviours on this page.
- 24/7 Incident Response Containment when a detection fires. Call +1 833 403 5875.
Stay ahead of emerging threats. Get notified when we publish new intelligence reports and advisories.
Subscribe to Alerts