Detection rules › Kusto
Kusto rules: 2s
Cisco Cloud Security - Hack Tool User-Agent Detected
#'Detects suspicious user agent strings used by known hack tools'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Execution | |
| Discovery | |
| Lateral Movement | |
| Collection | |
| Command & Control | |
| Exfiltration |
Rule Body
id: 8d537f3c-094f-430c-a588-8a87da36ee3a
name: Cisco Cloud Security - Hack Tool User-Agent Detected
description: |
'Detects suspicious user agent strings used by known hack tools'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: CiscoUmbrellaDataConnector
dataTypes:
- Cisco_Umbrella_proxy_CL
queryFrequency: 15m
queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
tactics:
- Execution
- Discovery
- LateralMovement
- Collection
- CommandAndControl
- Exfiltration
relevantTechniques:
- T1059
- T1046
- T1021
- T1557
- T1102
- T1020
query: |
let user_agents=dynamic([
'(hydra)',
' arachni/',
' BFAC ',
' brutus ',
' cgichk ',
'core-project/1.0',
' crimscanner/',
'datacha0s',
'dirbuster',
'domino hunter',
'dotdotpwn',
'FHScan Core',
'floodgate',
'get-minimal',
'gootkit auto-rooter scanner',
'grendel-scan',
' inspath ',
'internet ninja',
'jaascois',
' zmeu ',
'masscan',
' metis ',
'morfeus fucking scanner',
'n-stealth',
'nsauditor',
'pmafind',
'security scan',
'springenwerk',
'teh forest lobster',
'toata dragostea',
' vega/',
'voideye',
'webshag',
'webvulnscan',
' whcc/',
' Havij',
'absinthe',
'bsqlbf',
'mysqloit',
'pangolin',
'sql power injector',
'sqlmap',
'sqlninja',
'uil2pn',
'ruler',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729)'
]);
Cisco_Umbrella
| where EventType == "proxylogs"
| where HttpUserAgentOriginal has_any (user_agents)
| extend Message = "Hack Tool User Agent"
| project TimeGenerated, Message, SrcIpAddr, DstIpAddr, UrlOriginal, HttpUserAgentOriginal
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: UrlOriginal
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SrcIpAddr
version: 1.1.3
kind: Scheduled
Stages and Predicates
Let Binding: user_agents
let user_agents = dynamic([
'(hydra)',
' arachni/',
' BFAC ',
' brutus ',
' cgichk ',
'core-project/1.0',
' crimscanner/',
'datacha0s',
'dirbuster',
'domino hunter',
'dotdotpwn',
'FHScan Core',
'floodgate',
'get-minimal',
'gootkit auto-rooter scanner',
'grendel-scan',
' inspath ',
'internet ninja',
'jaascois',
' zmeu ',
'masscan',
' metis ',
'morfeus fucking scanner',
'n-stealth',
'nsauditor',
'pmafind',
'security scan',
'springenwerk',
'teh forest lobster',
'toata dragostea',
' vega/',
'voideye',
'webshag',
'webvulnscan',
' whcc/',
' Havij',
'absinthe',
'bsqlbf',
'mysqloit',
'pangolin',
'sql power injector',
'sqlmap',
'sqlninja',
'uil2pn',
'ruler',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729)'
]);
Stage 1: source
Cisco_Umbrella
Stage 2: where
| where EventType == "proxylogs"
Stage 3: where
| where HttpUserAgentOriginal has_any (user_agents)
Stage 4: extend
| extend Message = "Hack Tool User Agent"
Stage 5: project
| project TimeGenerated, Message, SrcIpAddr, DstIpAddr, UrlOriginal, HttpUserAgentOriginal
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventType | eq |
| field:"EventType" kind:eq value:"proxylogs" |
HttpUserAgentOriginal | match |
| field:"HttpUserAgentOriginal" kind:match |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DstIpAddr | project |
HttpUserAgentOriginal | project |
Message | project |
SrcIpAddr | project |
TimeGenerated | project |
UrlOriginal | project |
Cisco SDWAN - IPS Event Threshold
#'This analytic rule will monitor specific IPS event in the data.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: dc3627c3-f9de-4f17-bfd3-ba99b64a0a67
name: Cisco SDWAN - IPS Event Threshold
description: |
'This analytic rule will monitor specific IPS event in the data.'
severity: High
status: Available
requiredDataConnectors:
- connectorId: CiscoSDWAN
dataTypes:
- CiscoSyslogUTD
queryFrequency: 3h
queryPeriod: 3h
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1190
- T1189
query: |
CiscoSyslogUTD
| where Classification == "Enter classification"
| summarize count() by Classification
| where count_ > 10
incidentConfiguration:
createIncident: true
eventGroupingSettings:
aggregationKind: AlertPerResult
customDetails:
"classification": "Classification"
"classification_count": "count_"
entityMappings:
- entityType: Malware
fieldMappings:
- identifier: Name
columnName: Classification
version: 1.0.1
kind: Scheduled
Stages and Predicates
Stage 1: source
CiscoSyslogUTD
Stage 2: where
| where Classification == "Enter classification"
Stage 3: summarize
| summarize count() by Classification
Stage 4: where
| where count_ > 10
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Classification | eq |
| field:"Classification" kind:eq value:"Enter classification" |
count_ | gt |
| field:"count_" kind:gt value:"10" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Classification | summarize |
Corelight - Network Service Scanning Multiple IP Addresses
#'Identify scanning of services that may be available on the internal network.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: 599570d4-06f8-4939-8e29-95cd003f1abd
name: Corelight - Network Service Scanning Multiple IP Addresses
description: |
'Identify scanning of services that may be available on the internal network.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: Corelight
dataTypes:
- corelight_conn
- corelight_conn_red
- corelight_conn_long
- corelight_conn_agg
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1566
query: |
let threshold = 25;
union isfuzzy=true corelight_conn, corelight_conn_agg
| where local_resp == true
| where local_orig == true
| where conn_state in~ ('S0', 'REJ')
| where history !contains 'D'
| summarize count() by id_orig_h, id_resp_p, bin(TimeGenerated, 1m)
| where count_ > threshold
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: id_orig_h
version: 2.2.0
kind: Scheduled
Stages and Predicates
Parameters
let threshold = 25;
Union isfuzzy=true (2 Sources)
Each leg below queries one source; the rule matches if any leg does. Sources: corelight_conn, corelight_conn_agg
Leg 1: corelight_conn
Leg 2: corelight_conn_agg
Applied to the Combined Result
| where local_resp == true | where local_orig == true | where conn_state in~ ('S0', 'REJ') | where history !contains 'D' | summarize count() by id_orig_h, id_resp_p, bin(TimeGenerated, 1m) | where count_ > threshold
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
conn_state | in |
| field:"conn_state" kind:in |
count_ | gt |
| field:"count_" kind:gt value:"25" |
local_orig | eq |
| field:"local_orig" kind:eq value:"true" |
local_resp | eq |
| field:"local_resp" kind:eq value:"true" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
history | contains | D | excludes:history field:"history" value:"D" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
id_orig_h | summarize |
id_resp_p | summarize |
Credential Record Updated
#Detects when a credential record is updated in Veeam Backup & Replication.
Rule Body
id: 860e201a-deea-4129-8646-fcf8bdd976b0
name: Credential Record Updated
description: Detects when a credential record is updated in Veeam Backup & Replication.
severity: High
status: Available
requiredDataConnectors:
- connectorId: Syslog
dataTypes:
- Syslog
- connectorId: SyslogAma
dataTypes:
- Syslog
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
eventGroupingSettings:
aggregationKind: AlertPerResult
tactics: []
relevantTechniques: []
query: "Veeam_GetSecurityEvents\n| where instanceId == 25400\n| project\n Date\
\ = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),\n DataSource = original_host,\n\
\ EventId = instanceId,\n [\"User Name\"] = user,\n MessageDetails = Description,\n\
\ Severity = SeverityDescription"
version: 1.0.1
kind: Scheduled
customDetails:
Date: Date
VbrHostName: DataSource
EventId: EventId
MessageDetails: MessageDetails
Severity: Severity
Stages and Predicates
Stage 1: source
Veeam_GetSecurityEvents
Stage 2: where
| where instanceId == 25400
Stage 3: project
| project
Date = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),
DataSource = original_host,
EventId = instanceId,
["User Name"] = user,
MessageDetails = Description,
Severity = SeverityDescription
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
instanceId | eq |
| field:"instanceId" kind:eq value:"25400" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DataSource | project |
Date | project |
EventId | project |
MessageDetails | project |
Severity | project |
User Name | project |
Cyble Advisory Alerts Advisory
#This is a third-party alert feed, not a detection over modeled telemetry. The vendor product raised the finding; this rule forwards it into the SIEM. It is searchable for reference but is excluded from the detection-rule browse and the ATT&CK coverage matrix.
'Generates Microsoft Sentinel incidents from Cyble Advisory service alerts. Advisory alerts provide intelligence and context related to monitored keywords.Severity is normalized using MappedSeverity for downstream automation.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Reconnaissance | |
| Resource Development |
Rule Body
id: 1932DCFD-A32E-49F9-A212-5BCD084FBD78
name: Cyble Advisory Alerts Advisory
description: |
'Generates Microsoft Sentinel incidents from Cyble Advisory service alerts. Advisory alerts provide intelligence and context related to monitored keywords.Severity is normalized using MappedSeverity for downstream automation.'
severity: Low
status: Available
requiredDataConnectors:
- connectorId: CybleVisionAlerts
dataTypes:
- CybleVisionAlerts_CL
enabled: true
queryfrequency: 30m
queryPeriod: 30m
triggerOperator: GreaterThan
triggerThreshold: 0
eventGroupingSettings:
aggregationKind: AlertPerResult
suppressionEnabled: false
tactics:
- Reconnaissance
- ResourceDevelopment
relevantTechniques:
- T1595
- T1596
- T1587
entityMappings: null
query: |
Alerts_advisory
| where Service == "advisory"
| extend MappedSeverity = Severity
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: false
reopenClosedIncident: false
lookbackDuration: PT5H
matchingMethod: AllEntities
alertDetailsOverride:
alertDisplayNameFormat: Cyble Vision Advisory {{ADV_Value}} detected
alertDescriptionFormat: |
Vision Alert for AdvisoryId {{ADV_Value}}
customDetails:
MappedSeverity: Severity
Status: Status
AlertID: AlertID
Service: Service
Keyword: KeywordName
BucketName: BucketName
AdvisoryId: ADV_Value
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
Alerts_advisory
Stage 2: where
| where Service == "advisory"
Stage 3: extend
| extend MappedSeverity = Severity
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Service | eq |
| field:"Service" kind:eq value:"advisory" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
MappedSeverity | extend |
Detect web requests to potentially harmful files (ASIM Web Session)
#'This rule detects web requests made to URLs containing file types such as .ps1, .bat, .vbs,.scr etc. which have the potential to be harmful if downloaded. This rule uses the Advanced Security Information Model (ASIM) and supports any web session source that complies with ASIM.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Execution | |
| Persistence |
Rule Body
id: c6608467-3678-45fe-b038-b590ce6d00fb
name: Detect web requests to potentially harmful files (ASIM Web Session)
description: |
'This rule detects web requests made to URLs containing file types such as .ps1, .bat, .vbs,.scr etc. which have the potential to be harmful if downloaded. This rule uses the [Advanced Security Information Model (ASIM)](https://aka.ms/AboutASIM) and supports any web session source that complies with ASIM.'
severity: Medium
status: Available
tags:
- Schema: WebSession
SchemaVersion: 0.2.6
requiredDataConnectors: []
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
- Persistence
- Execution
relevantTechniques:
- T1133
- T1203
- T1566
query: |
let lookback = 5m;
let RiskyFileExtensions = materialize(externaldata(Extensions: string)
[@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/RiskyFileExtensionsInUrl.csv"]
with(format="csv", ignoreFirstRecord=True));
let CustomRiskyFileExtensions = (_ASIM_GetWatchlistRaw("Web_RiskyFileExtensions") // Create new Watchlist and add your custom indicators(Optional)
| extend
Extensions = tostring(WatchlistItem["Extensions"])
| project Extensions
| where isnotempty(Extensions));
let CombinedRiskyFileExtensions = union RiskyFileExtensions, CustomRiskyFileExtensions;
let knownRiskyFileExtensions=toscalar(CombinedRiskyFileExtensions
| where isnotempty(Extensions)
| summarize make_set(Extensions, 1000));
let Whitelisted_Domains = materialize(externaldata(WhiteListedDomains: string)
[@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/WhiteListedDomainsForWebSessionUseCases.csv"]
with(format="csv", ignoreFirstRecord=True));
let CustomWhiteListedDomains = (_ASIM_GetWatchlistRaw("Web_WhiteListedDomains") // Create new Watchlist and add your white listed domains(Optional)
| extend
WhiteListedDomains = tostring(WatchlistItem["WhiteListedDomains"])
| project WhiteListedDomains
| where isnotempty(WhiteListedDomains));
let CombinedWhitelisted_Domains = union Whitelisted_Domains, CustomWhiteListedDomains;
let knownWhitelisted_Domains=toscalar(CombinedWhitelisted_Domains
| where isnotempty(WhiteListedDomains)
| summarize make_set(WhiteListedDomains, 1000));
_Im_WebSession (starttime=ago(lookback), url_has_any=knownRiskyFileExtensions, eventresult='Success')
| project
Url,
SrcIpAddr,
TimeGenerated,
SrcUsername,
SrcHostname,
DstIpAddr,
DstPortNumber
| extend requestedFileName=tostring(split(tostring(parse_url(Url)["Path"]), '/')[-1])
| extend requestedFileExt=extract(@'(\.\w+)$', 1, requestedFileName, typeof(string))
| where requestedFileExt in~ (knownRiskyFileExtensions)
| summarize
EventCount=count(),
EventStartTime=min(TimeGenerated),
EventEndTime=max(TimeGenerated)
by
SrcUsername,
SrcIpAddr,
SrcHostname,
DstIpAddr,
DstPortNumber,
Url,
requestedFileName
| extend FQDN = split(parse_url(Url)["Host"], '.')
| extend Domain = iif(array_length(FQDN) > 1, strcat(FQDN[-2], '.', FQDN[-1]), FQDN)
| where Domain !in~ (knownWhitelisted_Domains)
| project-away FQDN
| extend Name = iif(SrcUsername contains "@", tostring(split(SrcUsername,'@',0)[0]),SrcUsername), UPNSuffix = iif(SrcUsername contains "@",tostring(split(SrcUsername,'@',1)[0]),"")
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SrcIpAddr
- entityType: URL
fieldMappings:
- identifier: Url
columnName: Url
- entityType: File
fieldMappings:
- identifier: Name
columnName: requestedFileName
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: SrcHostname
- entityType: Account
fieldMappings:
- identifier: Name
columnName: Name
- identifier: UPNSuffix
columnName: UPNSuffix
eventGroupingSettings:
aggregationKind: AlertPerResult
customDetails:
EventCount: EventCount
EventStartTime: EventStartTime
EventEndTime: EventEndTime
DstIpAddr: DstIpAddr
alertDetailsOverride:
alertDisplayNameFormat: "User '{{SrcUsername}}' with IP address '{{SrcIpAddr}}' accessed a potentially harmful URL"
alertDescriptionFormat: "User accessed URL - '{{Url}}' that contains a file - '{{requestedFileName}}' with risky extension. Downloading this file could pose a potential risk"
version: 1.0.0
kind: Scheduled
Stages and Predicates
Parameters
let lookback = 5m;
let CombinedRiskyFileExtensions = union RiskyFileExtensions, CustomRiskyFileExtensions;
let CombinedWhitelisted_Domains = union Whitelisted_Domains, CustomWhiteListedDomains;
Let Binding: RiskyFileExtensions
let RiskyFileExtensions = materialize(externaldata(Extensions: string)
[@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/RiskyFileExtensionsInUrl.csv"]
with(format="csv", ignoreFirstRecord=True));
Let Binding: CustomRiskyFileExtensions
let CustomRiskyFileExtensions = (_ASIM_GetWatchlistRaw("Web_RiskyFileExtensions")
| extend
Extensions = tostring(WatchlistItem["Extensions"])
| project Extensions
| where isnotempty(Extensions));
Let Binding: knownRiskyFileExtensions
let knownRiskyFileExtensions = toscalar(CombinedRiskyFileExtensions
| where isnotempty(Extensions)
| summarize make_set(Extensions, 1000));
Let Binding: Whitelisted_Domains
let Whitelisted_Domains = materialize(externaldata(WhiteListedDomains: string)
[@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/WhiteListedDomainsForWebSessionUseCases.csv"]
with(format="csv", ignoreFirstRecord=True));
Let Binding: CustomWhiteListedDomains
let CustomWhiteListedDomains = (_ASIM_GetWatchlistRaw("Web_WhiteListedDomains")
| extend
WhiteListedDomains = tostring(WatchlistItem["WhiteListedDomains"])
| project WhiteListedDomains
| where isnotempty(WhiteListedDomains));
Let Binding: knownWhitelisted_Domains
let knownWhitelisted_Domains = toscalar(CombinedWhitelisted_Domains
| where isnotempty(WhiteListedDomains)
| summarize make_set(WhiteListedDomains, 1000));
Stage 1: source
_Im_WebSession (starttime=ago(lookback), url_has_any=knownRiskyFileExtensions, eventresult='Success')
Stage 2: project
| project
Url,
SrcIpAddr,
TimeGenerated,
SrcUsername,
SrcHostname,
DstIpAddr,
DstPortNumber
Stage 3: extend
| extend requestedFileName=tostring(split(tostring(parse_url(Url)["Path"]), '/')[-1])
Stage 4: extend
| extend requestedFileExt=extract(@'(\.\w+)$', 1, requestedFileName, typeof(string))
Stage 5: where
| where requestedFileExt in~ (knownRiskyFileExtensions)
Stage 6: summarize
| summarize
EventCount=count(),
EventStartTime=min(TimeGenerated),
EventEndTime=max(TimeGenerated)
by
SrcUsername,
SrcIpAddr,
SrcHostname,
DstIpAddr,
DstPortNumber,
Url,
requestedFileName
Stage 7: extend
| extend FQDN = split(parse_url(Url)["Host"], '.')
Stage 8: extend
| extend Domain = iif(array_length(FQDN) > 1, strcat(FQDN[-2], '.', FQDN[-1]), FQDN)
Stage 9: where
| where Domain !in~ (knownWhitelisted_Domains)
Stage 10: project-away
| project-away FQDN
Stage 11: extend
| extend Name = iif(SrcUsername contains "@", tostring(split(SrcUsername,'@',0)[0]),SrcUsername), UPNSuffix = iif(SrcUsername contains "@",tostring(split(SrcUsername,'@',1)[0]),"")
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
requestedFileExt | in |
| field:"requestedFileExt" kind:in value:"knownRiskyFileExtensions" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
Domain | eq | knownWhitelisted_Domains | excludes:Domain field:"Domain" value:"knownWhitelisted_Domains" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DstIpAddr | summarize |
DstPortNumber | summarize |
EventCount | summarize |
EventEndTime | summarize |
EventStartTime | summarize |
SrcHostname | summarize |
SrcIpAddr | summarize |
SrcUsername | summarize |
Url | summarize |
requestedFileName | summarize |
Domain | extend |
Name | extend |
UPNSuffix | extend |
Flow Logs Alerts for Prancer
#'High severity flow Log alerts found by Prancer.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Reconnaissance |
Rule Body
id: 59336232-1bbc-4f66-90dd-5ac3708e4405
name: Flow Logs Alerts for Prancer
description: |
'High severity flow Log alerts found by Prancer.'
severity: High
requiredDataConnectors:
- connectorId: PrancerLogData
dataTypes:
- prancer_CL
queryFrequency: 5h
queryPeriod: 5h
triggerOperator: gt
triggerThreshold: 0
eventGroupingSettings:
aggregationKind: SingleAlert
status: Available
tactics:
- Reconnaissance
relevantTechniques:
- T1595
query: |
union prancer_CL
| where deviceProduct_s == 'azure'
| where parse_json(data_data_snapshots_s)[0].type == 'Microsoft.Network/networkWatchers/flowLogs'
| where data_data_severity_s == 'High' and data_data_result_s == 'failed'
| extend snapshot = parse_json(data_data_snapshots_s)
| mv-expand snapshot
| extend
id = tostring(snapshot.id),
structure = tostring(snapshot.structure),
reference = tostring(snapshot.reference),
source = tostring(snapshot.source),
collection = tostring(snapshot.collection),
type = tostring(snapshot.type),
region = tostring(snapshot.region),
resourceTypes = tostring(snapshot.resourceTypes),
path = tostring(snapshot.path)
customDetails:
entityMappings:
- entityType: AzureResource
fieldMappings:
- identifier: ResourceId
columnName: path
alertDetailsOverride:
alertDisplayNameFormat: "{{data_data_message_s}}"
alertDescriptionFormat: "{{data_data_description_s}}"
alertSeverityColumnName: "{{data_data_severity_s}}"
alertDynamicProperties:
- alertProperty: RemediationSteps
value: data_data_remediation_description_s
version: 1.0.3
kind: Scheduled
Stages and Predicates
Stage 1: union
union of 1 branches
Stage 2: source
prancer_CL
Stage 3: where
where deviceProduct_s == "azure"
Stage 4: where
where parse_json(data_data_snapshots_s)[0].type == "Microsoft.Network/networkWatchers/flowLogs"
Stage 5: where
where data_data_result_s == "failed" and data_data_severity_s == "High"
Stage 6: extend
extend snapshot
Stage 7: mv-expand
mv-expand snapshot
Stage 8: extend
extend collection, id, path, reference, region, resourceTypes, source, structure, type
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data_data_result_s | eq |
| field:"data_data_result_s" kind:eq value:"failed" |
data_data_severity_s | eq |
| field:"data_data_severity_s" kind:eq value:"High" |
data_data_snapshots_s[0].type | eq |
| field:"data_data_snapshots_s[0].type" kind:eq value:"Microsoft.Network/networkWatchers/flowLogs" |
deviceProduct_s | eq |
| field:"deviceProduct_s" kind:eq value:"azure" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
snapshot | extend |
collection | extend |
id | extend |
path | extend |
reference | extend |
region | extend |
resourceTypes | extend |
source | extend |
structure | extend |
type | extend |
Group created then added to built in domain local or global group
#Identifies when a recently created Group was added to a privileged built in domain local group or global group such as the Enterprise Admins, Cert Publishers or DnsAdmins. Be sure to verify this is an expected addition. References: For AD SID mappings - https://docs.microsoft.com/windows/security/identity-protection/access-control/active-directory-security-groups.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Persistence | |
| Privilege Escalation |
Telemetry Coverage
Rule Body
id: a7564d76-ec6b-4519-a66b-fcc80c42332b
name: Group created then added to built in domain local or global group
description: |
'Identifies when a recently created Group was added to a privileged built in domain local group or global group such as the Enterprise Admins, Cert Publishers or DnsAdmins. Be sure to verify this is an expected addition.
References: For AD SID mappings - https://docs.microsoft.com/windows/security/identity-protection/access-control/active-directory-security-groups.'
severity: Medium
requiredDataConnectors:
- connectorId: SecurityEvents
dataTypes:
- SecurityEvent
- connectorId: WindowsSecurityEvents
dataTypes:
- SecurityEvent
- connectorId: WindowsForwardedEvents
dataTypes:
- WindowsEvent
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
- PrivilegeEscalation
relevantTechniques:
- T1098
- T1078
query: |
let WellKnownLocalSID = "S-1-5-32-5[0-9][0-9]$";
let WellKnownGroupSID = "S-1-5-21-[0-9]*-[0-9]*-[0-9]*-5[0-9][0-9]$|S-1-5-21-[0-9]*-[0-9]*-[0-9]*-1102$|S-1-5-21-[0-9]*-[0-9]*-[0-9]*-1103$|S-1-5-21-[0-9]*-[0-9]*-[0-9]*-498$|S-1-5-21-[0-9]*-[0-9]*-[0-9]*-1000$";
let GroupAddition = (union isfuzzy=true
(SecurityEvent
// 4728 - A member was added to a security-enabled global group
// 4732 - A member was added to a security-enabled local group
// 4756 - A member was added to a security-enabled universal group
| where EventID in ("4728", "4732", "4756")
| where AccountType =~ "User"
// Exclude Remote Desktop Users group: S-1-5-32-555
| where TargetSid !in ("S-1-5-32-555")
| where TargetSid matches regex WellKnownLocalSID or TargetSid matches regex WellKnownGroupSID
| project GroupAddTime = TimeGenerated, GroupAddEventID = EventID, GroupAddActivity = Activity, GroupAddComputer = Computer,
GroupAddTargetAccount = TargetAccount, GroupAddTargetUserName = TargetUserName, GroupAddTargetDomainName = TargetDomainName, GroupAddTargetSid = TargetSid,
GroupAddSubjectAccount = SubjectAccount, GroupAddSubjectUserName = SubjectUserName, GroupAddSubjectDomainName = SubjectDomainName, GroupAddSubjectUserSid = SubjectUserSid,
GroupSid = MemberSid
),
(
WindowsEvent
// 4728 - A member was added to a security-enabled global group
// 4732 - A member was added to a security-enabled local group
// 4756 - A member was added to a security-enabled universal group
| where EventID in ("4728", "4732", "4756") and not(EventData has "S-1-5-32-555")
| extend SubjectUserSid = tostring(EventData.SubjectUserSid)
| extend Account = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName))
| extend AccountType=case(Account endswith "$" or SubjectUserSid in ("S-1-5-18", "S-1-5-19", "S-1-5-20"), "Machine", isempty(SubjectUserSid), "", "User")
| extend MemberName = tostring(EventData.MemberName)
| where AccountType =~ "User"
// Exclude Remote Desktop Users group: S-1-5-32-555
| extend TargetSid = tostring(EventData.TargetSid)
| where TargetSid !in ("S-1-5-32-555")
| where TargetSid matches regex WellKnownLocalSID or TargetSid matches regex WellKnownGroupSID
| extend TargetAccount = strcat(EventData.TargetDomainName,"\\", EventData.TargetUserName)
| extend MemberSid = tostring(EventData.MemberSid)
| extend Activity= "GroupAddActivity"
| project GroupAddTime = TimeGenerated, GroupAddEventID = EventID, GroupAddActivity = Activity, GroupAddComputer = Computer,
GroupAddTargetAccount = TargetAccount, GroupAddTargetUserName = tostring(EventData.TargetUserName), GroupAddTargetDomainName = tostring(EventData.TargetDomainName), GroupAddTargetSid = TargetSid,
GroupAddSubjectAccount = Account, GroupAddSubjectUserName = tostring(EventData.SubjectUserName), GroupAddSubjectDomainName = tostring(EventData.SubjectDomainName), GroupAddSubjectUserSid = SubjectUserSid,
GroupSid = MemberSid
));
let GroupCreated = (union isfuzzy=true
(SecurityEvent
// 4727 - A security-enabled global group was created
// 4731 - A security-enabled local group was created
// 4754 - A security-enabled universal group was created
| where EventID in ("4727", "4731", "4754")
| where AccountType =~ "User"
| project GroupCreateTime = TimeGenerated, GroupCreateEventID = EventID, GroupCreateActivity = Activity, GroupCreateComputer = Computer,
GroupCreateTargetAccount = TargetAccount, GroupCreateTargetUserName = TargetUserName, GroupCreateTargetDomainName = TargetDomainName,
GroupCreateSubjectAccount = SubjectAccount, GroupCreateSubjectUserName = SubjectUserName, GroupCreateSubjectDomainName = SubjectDomainName, GroupCreateSubjectUserSid = SubjectUserSid,
GroupSid = TargetSid
),
(WindowsEvent
// 4727 - A security-enabled global group was created
// 4731 - A security-enabled local group was created
// 4754 - A security-enabled universal group was created
| where EventID in ("4727", "4731", "4754")
| extend SubjectUserSid = tostring(EventData.SubjectUserSid)
| extend Account = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName))
| extend AccountType=case(Account endswith "$", "Machine", iff(SubjectUserSid in ("S-1-5-18", "S-1-5-19", "S-1-5-20"), "Machine", iff(isempty(SubjectUserSid), "", "User")))
| where AccountType =~ "User"
| extend TargetAccount = strcat(EventData.TargetDomainName,"\\", EventData.TargetUserName)
| extend SubjectAccount = strcat(EventData.SubjectDomainName,"\\", EventData.SubjectUserName)
| extend TargetSid = tostring(EventData.TargetSid)
| extend Activity= "GroupAddActivity"
| project GroupCreateTime = TimeGenerated, GroupCreateEventID = EventID, GroupCreateActivity = Activity, GroupCreateComputer = Computer,
GroupCreateTargetAccount = TargetAccount, GroupCreateTargetUserName = tostring(EventData.TargetUserName), GroupCreateTargetDomainName = tostring(EventData.TargetDomainName),
GroupCreateSubjectAccount = SubjectAccount, GroupCreateSubjectUserName = tostring(EventData.SubjectUserName), GroupCreateSubjectDomainName = tostring(EventData.SubjectDomainName),GroupCreateSubjectUserSid = SubjectUserSid,
GroupSid = TargetSid
));
GroupCreated
| join (
GroupAddition
) on GroupSid
| extend GroupCreateHostName = tostring(split(GroupCreateComputer , ".")[0]), DomainIndex = toint(indexof(GroupCreateComputer , '.'))
| extend GroupCreateHostNameDomain = iff(DomainIndex != -1, substring(GroupCreateComputer , DomainIndex + 1), GroupCreateComputer)
| extend GroupAddHostName = tostring(split(GroupAddComputer , ".")[0]), DomainIndex = toint(indexof(GroupAddComputer , '.'))
| extend GroupAddHostNameDomain = iff(DomainIndex != -1, substring(GroupAddComputer , DomainIndex + 1), GroupAddComputer)
| project-away DomainIndex
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: GroupCreateSubjectAccount
- identifier: Name
columnName: GroupCreateSubjectUserName
- identifier: NTDomain
columnName: GroupCreateSubjectDomainName
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: GroupCreateTargetAccount
- identifier: Name
columnName: GroupAddSubjectUserName
- identifier: NTDomain
columnName: GroupAddSubjectDomainName
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: GroupCreateComputer
- identifier: HostName
columnName: GroupCreateHostName
- identifier: DnsDomain
columnName: GroupCreateHostNameDomain
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: GroupAddComputer
- identifier: HostName
columnName: GroupAddHostName
- identifier: DnsDomain
columnName: GroupAddHostNameDomain
version: 1.1.7
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Microsoft Security Research
support:
tier: Community
categories:
domains: [ "Security - Others" ]
Stages and Predicates
Parameters
let WellKnownLocalSID = "S-1-5-32-5[0-9][0-9]$";
Let Binding: WellKnownGroupSID
let WellKnownGroupSID = "S-1-5-21-[0-9]*-[0-9]*-[0-9]*-5[0-9][0-9]$|S-1-5-21-[0-9]*-[0-9]*-[0-9]*-1102$|S-1-5-21-[0-9]*-[0-9]*-[0-9]*-1103$|S-1-5-21-[0-9]*-[0-9]*-[0-9]*-498$|S-1-5-21-[0-9]*-[0-9]*-[0-9]*-1000$";
Let Binding: GroupAddition
let GroupAddition = (union isfuzzy=true
(SecurityEvent
| where EventID in ("4728", "4732", "4756")
| where AccountType =~ "User"
| where TargetSid !in ("S-1-5-32-555")
| where TargetSid matches regex WellKnownLocalSID or TargetSid matches regex WellKnownGroupSID
| project GroupAddTime = TimeGenerated, GroupAddEventID = EventID, GroupAddActivity = Activity, GroupAddComputer = Computer,
GroupAddTargetAccount = TargetAccount, GroupAddTargetUserName = TargetUserName, GroupAddTargetDomainName = TargetDomainName, GroupAddTargetSid = TargetSid,
GroupAddSubjectAccount = SubjectAccount, GroupAddSubjectUserName = SubjectUserName, GroupAddSubjectDomainName = SubjectDomainName, GroupAddSubjectUserSid = SubjectUserSid,
GroupSid = MemberSid
),
(
WindowsEvent
| where EventID in ("4728", "4732", "4756") and not(EventData has "S-1-5-32-555")
| extend SubjectUserSid = tostring(EventData.SubjectUserSid)
| extend Account = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName))
| extend AccountType=case(Account endswith "$" or SubjectUserSid in ("S-1-5-18", "S-1-5-19", "S-1-5-20"), "Machine", isempty(SubjectUserSid), "", "User")
| extend MemberName = tostring(EventData.MemberName)
| where AccountType =~ "User"
| extend TargetSid = tostring(EventData.TargetSid)
| where TargetSid !in ("S-1-5-32-555")
| where TargetSid matches regex WellKnownLocalSID or TargetSid matches regex WellKnownGroupSID
| extend TargetAccount = strcat(EventData.TargetDomainName,"\\", EventData.TargetUserName)
| extend MemberSid = tostring(EventData.MemberSid)
| extend Activity= "GroupAddActivity"
| project GroupAddTime = TimeGenerated, GroupAddEventID = EventID, GroupAddActivity = Activity, GroupAddComputer = Computer,
GroupAddTargetAccount = TargetAccount, GroupAddTargetUserName = tostring(EventData.TargetUserName), GroupAddTargetDomainName = tostring(EventData.TargetDomainName), GroupAddTargetSid = TargetSid,
GroupAddSubjectAccount = Account, GroupAddSubjectUserName = tostring(EventData.SubjectUserName), GroupAddSubjectDomainName = tostring(EventData.SubjectDomainName), GroupAddSubjectUserSid = SubjectUserSid,
GroupSid = MemberSid
));
Union isfuzzy=true (2 Sources)
Each leg below queries one source; the rule matches if any leg does. Sources: SecurityEvent, WindowsEvent
Leg 1: SecurityEvent
SecurityEvent
| where EventID in ("4727", "4731", "4754")
| where AccountType =~ "User"
| project GroupCreateTime = TimeGenerated, GroupCreateEventID = EventID, GroupCreateActivity = Activity, GroupCreateComputer = Computer,
GroupCreateTargetAccount = TargetAccount, GroupCreateTargetUserName = TargetUserName, GroupCreateTargetDomainName = TargetDomainName,
GroupCreateSubjectAccount = SubjectAccount, GroupCreateSubjectUserName = SubjectUserName, GroupCreateSubjectDomainName = SubjectDomainName, GroupCreateSubjectUserSid = SubjectUserSid,
GroupSid = TargetSid
Leg 2: WindowsEvent
WindowsEvent
| where EventID in ("4727", "4731", "4754")
| extend SubjectUserSid = tostring(EventData.SubjectUserSid)
| extend Account = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName))
| extend AccountType=case(Account endswith "$", "Machine", iff(SubjectUserSid in ("S-1-5-18", "S-1-5-19", "S-1-5-20"), "Machine", iff(isempty(SubjectUserSid), "", "User")))
| where AccountType =~ "User"
| extend TargetAccount = strcat(EventData.TargetDomainName,"\\", EventData.TargetUserName)
| extend SubjectAccount = strcat(EventData.SubjectDomainName,"\\", EventData.SubjectUserName)
| extend TargetSid = tostring(EventData.TargetSid)
| extend Activity= "GroupAddActivity"
| project GroupCreateTime = TimeGenerated, GroupCreateEventID = EventID, GroupCreateActivity = Activity, GroupCreateComputer = Computer,
GroupCreateTargetAccount = TargetAccount, GroupCreateTargetUserName = tostring(EventData.TargetUserName), GroupCreateTargetDomainName = tostring(EventData.TargetDomainName),
GroupCreateSubjectAccount = SubjectAccount, GroupCreateSubjectUserName = tostring(EventData.SubjectUserName), GroupCreateSubjectDomainName = tostring(EventData.SubjectDomainName),GroupCreateSubjectUserSid = SubjectUserSid,
GroupSid = TargetSid
Applied to the Combined Result
| join (
GroupAddition
) on GroupSid | extend GroupCreateHostName = tostring(split(GroupCreateComputer , ".")[0]), DomainIndex = toint(indexof(GroupCreateComputer , '.')) | extend GroupCreateHostNameDomain = iff(DomainIndex != -1, substring(GroupCreateComputer , DomainIndex + 1), GroupCreateComputer) | extend GroupAddHostName = tostring(split(GroupAddComputer , ".")[0]), DomainIndex = toint(indexof(GroupAddComputer , '.')) | extend GroupAddHostNameDomain = iff(DomainIndex != -1, substring(GroupAddComputer , DomainIndex + 1), GroupAddComputer) | project-away DomainIndex
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
AccountType | eq |
| field:"AccountType" kind:eq value:"User" |
EventID | in |
| field:"EventID" kind:in |
TargetSid | regex_match |
| field:"TargetSid" kind:regex_match |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
EventData | match | S-1-5-32-555 | excludes:EventData field:"EventData" value:"S-1-5-32-555" |
TargetSid | eq | S-1-5-32-555 | excludes:TargetSid field:"TargetSid" value:"S-1-5-32-555" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
GroupCreateActivity | project |
GroupCreateComputer | project |
GroupCreateEventID | project |
GroupCreateSubjectAccount | project |
GroupCreateSubjectDomainName | project |
GroupCreateSubjectUserName | project |
GroupCreateSubjectUserSid | project |
GroupCreateTargetAccount | project |
GroupCreateTargetDomainName | project |
GroupCreateTargetUserName | project |
GroupCreateTime | project |
GroupSid | project |
GroupCreateHostName | extend |
GroupCreateHostNameDomain | extend |
GroupAddHostName | extend |
GroupAddHostNameDomain | extend |
Midnight Blizzard - suspicious rundll32.exe execution of vbscript
#This query idenifies when rundll32.exe executes a specific set of inline VBScript commands References: https://www.microsoft.com/security/blog/2021/03/04/goldmax-goldfinder-sibot-analyzing-nobelium-malware/
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Persistence |
Telemetry Coverage
| Provider | Record / event type |
|---|---|
| Security-Auditing | Event ID 4688: A new process has been created. |
Rule Body
id: d82e1987-4356-4a7b-bc5e-064f29b143c0
name: Midnight Blizzard - suspicious rundll32.exe execution of vbscript
description: |
'This query idenifies when rundll32.exe executes a specific set of inline VBScript commands
References: https://www.microsoft.com/security/blog/2021/03/04/goldmax-goldfinder-sibot-analyzing-nobelium-malware/'
severity: Medium
requiredDataConnectors:
- connectorId: SecurityEvents
dataTypes:
- SecurityEvent
- connectorId: WindowsSecurityEvents
dataTypes:
- SecurityEvent
- connectorId: WindowsSecurityEvents
dataTypes:
- SecurityEvents
- connectorId: WindowsForwardedEvents
dataTypes:
- WindowsEvent
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
relevantTechniques:
- T1547
tags:
- Midnight Blizzard
query: |
(union isfuzzy=true
(SecurityEvent
| where EventID == 4688
| where Process =~ 'rundll32.exe'
| where CommandLine has_all ('Execute','RegRead','window.close')
| project TimeGenerated, Computer, SubjectAccount = Account, SubjectUserName, SubjectDomainName, SubjectUserSid, Process, ProcessId, NewProcessName, CommandLine, ParentProcessName, _ResourceId
),
(WindowsEvent
| where EventID == 4688 and EventData has 'rundll32.exe' and EventData has_any ('Execute','RegRead','window.close')
| extend NewProcessName = tostring(EventData.NewProcessName)
| extend Process=tostring(split(NewProcessName, '\\')[-1])
| where Process =~ 'rundll32.exe'
| extend CommandLine = tostring(EventData.CommandLine)
| where CommandLine has_all ('Execute','RegRead','window.close')
| extend SubjectAccount = strcat(EventData.SubjectDomainName,"\\", EventData.SubjectUserName)
| extend ParentProcessName = tostring(EventData.ParentProcessName)
| project TimeGenerated, Computer, SubjectAccount, SubjectUserName = tostring(EventData.SubjectUserName), SubjectDomainName = tostring(EventData.SubjectDomainName), SubjectUserSid = tostring(EventData.SubjectUserSid), Process, NewProcessName, CommandLine, ParentProcessName, _ResourceId
)
)
| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
| project-away DomainIndex
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: SubjectAccount
- identifier: Name
columnName: SubjectUserName
- identifier: NTDomain
columnName: SubjectDomainName
- entityType: Account
fieldMappings:
- identifier: Sid
columnName: SubjectUserSid
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: Computer
- identifier: HostName
columnName: HostName
- identifier: DnsDomain
columnName: HostNameDomain
version: 1.1.6
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Microsoft Security Research
support:
tier: Community
categories:
domains: [ "Security - Threat Intelligence" ]
Stages and Predicates
Union isfuzzy=true (2 Sources)
Each leg below queries one source; the rule matches if any leg does. Sources: SecurityEvent, WindowsEvent
Leg 1: SecurityEvent
SecurityEvent
| where EventID == 4688
| where Process =~ 'rundll32.exe'
| where CommandLine has_all ('Execute','RegRead','window.close')
| project TimeGenerated, Computer, SubjectAccount = Account, SubjectUserName, SubjectDomainName, SubjectUserSid, Process, ProcessId, NewProcessName, CommandLine, ParentProcessName, _ResourceId
Leg 2: WindowsEvent
WindowsEvent
| where EventID == 4688 and EventData has 'rundll32.exe' and EventData has_any ('Execute','RegRead','window.close')
| extend NewProcessName = tostring(EventData.NewProcessName)
| extend Process=tostring(split(NewProcessName, '\\')[-1])
| where Process =~ 'rundll32.exe'
| extend CommandLine = tostring(EventData.CommandLine)
| where CommandLine has_all ('Execute','RegRead','window.close')
| extend SubjectAccount = strcat(EventData.SubjectDomainName,"\\", EventData.SubjectUserName)
| extend ParentProcessName = tostring(EventData.ParentProcessName)
| project TimeGenerated, Computer, SubjectAccount, SubjectUserName = tostring(EventData.SubjectUserName), SubjectDomainName = tostring(EventData.SubjectDomainName), SubjectUserSid = tostring(EventData.SubjectUserSid), Process, NewProcessName, CommandLine, ParentProcessName, _ResourceId
Applied to the Combined Result
| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
| project-away DomainIndex
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
CommandLine | match |
| field:"CommandLine" kind:match |
EventData | match |
| field:"EventData" kind:match |
EventID | eq |
| field:"EventID" kind:eq value:"4688" |
Process | eq |
| field:"Process" kind:eq value:"rundll32.exe" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
CommandLine | project |
Computer | project |
NewProcessName | project |
ParentProcessName | project |
Process | project |
SubjectAccount | project |
SubjectDomainName | project |
SubjectUserName | project |
SubjectUserSid | project |
TimeGenerated | project |
_ResourceId | project |
HostName | extend |
HostNameDomain | extend |
NRT Malicious Inbox Rule
#'Often times after the initial compromise the attackers create inbox rules to delete emails that contain certain keywords. This is done so as to limit ability to warn compromised users that they've been compromised. Below is a sample query that tries to detect this. Reference: https://www.reddit.com/r/sysadmin/comments/7kyp0a/recent_phishing_attempts_my_experience_and_what/'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Persistence | |
| Stealth |
Rules Detecting the Same Action
These rules filter on the same operation.
Rule Body
id: b79f6190-d104-4691-b7db-823e05980895
name: NRT Malicious Inbox Rule
description: |
'Often times after the initial compromise the attackers create inbox rules to delete emails that contain certain keywords.
This is done so as to limit ability to warn compromised users that they've been compromised. Below is a sample query that tries to detect this.
Reference: https://www.reddit.com/r/sysadmin/comments/7kyp0a/recent_phishing_attempts_my_experience_and_what/'
severity: Medium
requiredDataConnectors:
- connectorId: Office365
dataTypes:
- OfficeActivity
tactics:
- Persistence
- DefenseEvasion
relevantTechniques:
- T1098
- T1078
query: |
let Keywords = dynamic(["helpdesk", " alert", " suspicious", "fake", "malicious", "phishing", "spam", "do not click", "do not open", "hijacked", "Fatal"]);
OfficeActivity
| where OfficeWorkload =~ "Exchange"
| where Parameters has "Deleted Items" or Parameters has "Junk Email" or Parameters has "DeleteMessage"
| extend Events=todynamic(Parameters)
| parse Events with * "SubjectContainsWords" SubjectContainsWords '}'*
| parse Events with * "BodyContainsWords" BodyContainsWords '}'*
| parse Events with * "SubjectOrBodyContainsWords" SubjectOrBodyContainsWords '}'*
| where SubjectContainsWords has_any (Keywords)
or BodyContainsWords has_any (Keywords)
or SubjectOrBodyContainsWords has_any (Keywords)
| extend ClientIPAddress = case( ClientIP has ".", tostring(split(ClientIP,":")[0]), ClientIP has "[", tostring(trim_start(@'[[]',tostring(split(ClientIP,"]")[0]))), ClientIP )
| extend Keyword = iff(isnotempty(SubjectContainsWords), SubjectContainsWords, (iff(isnotempty(BodyContainsWords),BodyContainsWords,SubjectOrBodyContainsWords )))
| extend RuleDetail = case(OfficeObjectId contains '/' , tostring(split(OfficeObjectId, '/')[-1]) , tostring(split(OfficeObjectId, '\\')[-1]))
| summarize count(), StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated) by UserId, ClientIPAddress, ResultStatus, Keyword, OriginatingServer, OfficeObjectId, RuleDetail
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: UserId
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: OriginatingServer
- entityType: IP
fieldMappings:
- identifier: Address
columnName: ClientIPAddress
version: 1.0.2
kind: NRT
metadata:
source:
kind: Community
author:
name: Pete Bryan
support:
tier: Community
categories:
domains: [ "Security - Threat Protection" ]
Stages and Predicates
Parameters
let Keywords = dynamic(["helpdesk", " alert", " suspicious", "fake", "malicious", "phishing", "spam", "do not click", "do not open", "hijacked", "Fatal"]);
Stage 1: source
OfficeActivity
Stage 2: where
| where OfficeWorkload =~ "Exchange"
Stage 3: where
| where Parameters has "Deleted Items" or Parameters has "Junk Email" or Parameters has "DeleteMessage"
Stage 4: extend
| extend Events=todynamic(Parameters)
Stage 5: parse
| parse Events with * "SubjectContainsWords" SubjectContainsWords '}'*
Stage 6: parse
| parse Events with * "BodyContainsWords" BodyContainsWords '}'*
Stage 7: parse
| parse Events with * "SubjectOrBodyContainsWords" SubjectOrBodyContainsWords '}'*
Stage 8: where
| where SubjectContainsWords has_any (Keywords)
or BodyContainsWords has_any (Keywords)
or SubjectOrBodyContainsWords has_any (Keywords)
Stage 9: extend (3 consecutive steps)
| extend ClientIPAddress = case( ClientIP has ".", tostring(split(ClientIP,":")[0]), ClientIP has "[", tostring(trim_start(@'[[]',tostring(split(ClientIP,"]")[0]))), ClientIP )
| extend Keyword = iff(isnotempty(SubjectContainsWords), SubjectContainsWords, (iff(isnotempty(BodyContainsWords),BodyContainsWords,SubjectOrBodyContainsWords )))
| extend RuleDetail = case(OfficeObjectId contains '/' , tostring(split(OfficeObjectId, '/')[-1]) , tostring(split(OfficeObjectId, '\\')[-1]))
ClientIPAddress =ClientIP has "."tostring(split(ClientIP, ":")[0])ClientIP has "["tostring(trim_start(@'[[]', tostring(split(ClientIP, "]")[0])))ClientIPStage 10: summarize
| summarize count(), StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated) by UserId, ClientIPAddress, ResultStatus, Keyword, OriginatingServer, OfficeObjectId, RuleDetail
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
BodyContainsWords | match |
| field:"BodyContainsWords" kind:match |
OfficeWorkload | eq |
| field:"m365::Workload" kind:eq value:"Exchange" |
Parameters | match |
| field:"m365::Parameters" kind:match |
SubjectContainsWords | match |
| field:"SubjectContainsWords" kind:match |
SubjectOrBodyContainsWords | match |
| field:"SubjectOrBodyContainsWords" kind:match |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ClientIPAddress | summarize |
EndTimeUtc | summarize |
Keyword | summarize |
OfficeObjectId | summarize |
OriginatingServer | summarize |
ResultStatus | summarize |
RuleDetail | summarize |
StartTimeUtc | summarize |
UserId | summarize |
Pathlock TDnR - HR User Master Change Requests
#Detects change requests to the HR user master data in SAP, forwarded by Pathlock Threat Detection and Response. Unauthorized HR data changes may indicate targeted manipulation of employee records, payroll fraud, or exfiltration of sensitive personnel information.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Collection | |
| Impact |
Rule Body
id: 2a3b4c5d-6e7f-4a0b-8c1d-2e3f4a5b6c30
name: Pathlock TDnR - HR User Master Change Requests
kind: Scheduled
description: >-
Detects change requests to the HR user master data in SAP, forwarded by Pathlock Threat Detection
and Response. Unauthorized HR data changes may indicate targeted manipulation of employee records,
payroll fraud, or exfiltration of sensitive personnel information.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: Pathlock_TDnR
dataTypes:
- Pathlock_TDnR_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Impact
- Collection
relevantTechniques:
- T1565
- T1213
query: |
Pathlock_TDnR_CL
| where DataSource == "HR_PA_CHANGELOG"
| project TimeGenerated, Sysid, DataSource, Eventid, Instance, Hostname, Bname,
Tcode, Report, Area, Subid, SrcIp, DestIp, AffectedUser, LogLine,
MsgType, MsgId, MsgNo, MessageV1, MessageV2, MessageV3, MessageV4, CentralTs
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: Bname
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: Hostname
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SrcIp
eventGroupingSettings:
aggregationKind: SingleAlert
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: 5h
matchingMethod: AnyAlert
groupByEntities: []
groupByAlertDetails: []
groupByCustomDetails: []
suppressionDuration: 5h
suppressionEnabled: false
version: 1.0.0
Stages and Predicates
Stage 1: source
Pathlock_TDnR_CL
Stage 2: where
| where DataSource == "HR_PA_CHANGELOG"
Stage 3: project
| project TimeGenerated, Sysid, DataSource, Eventid, Instance, Hostname, Bname,
Tcode, Report, Area, Subid, SrcIp, DestIp, AffectedUser, LogLine,
MsgType, MsgId, MsgNo, MessageV1, MessageV2, MessageV3, MessageV4, CentralTs
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
DataSource | eq |
| field:"DataSource" kind:eq value:"HR_PA_CHANGELOG" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AffectedUser | project |
Area | project |
Bname | project |
CentralTs | project |
DataSource | project |
DestIp | project |
Eventid | project |
Hostname | project |
Instance | project |
LogLine | project |
MessageV1 | project |
MessageV2 | project |
MessageV3 | project |
MessageV4 | project |
MsgId | project |
MsgNo | project |
MsgType | project |
Report | project |
SrcIp | project |
Subid | project |
Sysid | project |
Tcode | project |
TimeGenerated | project |
Protection Group Deleted
#Detects when a protection group is deleted from Veeam Backup & Replication. This might indicate unauthorized removal of critical components.
Rule Body
id: 5fda37e0-d67c-4e8d-b277-90e5eac2172c
name: Protection Group Deleted
description: Detects when a protection group is deleted from Veeam Backup & Replication.
This might indicate unauthorized removal of critical components.
severity: High
status: Available
requiredDataConnectors:
- connectorId: Syslog
dataTypes:
- Syslog
- connectorId: SyslogAma
dataTypes:
- Syslog
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
eventGroupingSettings:
aggregationKind: AlertPerResult
tactics: []
relevantTechniques: []
query: "Veeam_GetSecurityEvents\n| where instanceId == 29120\n| extend ProtectionGroupName\
\ = extract(\"ProtectionGroupName=\\\"([^\\\"]*)\\\"\", 1, SyslogMessage)\n| project\n\
\ Date = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),\n DataSource\
\ = original_host,\n EventId = instanceId,\n [\"User Name\"] = user,\n \
\ [\"Protection Group Name\"] = ProtectionGroupName,\n MessageDetails = Description,\n\
\ Severity = SeverityDescription"
version: 1.0.1
kind: Scheduled
customDetails:
Date: Date
VbrHostName: DataSource
EventId: EventId
MessageDetails: MessageDetails
Severity: Severity
Stages and Predicates
Stage 1: source
Veeam_GetSecurityEvents
Stage 2: where
| where instanceId == 29120
Stage 3: extend
| extend ProtectionGroupName = extract("ProtectionGroupName=\"([^\"]*)\"", 1, SyslogMessage)
Stage 4: project
| project
Date = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),
DataSource = original_host,
EventId = instanceId,
["User Name"] = user,
["Protection Group Name"] = ProtectionGroupName,
MessageDetails = Description,
Severity = SeverityDescription
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
instanceId | eq |
| field:"instanceId" kind:eq value:"29120" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DataSource | project |
Date | project |
EventId | project |
MessageDetails | project |
Protection Group Name | project |
Severity | project |
User Name | project |
Samsung Knox - Suspicious URL Accessed Events
#This is a third-party alert feed, not a detection over modeled telemetry. The vendor product raised the finding; this rule forwards it into the SIEM. It is searchable for reference but is excluded from the detection-rule browse and the ATT&CK coverage matrix.
'When a Knox device user clicks on URLs or links detected as suspicious (potentially phishing or malicious) with a high degree of confidence.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: 18d4d4f3-6605-4fd2-968c-82c171409c1c
name: Samsung Knox - Suspicious URL Accessed Events
version: 1.0.2
kind: NRT
description: |
'When a Knox device user clicks on URLs or links detected as suspicious (potentially phishing or malicious) with a high degree of confidence.'
severity: High
status: Available
requiredDataConnectors:
- connectorId: SamsungDCDefinition
dataTypes:
- Samsung_Knox_User_CL
tactics:
- InitialAccess
relevantTechniques:
- T1566
query: |
Samsung_Knox_User_CL
| where Name == "SUSPICIOUS_URL_ACCESSED"
and ConfidenceScore > 0.9
suppressionEnabled: false
suppressionDuration: PT5H
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: Url
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: false
reopenClosedIncident: false
lookbackDuration: PT5H
matchingMethod: AllEntities
eventGroupingSettings:
aggregationKind: SingleAlert
Stages and Predicates
Stage 1: source
Samsung_Knox_User_CL
Stage 2: where
| where Name == "SUSPICIOUS_URL_ACCESSED"
and ConfidenceScore > 0.9
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ConfidenceScore | gt |
| field:"ConfidenceScore" kind:gt value:"0.9" |
Name | eq |
| field:"Name" kind:eq value:"SUSPICIOUS_URL_ACCESSED" |
Snowflake - Query on sensitive or restricted table
#'Detects query on sensitive or restricted table.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Collection |
Rule Body
id: f258fa0c-e26c-4e2b-94fb-88b6cef0ca6e
name: Snowflake - Query on sensitive or restricted table
description: |
'Detects query on sensitive or restricted table.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: Snowflake
dataTypes:
- Snowflake
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Collection
relevantTechniques:
- T1119
query: |
let r_tbl = dynamic(['table_name']);
Snowflake
| where QueryType =~ 'SELECT'
| where QueryExecutionStatus =~ 'SUCCESS'
| extend tbl = extract(@'(FROM|from)\s(\S+)\s', 2, QueryText)
| where tbl in~ (r_tbl)
| extend AccountCustomEntity = TargetUsername
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountCustomEntity
version: 1.0.1
kind: Scheduled
Stages and Predicates
Parameters
let r_tbl = dynamic(['table_name']);
Stage 1: source
Snowflake
Stage 2: where
| where QueryType =~ 'SELECT'
Stage 3: where
| where QueryExecutionStatus =~ 'SUCCESS'
Stage 4: extend
| extend tbl = extract(@'(FROM|from)\s(\S+)\s', 2, QueryText)
Stage 5: where
| where tbl in~ (r_tbl)
Stage 6: extend
| extend AccountCustomEntity = TargetUsername
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
QueryExecutionStatus | eq |
| field:"QueryExecutionStatus" kind:eq value:"SUCCESS" |
QueryType | eq |
| field:"QueryType" kind:eq value:"SELECT" |
tbl | in |
| field:"tbl" kind:in value:"r_tbl" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
tbl | extend |
AccountCustomEntity | extend |
Vaikora - Behavioral anomaly detected
#This is a third-party alert feed, not a detection over modeled telemetry. The vendor product raised the finding; this rule forwards it into the SIEM. It is searchable for reference but is excluded from the detection-rule browse and the ATT&CK coverage matrix.
Identifies AI agent actions flagged as behavioral anomalies by Vaikora that fall outside the high or critical severity buckets but still represent statistically unusual activity worth investigation.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Discovery | No specific technique |
| Lateral Movement | No specific technique |
| Collection | No specific technique |
| Exfiltration | No specific technique |
Rule Body
id: c0984707-0855-430e-9c36-5e2d0d0ce56f
name: Vaikora - Behavioral anomaly detected
description: |
Identifies AI agent actions flagged as behavioral anomalies by Vaikora that fall outside the high or critical severity buckets but still represent statistically unusual activity worth investigation.
severity: Medium
requiredDataConnectors:
- connectorId: VaikoraSecurityCenter
dataTypes:
- Vaikora_AgentSignals_CL
queryFrequency: 6h
queryPeriod: 6h
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
- Discovery
- LateralMovement
- Collection
- Exfiltration
relevantTechniques: []
query: |
Vaikora_AgentSignals_CL
| where TimeGenerated >= ago(6h)
| where is_anomaly_b == true
| where severity_s !in ("high", "critical")
| extend
ActionId = action_id_s,
AgentId = agent_id_s,
ActionType = action_type_s,
Severity = severity_s,
Status = status_s,
AnomalyScore = anomaly_score_d
| project TimeGenerated, ActionId, AgentId, ActionType, Severity, Status, AnomalyScore
| order by AnomalyScore desc, TimeGenerated desc
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AgentId
alertDetailsOverride:
alertDisplayNameFormat: "Vaikora anomaly on agent {{agent_id_s}}: {{action_type_s}}"
alertDescriptionFormat: "Vaikora flagged a behavioral anomaly with score {{anomaly_score_d}}."
version: 1.0.1
kind: Scheduled
Stages and Predicates
Stage 1: source
Vaikora_AgentSignals_CL
Stage 2: where
| where TimeGenerated >= ago(6h)
Stage 3: where
| where is_anomaly_b == true
Stage 4: where
| where severity_s !in ("high", "critical")
Stage 5: extend
| extend
ActionId = action_id_s,
AgentId = agent_id_s,
ActionType = action_type_s,
Severity = severity_s,
Status = status_s,
AnomalyScore = anomaly_score_d
Stage 6: project
| project TimeGenerated, ActionId, AgentId, ActionType, Severity, Status, AnomalyScore
Stage 7: sort
| order by AnomalyScore desc, TimeGenerated desc
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
is_anomaly_b | eq |
| field:"is_anomaly_b" kind:eq value:"true" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
severity_s | in | critical, high | excludes:severity_s field:"severity_s" value:"critical" field:"severity_s" value:"high" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ActionId | project |
ActionType | project |
AgentId | project |
AnomalyScore | project |
Severity | project |
Status | project |
TimeGenerated | project |
Veeam ONE Backup Server Security and Compliance State
#This is a third-party alert feed, not a detection over modeled telemetry. The vendor product raised the finding; this rule forwards it into the SIEM. It is searchable for reference but is excluded from the detection-rule browse and the ATT&CK coverage matrix.
Detects backup server security and compliance state issues.
Rule Body
id: 7ad4b9ff-8089-4b70-b98e-a2ca995611e9
name: Veeam ONE Backup Server Security and Compliance State
description: Detects backup server security and compliance state issues.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: VeeamCustomTablesDataConnector
dataTypes:
- VeeamOneTriggeredAlarms_CL
queryFrequency: 3h
queryPeriod: 3h
triggerOperator: gt
triggerThreshold: 0
eventGroupingSettings:
aggregationKind: AlertPerResult
tactics: []
relevantTechniques: []
query: VeeamOneTriggeredAlarms_CL | where PredefinedAlarmId == 395
version: 1.0.1
kind: Scheduled
customDetails:
PredefinedAlarmId: PredefinedAlarmId
TriggeredAlarmId: TriggeredAlarmId
Description: Description
Name: Name
VoneHostName: VoneHostName
TriggeredTime: TriggeredTime
Status: Status
Comment: Comment
ObjectId: ObjectId
ObjectName: ObjectName
ObjectType: ObjectType
Stages and Predicates
Stage 1: source
VeeamOneTriggeredAlarms_CL
Stage 2: where
| where PredefinedAlarmId == 395
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
PredefinedAlarmId | eq |
| field:"PredefinedAlarmId" kind:eq value:"395" |