Detection rules › Kusto

Detect Rare scheduled task created

Author
Robbe Van den Daele
Source
github.com/HybridBrothers/Hunting-Queries-Detection-Rules

Persistence via Scheduled Tasks is a well-known technique used by adversaries to make sure their malware programs keep running an the compromised device. With this detection rule, you can search for scheduled tasks being created by processes that did not performed this before. > [!WARNING] > This detection rule is the base for the detection. You will need to add environment specific finetuning in order to limit the BP detections on legitimate processes

MITRE ATT&CK coverage

References

Telemetry coverage

Rule body

let lolbins = toscalar(externaldata(FileName:string, Description:string, Author:string, Date:datetime, Command:string, CommandDescription:string, CommandUsecase:string, CommandCategory:string)
    ["https://lolbas-project.github.io/api/lolbas.csv"] with(format="csv", ignoreFirstRecord=true)
    | extend FileName = tolower(FileName)
    | summarize make_set(FileName)
);
// Setting up the rare ones.
let rareScheduledTaskRegistrations = toscalar(
    DeviceProcessEvents
    | where Timestamp > ago(14d)
    | where ProcessCommandLine has_all ("schtasks",  "/create")
    | summarize count() by ProcessCommandLine
    | where count_ < 5
    | summarize make_set(ProcessCommandLine)
);
DeviceProcessEvents
| where Timestamp > ago(1d)
| where ProcessCommandLine has_all ("schtasks",  "/create")
| extend ProcessCommandLine = replace_regex(ProcessCommandLine, @"C:\\Users\\[^\\]+", "C:\\Users\\<USERNAME>")
// Only take the ones in the last day we find rare within the organization.
| where ProcessCommandLine in (rareScheduledTaskRegistrations)
| invoke FileProfile(InitiatingProcessSHA256, 1000)
| where not(GlobalPrevalence > 1000 and tolower(InitiatingProcessFileName) !in (lolbins))

Stages and Predicates

Let binding: lolbins used in Stage 7

let lolbins = toscalar(externaldata(FileName:string, Description:string, Author:string, Date:datetime, Command:string, CommandDescription:string, CommandUsecase:string, CommandCategory:string)
    ["https://lolbas-project.github.io/api/lolbas.csv"] with(format="csv", ignoreFirstRecord=true)
    | extend FileName = tolower(FileName)
    | summarize make_set(FileName)
);

Let binding: rareScheduledTaskRegistrations used in Stage 5

let rareScheduledTaskRegistrations = toscalar(
    DeviceProcessEvents
    | where Timestamp > ago(14d)
    | where ProcessCommandLine has_all ("schtasks",  "/create")
    | summarize count() by ProcessCommandLine
    | where count_ < 5
    | summarize make_set(ProcessCommandLine)
);

Stage 1: source

DeviceProcessEvents

Stage 2: where

| where Timestamp > ago(1d)

Stage 3: where

| where ProcessCommandLine has_all ("schtasks",  "/create")

Stage 4: extend

| extend ProcessCommandLine = replace_regex(ProcessCommandLine, @"C:\\Users\\[^\\]+", "C:\\Users\\<USERNAME>")

Stage 5: where

| where ProcessCommandLine in (rareScheduledTaskRegistrations)

Stage 6: invoke

| invoke FileProfile(InitiatingProcessSHA256, 1000)

Stage 7: where

| where not(GlobalPrevalence > 1000 and tolower(InitiatingProcessFileName) !in (lolbins))

Exclusions

The rule actively suppresses these predicates.

Indicators

These rows show field, operator, and value matches.

Output fields

These fields are emitted when the rule matches.

FieldSource
ProcessCommandLineextend