Detection rules › Kusto
Kusto rules: 31
App Gateway WAF - SQLi Detection
#'Identifies a match for a SQL Injection attack in the App Gateway WAF logs. The threshold value in the query can be changed as per your infrastructure's requirements. References: https://owasp.org/Top10/A03_2021-Injection/'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Execution | |
| Stealth | |
| Privilege Escalation |
Rule Body
id: bdb2cd63-99f2-472e-b1b9-acba473b6744
name: App Gateway WAF - SQLi Detection
description: |
'Identifies a match for a SQL Injection attack in the App Gateway WAF logs. The threshold value in the query can be changed as per your infrastructure's requirements.
References: https://owasp.org/Top10/A03_2021-Injection/'
severity: High
status: Available
requiredDataConnectors:
- connectorId: WAF
dataTypes:
- AzureDiagnostics
queryFrequency: 6h
queryPeriod: 6h
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
- Execution
- InitialAccess
- PrivilegeEscalation
relevantTechniques:
- T1211
- T1059
- T1190
- T0890
tags:
- SQL Injection
query: |
let Threshold = 3;
AGWFirewallLogs
| where Action == "Matched"
| where Message has "SQL Injection"
| project TransactionId, Hostname, RequestUri, TimeGenerated, ClientIp, Message
| join kind = inner(
AGWFirewallLogs
| where Action == "Blocked"
| extend transactionId_g = tostring(TransactionId)) on TransactionId
| extend Uri = strcat(Hostname,RequestUri)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), TransactionID = make_set(transactionId_g,100), Message = make_set(Message,100), Total_TransactionId = dcount(transactionId_g) by ClientIp, Uri, Action
| where Total_TransactionId >= Threshold
# The Threshold value above can be changed as per your infrastructure's requirement
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: Uri
- entityType: IP
fieldMappings:
- identifier: Address
columnName: ClientIp
version: 1.0.2
kind: Scheduled
Stages and Predicates
Parameters
let Threshold = 3;
Stage 1: source
AGWFirewallLogs
Stage 2: where
| where Action == "Matched"
Stage 3: where
| where Message has "SQL Injection"
Stage 4: project
| project TransactionId, Hostname, RequestUri, TimeGenerated, ClientIp, Message
Stage 5: join
| join kind = inner(
AGWFirewallLogs
| where Action == "Blocked"
| extend transactionId_g = tostring(TransactionId)) on TransactionId
Stage 6: extend
extend Uri
Stage 7: summarize
summarize EndTime, Message, StartTime, Total_TransactionId, TransactionID by ClientIp, Uri, Action
Stage 8: where
where Total_TransactionId >= 3
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Action | eq |
| field:"Action" kind:eq |
Message | match |
| field:"Message" kind:match value:"SQL Injection" |
Total_TransactionId | ge |
| field:"Total_TransactionId" kind:ge value:"3" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Action | summarize |
ClientIp | summarize |
EndTime | summarize |
Message | summarize |
StartTime | summarize |
Total_TransactionId | summarize |
TransactionID | summarize |
Uri | summarize |
Attempt to Delete Backup Failed
#Detects failed backup operations. This might indicate system or storage issues, or a potential sabotage of the backup infrastructure.
Rule Body
id: 4595192f-671b-4724-aa62-093a9724c2f3
name: Attempt to Delete Backup Failed
description: Detects failed backup operations. This might indicate system or storage
issues, or a potential sabotage of the backup infrastructure.
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 == 41800\n| extend Endpoint =\
\ extract(\"param2=\\\"([^\\\"]*)\\\"\", 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 [\"Endpoint\"] = Endpoint,\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 == 41800
Stage 3: extend
| extend Endpoint = extract("param2=\"([^\"]*)\"", 1, SyslogMessage)
Stage 4: project
| project
Date = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),
DataSource = original_host,
EventId = instanceId,
["User Name"] = user,
["Endpoint"] = Endpoint,
MessageDetails = Description,
Severity = SeverityDescription
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
instanceId | eq |
| field:"instanceId" kind:eq value:"41800" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DataSource | project |
Date | project |
Endpoint | project |
EventId | project |
MessageDetails | project |
Severity | project |
User Name | project |
BloodHound Attack Path Finding - WriteDacl Privileges on Tier Zero Objects
#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.
BloodHound Attack Path Finding - WriteDacl Privileges on Tier Zero Objects
Rule Body
id: c09d3a9d-47da-4bd8-a14d-ea51b447d75d
name: BloodHound Attack Path Finding - WriteDacl Privileges on Tier Zero Objects
description: BloodHound Attack Path Finding - WriteDacl Privileges on Tier Zero Objects
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: BloodHoundEnterprise
dataTypes:
- BHEAttackPathsData_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics: []
relevantTechniques: []
query: BHEAttackPathsData_CL | where Finding == "T0WriteDACL"
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: domain_name
customDetails:
Description: ShortDescription
Remediation: ShortRemediation
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
BHEAttackPathsData_CL
Stage 2: where
| where Finding == "T0WriteDACL"
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Finding | eq |
| field:"Finding" kind:eq value:"T0WriteDACL" |
Cognni Incidents for Low Sensitivity Business Information
#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.
'Display incidents in which low sensitivity business information] was placed at risk by user sharing.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Collection |
Rule Body
id: a0647a60-16f9-4175-b344-5cdd2934413f
name: Cognni Incidents for Low Sensitivity Business Information
description: |
'Display incidents in which low sensitivity business information] was placed at risk by user sharing.'
severity: Low
requiredDataConnectors:
- connectorId: CognniSentinelDataConnector
dataTypes:
- CognniIncidents_CL
queryFrequency: 5h
queryPeriod: 5h
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
- Collection
relevantTechniques:
- T1530
query: |
let lowRisk = 1;
let business = 'Business Information';
CognniIncidents_CL
| where Severity == lowRisk
| where informationType_s == business
| where TimeGenerated >= ago(5h)
| extend AccountCustomEntity = userId_s
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
version: 1.0.0
kind: Scheduled
Stages and Predicates
Parameters
let lowRisk = 1;
let business = 'Business Information';
Stage 1: source
CognniIncidents_CL
Stage 2: where
| where Severity == lowRisk
Stage 3: where
| where informationType_s == business
Stage 4: where
| where TimeGenerated >= ago(5h)
Stage 5: extend
| extend AccountCustomEntity = userId_s
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Severity | eq |
| field:"Severity" kind:eq value:"1" |
informationType_s | eq |
| field:"informationType_s" kind:eq value:"Business Information" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AccountCustomEntity | extend |
Contrast Blocks
#'Creates Incidents for Blocked events sourced from the Contrast Protect agent.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: 4396f8c3-d114-4154-9f4c-048ba522ed04
name: Contrast Blocks
description: |
'Creates Incidents for Blocked events sourced from the Contrast Protect agent.'
severity: Low
requiredDataConnectors:
- connectorId: ContrastProtect
dataTypes:
- CommonSecurityLog
- connectorId: ContrastProtectAma
dataTypes:
- CommonSecurityLog
- connectorId: CefAma
dataTypes:
- CommonSecurityLog
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
- InitialAccess
- Exfiltration
relevantTechniques:
- T1566
query: |
let extract_data=(a:string, k:string) {
parse_urlquery(replace(@';', @'&', a))["Query Parameters"][k]
};
CommonSecurityLog
| where DeviceVendor == "Contrast Security"
| where AdditionalExtensions contains "BLOCKED"
| extend DeviceProduct
| extend SourceIP
| extend DeviceVersion
| extend Activity
| extend ApplicationProtocol
| extend RequestURL
| extend RequestMethod
| extend Rule = extract_data(AdditionalExtensions, 'pri')
customDetails:
Application: ApplicationProtocol
Agent: DeviceProduct
AgentVersion: DeviceVersion
Attack: Activity
Details: AdditionalExtensions
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SourceIP
- entityType: URL
fieldMappings:
- identifier: Url
columnName: RequestURL
- entityType: CloudApplication
fieldMappings:
- identifier: Name
columnName: ApplicationProtocol
- entityType: Malware
fieldMappings:
- identifier: Name
columnName: Activity
- identifier: Category
columnName: Rule
version: 1.0.2
kind: Scheduled
Stages and Predicates
Let Binding: extract_data
let extract_data = (a:string, k:string) {
parse_urlquery(replace(@';', @'&', a))["Query Parameters"][k]
};
Stage 1: source
CommonSecurityLog
Stage 2: where
| where DeviceVendor == "Contrast Security"
Stage 3: where
| where AdditionalExtensions contains "BLOCKED"
Stage 4: extend (8 consecutive steps)
| extend DeviceProduct
| extend SourceIP
| extend DeviceVersion
| extend Activity
| extend ApplicationProtocol
| extend RequestURL
| extend RequestMethod
| extend Rule = extract_data(AdditionalExtensions, 'pri')
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
AdditionalExtensions | contains |
| field:"AdditionalExtensions" kind:contains value:"BLOCKED" |
DeviceVendor | eq |
| field:"DeviceVendor" kind:eq value:"Contrast Security" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DeviceProduct | extend |
SourceIP | extend |
DeviceVersion | extend |
Activity | extend |
ApplicationProtocol | extend |
RequestURL | extend |
RequestMethod | extend |
Rule | extend |
CYFIRMA - Medium severity Malicious Phishing Network Indicators - Monitor Recommended Rule
#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.
"This analytics rule identifies network-based indicators such as URLs, IP addresses, and domains related to phishing campaigns, as reported by CYFIRMA threat intelligence. These indicators are flagged with a recommended action to block and are categorized under the 'Phishing' role. Such infrastructure is often used to deliver phishing emails, host fake login portals, or redirect victims to credential-harvesting pages. monitoring these indicators proactively helps prevent user compromise and data theft."
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Execution | |
| Credential Access | |
| Exfiltration |
Rule Body
id: 1b9603dd-4787-403e-8a35-387c554bd15b
name: CYFIRMA - Medium severity Malicious Phishing Network Indicators - Monitor Recommended Rule
description: |
"This analytics rule identifies network-based indicators such as URLs, IP addresses, and domains related to phishing campaigns, as reported by CYFIRMA threat intelligence.
These indicators are flagged with a recommended action to block and are categorized under the 'Phishing' role.
Such infrastructure is often used to deliver phishing emails, host fake login portals, or redirect victims to credential-harvesting pages.
monitoring these indicators proactively helps prevent user compromise and data theft."
version: 1.0.1
kind: Scheduled
severity: Medium
enabled: false
requiredDataConnectors:
- connectorId: CyfirmaCyberIntelligenceDC
dataTypes:
- CyfirmaIndicators_CL
query: |
//Phishing Network Indicators - Monitor Recommended
let timeFrame= 5m;
CyfirmaIndicators_CL
| where (ConfidenceScore < 80 and ConfidenceScore >= 50)
and TimeGenerated between (ago(timeFrame) .. now())
and pattern !contains 'file:hashes' and RecommendedActions has 'Monitor' and Roles has 'Phishing'
| extend IPv4 = extract(@"ipv4-addr:value\s*=\s*'([^']+)'", 1, pattern)
| extend IPv6 = extract(@"ipv6-addr:value\s*=\s*'([^']+)'", 1, pattern)
| extend URL = extract(@"url:value\s*=\s*'([^']+)'", 1, pattern)
| extend Domain = extract(@"domain-name:value\s*=\s*'([^']+)'", 1, pattern)
| extend parsed = parse_json(extensions)
| extend extensionKeys = bag_keys(parsed)
| mv-expand extensionKeys
| extend extensionKeyStr = tostring(extensionKeys)
| extend ext = parsed[extensionKeyStr]
| extend props = ext.properties
| extend
extension_id = extensionKeyStr,
ASN_Owner = props.asn_owner,
ASN = props.asn,
ProviderName = 'CYFIRMA',
ProductName = 'DeCYFIR/DeTCT'
| project
IPv4,
IPv6,
URL,
Domain,
ThreatActors,
RecommendedActions,
Sources,
Roles,
Country,
IPAbuse,
name,
Description,
ConfidenceScore,
IndicatorID,
created,
modified,
valid_from,
Tags,
ThreatType,
TimeGenerated,
SecurityVendors,
ProductName,
ProviderName
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: GreaterThan
triggerThreshold: 0
suppressionDuration: 5m
suppressionEnabled: true
tactics:
- InitialAccess
- Execution
- CredentialAccess
- Exfiltration
relevantTechniques:
- T1566
- T1204
- T1556
- T1110
- T1041
- T1566.001
- T1566.002
- T1204.001
- T1556.002
- T1110.003
alertDetailsOverride:
alertDisplayNameFormat: "High-Confidence Malicious Phishing Network Indicators - Monitor Recommended - {{name}} "
alertDescriptionFormat: "{{Description}} - {{name}} "
alertDynamicProperties:
- alertProperty: ProductName
value: ProductName
- alertProperty: ProviderName
value: ProviderName
customDetails:
ThreatActors: ThreatActors
Sources: Sources
RecommendedActions: RecommendedActions
Roles: Roles
Country: Country
Description: Description
ConfidenceScore: ConfidenceScore
SecurityVendors: SecurityVendors
IndicatorID: IndicatorID
Created: created
Modified: modified
ValidFrom: valid_from
Tags: Tags
ThreatType: ThreatType
TimeGenerated: TimeGenerated
IPAbuse: IPAbuse
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPv4
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPv6
- entityType: DNS
fieldMappings:
- identifier: DomainName
columnName: Domain
- entityType: URL
fieldMappings:
- identifier: Url
columnName: URL
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: false
reopenClosedIncident: false
lookbackDuration: PT5H
matchingMethod: AllEntities
eventGroupingSettings:
aggregationKind: AlertPerResult
Stages and Predicates
Parameters
let timeFrame = 5m;
Stage 1: source
CyfirmaIndicators_CL
Stage 2: where
| where (ConfidenceScore < 80 and ConfidenceScore >= 50)
and TimeGenerated between (ago(timeFrame) .. now())
and pattern !contains 'file:hashes' and RecommendedActions has 'Monitor' and Roles has 'Phishing'
Stage 3: extend (6 consecutive steps)
| extend IPv4 = extract(@"ipv4-addr:value\s*=\s*'([^']+)'", 1, pattern)
| extend IPv6 = extract(@"ipv6-addr:value\s*=\s*'([^']+)'", 1, pattern)
| extend URL = extract(@"url:value\s*=\s*'([^']+)'", 1, pattern)
| extend Domain = extract(@"domain-name:value\s*=\s*'([^']+)'", 1, pattern)
| extend parsed = parse_json(extensions)
| extend extensionKeys = bag_keys(parsed)
Stage 4: mv-expand
| mv-expand extensionKeys
Stage 5: extend (4 consecutive steps)
| extend extensionKeyStr = tostring(extensionKeys)
| extend ext = parsed[extensionKeyStr]
| extend props = ext.properties
| extend
extension_id = extensionKeyStr,
ASN_Owner = props.asn_owner,
ASN = props.asn,
ProviderName = 'CYFIRMA',
ProductName = 'DeCYFIR/DeTCT'
Stage 6: project
| project
IPv4,
IPv6,
URL,
Domain,
ThreatActors,
RecommendedActions,
Sources,
Roles,
Country,
IPAbuse,
name,
Description,
ConfidenceScore,
IndicatorID,
created,
modified,
valid_from,
Tags,
ThreatType,
TimeGenerated,
SecurityVendors,
ProductName,
ProviderName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ConfidenceScore | ge |
| field:"ConfidenceScore" kind:ge value:"50" |
ConfidenceScore | lt |
| field:"ConfidenceScore" kind:lt value:"80" |
RecommendedActions | match |
| field:"RecommendedActions" kind:match value:"Monitor" |
Roles | match |
| field:"Roles" kind:match value:"Phishing" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
pattern | contains | file:hashes | excludes:pattern field:"pattern" value:"file:hashes" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ConfidenceScore | project |
Country | project |
Description | project |
Domain | project |
IPAbuse | project |
IPv4 | project |
IPv6 | project |
IndicatorID | project |
ProductName | project |
ProviderName | project |
RecommendedActions | project |
Roles | project |
SecurityVendors | project |
Sources | project |
Tags | project |
ThreatActors | project |
ThreatType | project |
TimeGenerated | project |
URL | project |
created | project |
modified | project |
name | project |
valid_from | project |
CYFIRMA - Social and Public Exposure - Exposure of PII/CII in Public Domain Rule
#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.
"This analytics rule detects high severity alerts from CYFIRMA indicating exposure of Personally Identifiable Information (PII) or Confidential Information (CII) in public or unsecured sources. Such leaks may include email addresses, credentials, phone numbers, or other sensitive personal or organizational data. These exposures can lead to identity theft, phishing, credential compromise, or regulatory non-compliance. Investigate promptly and initiate remediation steps including user notifications and credential resets."
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Credential Access | |
| Collection | |
| Exfiltration |
Rule Body
id: b484f224-687f-4406-af8a-ff019f9f2c24
name: CYFIRMA - Social and Public Exposure - Exposure of PII/CII in Public Domain Rule
description: |
"This analytics rule detects high severity alerts from CYFIRMA indicating exposure of Personally Identifiable Information (PII) or Confidential Information (CII) in public or unsecured sources.
Such leaks may include email addresses, credentials, phone numbers, or other sensitive personal or organizational data.
These exposures can lead to identity theft, phishing, credential compromise, or regulatory non-compliance.
Investigate promptly and initiate remediation steps including user notifications and credential resets."
version: 1.0.1
kind: Scheduled
severity: Medium
requiredDataConnectors:
- connectorId: CyfirmaDigitalRiskAlertsConnector
dataTypes:
- CyfirmaSPEPIIAndCIIAlerts_CL
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
- InitialAccess
- Exfiltration
- Collection
- CredentialAccess
relevantTechniques:
- T1078
- T1003
- T1213
- T1537
query: |
// Medium severity - Social and Public Exposure - Exposure of PII/CII in Public Domain
let timeFrame = 5m;
CyfirmaSPEPIIAndCIIAlerts_CL
| where severity == 'High' and TimeGenerated between (ago(timeFrame) .. now())
| extend
Description=description,
FirstSeen=first_seen,
LastSeen=last_seen,
RiskScore=risk_score,
AlertUID=alert_uid,
UID=uid,
AssetType=asset_type,
AssetValue=signature,
Source=source,
Impact=impact,
Recommendation=recommendation,
PostedDate=posted_date,
ProviderName='CYFIRMA',
ProductName='DeCYFIR/DeTCT',
AlertTitle=Alert_title
| project
TimeGenerated,
Description,
RiskScore,
FirstSeen,
LastSeen,
AlertUID,
UID,
AssetType,
AssetValue,
Source,
Impact,
Recommendation,
PostedDate,
ProductName,
ProviderName,
AlertTitle
customDetails:
AssetType: AssetType
AssetValue: AssetValue
RiskScore: RiskScore
Source: Source
Impact: Impact
Description: Description
Recommendation: Recommendation
FirstSeen: FirstSeen
LastSeen: LastSeen
AlertUID: AlertUID
UID: UID
TimeGenerated: TimeGenerated
alertDetailsOverride:
alertDisplayNameFormat: "CYFIRMA - Medium Severity: Exposure of PII/CII in Public Domain - {{AlertTitle}} "
alertDescriptionFormat: "{{Description}} "
alertDynamicProperties:
- alertProperty: ProductName
value: ProductName
- alertProperty: ProviderName
value: ProviderName
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: false
reopenClosedIncident: false
lookbackDuration: PT5H
matchingMethod: AllEntities
eventGroupingSettings:
aggregationKind: AlertPerResult
Stages and Predicates
Parameters
let timeFrame = 5m;
Stage 1: source
CyfirmaSPEPIIAndCIIAlerts_CL
Stage 2: where
| where severity == 'High' and TimeGenerated between (ago(timeFrame) .. now())
Stage 3: extend
| extend
Description=description,
FirstSeen=first_seen,
LastSeen=last_seen,
RiskScore=risk_score,
AlertUID=alert_uid,
UID=uid,
AssetType=asset_type,
AssetValue=signature,
Source=source,
Impact=impact,
Recommendation=recommendation,
PostedDate=posted_date,
ProviderName='CYFIRMA',
ProductName='DeCYFIR/DeTCT',
AlertTitle=Alert_title
Stage 4: project
| project
TimeGenerated,
Description,
RiskScore,
FirstSeen,
LastSeen,
AlertUID,
UID,
AssetType,
AssetValue,
Source,
Impact,
Recommendation,
PostedDate,
ProductName,
ProviderName,
AlertTitle
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
severity | eq |
| field:"severity" kind:eq value:"High" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AlertTitle | project |
AlertUID | project |
AssetType | project |
AssetValue | project |
Description | project |
FirstSeen | project |
Impact | project |
LastSeen | project |
PostedDate | project |
ProductName | project |
ProviderName | project |
Recommendation | project |
RiskScore | project |
Source | project |
TimeGenerated | project |
UID | project |
Cynerio - Exploitation Attempt of IoT device
#Exploitation Attempt of IoT device - Attack detection
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Lateral Movement |
Rule Body
id: 3d853a88-92d2-4aec-a680-2bf7bb560c56
name: Cynerio - Exploitation Attempt of IoT device
description: Exploitation Attempt of IoT device - Attack detection
severity: High
requiredDataConnectors:
- connectorId: CynerioSecurityEvents
dataTypes:
- CynerioEvent_CL
queryFrequency: 5h
queryPeriod: 5h
triggerOperator: gt
triggerThreshold: 0
tactics:
- LateralMovement
relevantTechniques:
- T0866
query: |
CynerioEvent_CL
| where TimeGenerated > ago(24h)
| where module_s == 'IDS'
| where title_s == 'Exploitation Attempt'
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: asset_ip_s
- entityType: IP
fieldMappings:
- identifier: Address
columnName: dst_ip_s
eventGroupingSettings:
aggregationKind: SingleAlert
customDetails:
ExploitDescription: details_s
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
CynerioEvent_CL
Stage 2: where
| where TimeGenerated > ago(24h)
Stage 3: where
| where module_s == 'IDS'
Stage 4: where
| where title_s == 'Exploitation Attempt'
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
module_s | eq |
| field:"module_s" kind:eq value:"IDS" |
title_s | eq |
| field:"title_s" kind:eq value:"Exploitation Attempt" |
Flare infected device results
#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.
'This query searches for infected device events on Darkweb or Telegram.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Credential Access |
Rule Body
id: 9cb7c337-f176-4af6-b0e8-b6b7552d762d
name: Flare infected device results
description: |
'This query searches for infected device events on Darkweb or Telegram.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: Flare
dataTypes:
- FireworkV2_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- CredentialAccess
relevantTechniques:
- T1555
query: |
FireworkV2_CL
| where notempty(uid) and RiskScore >= 3
| extend index_name = split(uid, "/")[0]
| where index_name in ("bot", "stealer_log")
version: 3.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
FireworkV2_CL
Stage 2: where
| where notempty(uid) and RiskScore >= 3
Stage 3: extend
| extend index_name = split(uid, "/")[0]
Stage 4: where
| where index_name in ("bot", "stealer_log")
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
RiskScore | ge |
| field:"RiskScore" kind:ge value:"3" |
index_name | in |
| field:"index_name" kind:in |
uid | is_not_null | field:"uid" kind:is_not_null |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
index_name | extend |
Google DNS - Multiple errors to same domain
#'Detects multiple errors to same domain.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Command & Control |
Rule Body
id: da04a5d6-e2be-4cba-8cdb-a3f2efa87e9e
name: Google DNS - Multiple errors to same domain
description: |
'Detects multiple errors to same domain.'
severity: Medium
requiredDataConnectors:
- connectorId: GCPDNSDataConnector
dataTypes:
- GCPCloudDNS
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandAndControl
relevantTechniques:
- T1095
query: |
let threshold = 2;
let err = dynamic(['NXDOMAIN', 'SERVFAIL', 'REFUSED']);
GCPCloudDNS
| where EventResultDetails in~ (err)
| summarize ips = makeset(SrcIpAddr) by Query, bin(TimeGenerated, 10m)
| where array_length(ips) >= threshold
| extend DNSCustomEntity = Query, IPCustomEntity = ips
entityMappings:
- entityType: DNS
fieldMappings:
- identifier: DomainName
columnName: DNSCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.0
kind: Scheduled
Stages and Predicates
Parameters
let threshold = 2;
let err = dynamic(['NXDOMAIN', 'SERVFAIL', 'REFUSED']);
Stage 1: source
GCPCloudDNS
Stage 2: where
| where EventResultDetails in~ (err)
Stage 3: summarize
| summarize ips = makeset(SrcIpAddr) by Query, bin(TimeGenerated, 10m)
Stage 4: where
| where array_length(ips) >= threshold
Stage 5: extend
| extend DNSCustomEntity = Query, IPCustomEntity = ips
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventResultDetails | in |
| field:"EventResultDetails" kind:in |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Query | summarize |
ips | summarize |
DNSCustomEntity | extend |
IPCustomEntity | extend |
GreyNoise TI map IP entity to OfficeActivity
#This query maps any GreyNoise IP indicators of compromise (IOCs) from threat intelligence (TI), by searching for matches in OfficeActivity.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Command & Control |
Rule Body
id: c51628fe-999c-5150-9fd7-660fc4f58ed2
name: GreyNoise TI map IP entity to OfficeActivity
version: 1.0.1
kind: Scheduled
description: |
This query maps any GreyNoise IP indicators of compromise (IOCs) from threat intelligence (TI), by searching for matches in OfficeActivity.
severity: Medium
requiredDataConnectors:
- connectorId: ThreatIntelligence
dataTypes:
- ThreatIntelligenceIndicator
- connectorId: ThreatIntelligenceTaxii
dataTypes:
- ThreatIntelligenceIndicator
- connectorId: MicrosoftDefenderThreatIntelligence
dataTypes:
- ThreatIntelligenceIndicator
- connectorId: Office365
dataTypes:
- OfficeActivity
- connectorId: GreyNoise2SentinelAPI
dataTypes:
- ThreatIntelligenceIndicator
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandAndControl
relevantTechniques:
- T1071
query: |
let dt_lookBack = 1h; // Look back 1 hour for OfficeActivity events
let ioc_lookBack = 14d; // Look back 14 days for threat intelligence indicators
// Fetch threat intelligence indicators related to IP addresses
let IP_Indicators = ThreatIntelligenceIndicator
| where TimeGenerated >= ago(ioc_lookBack)
| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
| where Active == true and ExpirationDateTime > now()
| where SourceSystem == 'GreyNoise'
| where isnotempty(NetworkIP) or isnotempty(EmailSourceIpAddress) or isnotempty(NetworkDestinationIP) or isnotempty(NetworkSourceIP)
| extend TI_ipEntity = iff(isnotempty(NetworkIP), NetworkIP, NetworkDestinationIP)
| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(NetworkSourceIP), NetworkSourceIP, TI_ipEntity)
| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(EmailSourceIpAddress), EmailSourceIpAddress, TI_ipEntity)
| where ipv4_is_private(TI_ipEntity) == false and TI_ipEntity !startswith "fe80" and TI_ipEntity !startswith "::" and TI_ipEntity !startswith "127.";
// Perform a join between IP indicators and OfficeActivity events
IP_Indicators
// Use innerunique to keep performance fast and result set low, as we only need one match to indicate potential malicious activity that needs investigation
| join kind=innerunique (
OfficeActivity
| where TimeGenerated >= ago(dt_lookBack)
| where isnotempty(ClientIP)
| extend ClientIPValues = extract_all(@'\[?(::ffff:)?(?P<IPAddress>(\d+\.\d+\.\d+\.\d+)|[^\]%]+)(%\d+)?\]?([-:](?P<Port>\d+))?', dynamic(["IPAddress", "Port"]), ClientIP)[0]
| extend IPAddress = iff(array_length(ClientIPValues) > 0, tostring(ClientIPValues[0]), '')
| extend OfficeActivity_TimeGenerated = TimeGenerated
)
on $left.TI_ipEntity == $right.IPAddress
// Filter out OfficeActivity events that occurred after the expiration of the corresponding indicator
| where OfficeActivity_TimeGenerated < ExpirationDateTime
// Group the results by IndicatorId and keep the OfficeActivity event with the latest timestamp
| summarize OfficeActivity_TimeGenerated = arg_max(OfficeActivity_TimeGenerated, *) by IndicatorId
// Select the desired output fields
| project OfficeActivity_TimeGenerated, Description, ActivityGroupNames, IndicatorId, ThreatType, Url, ExpirationDateTime, ConfidenceScore,
TI_ipEntity, ClientIP, UserId, Operation, ResultStatus, RecordType, OfficeObjectId, NetworkIP, NetworkDestinationIP, NetworkSourceIP, EmailSourceIpAddress, Type
| extend timestamp = OfficeActivity_TimeGenerated, Name = tostring(split(UserId, '@', 0)[0]), UPNSuffix = tostring(split(UserId, '@', 1)[0])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: Name
- identifier: UPNSuffix
columnName: UPNSuffix
- entityType: IP
fieldMappings:
- identifier: Address
columnName: TI_ipEntity
- entityType: URL
fieldMappings:
- identifier: Url
columnName: Url
Stages and Predicates
Parameters
let dt_lookBack = 1h;
let ioc_lookBack = 14d;
let IP_Indicators is inlined into the numbered stages below.
Stages 1 to 8 define let IP_Indicators as the rule's main pipeline source. Stages 9 to 13 use it.
Stage 1: source
ThreatIntelligenceIndicator
Stage 2: where
| where TimeGenerated >= ago(ioc_lookBack)
Stage 3: summarize
| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
Stage 4: where
| where Active == true and ExpirationDateTime > now()
Stage 5: where
| where SourceSystem == 'GreyNoise'
Stage 6: where
| where isnotempty(NetworkIP) or isnotempty(EmailSourceIpAddress) or isnotempty(NetworkDestinationIP) or isnotempty(NetworkSourceIP)
Stage 7: extend (3 consecutive steps)
| extend TI_ipEntity = iff(isnotempty(NetworkIP), NetworkIP, NetworkDestinationIP)
| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(NetworkSourceIP), NetworkSourceIP, TI_ipEntity)
| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(EmailSourceIpAddress), EmailSourceIpAddress, TI_ipEntity)
TI_ipEntity =isnotempty(NetworkIP)NetworkIPNetworkDestinationIPStage 8: where
| where ipv4_is_private(TI_ipEntity) == false and TI_ipEntity !startswith "fe80" and TI_ipEntity !startswith "::" and TI_ipEntity !startswith "127."
Stage 9: join
IP_Indicators
| join kind=innerunique (
OfficeActivity
| where TimeGenerated >= ago(dt_lookBack)
| where isnotempty(ClientIP)
| extend ClientIPValues = extract_all(@'\[?(::ffff:)?(?P<IPAddress>(\d+\.\d+\.\d+\.\d+)|[^\]%]+)(%\d+)?\]?([-:](?P<Port>\d+))?', dynamic(["IPAddress", "Port"]), ClientIP)[0]
| extend IPAddress = iff(array_length(ClientIPValues) > 0, tostring(ClientIPValues[0]), '')
| extend OfficeActivity_TimeGenerated = TimeGenerated
)
on $left.TI_ipEntity == $right.IPAddress
Stage 10: where
where OfficeActivity_TimeGenerated < ExpirationDateTime
Stage 11: summarize
summarize OfficeActivity_TimeGenerated by IndicatorId
Stage 12: project
project ActivityGroupNames, ClientIP, ConfidenceScore, Description, EmailSourceIpAddress, ExpirationDateTime, IndicatorId, NetworkDestinationIP, NetworkIP, NetworkSourceIP, OfficeActivity_TimeGenerated, OfficeObjectId, Operation, RecordType, ResultStatus, TI_ipEntity, ThreatType, Type, Url, UserId
Stage 13: extend
extend Name, UPNSuffix, timestamp
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Active | eq |
| field:"Active" kind:eq value:"true" |
ClientIP | is_not_null | field:"ClientIP" kind:is_not_null | |
EmailSourceIpAddress | is_not_null | field:"EmailSourceIpAddress" kind:is_not_null | |
NetworkDestinationIP | is_not_null | field:"NetworkDestinationIP" kind:is_not_null | |
NetworkIP | is_not_null | field:"NetworkIP" kind:is_not_null | |
NetworkSourceIP | is_not_null | field:"NetworkSourceIP" kind:is_not_null | |
SourceSystem | eq |
| field:"SourceSystem" kind:eq value:"GreyNoise" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
TI_ipEntity | cidr_match | 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16, 127.0.0.0/8 | excludes:TI_ipEntity |
TI_ipEntity | starts_with | 127. | excludes:TI_ipEntity field:"TI_ipEntity" value:"127." |
TI_ipEntity | starts_with | :: | excludes:TI_ipEntity field:"TI_ipEntity" value:"::" |
TI_ipEntity | starts_with | fe80 | excludes:TI_ipEntity field:"TI_ipEntity" value:"fe80" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ActivityGroupNames | project |
ClientIP | project |
ConfidenceScore | project |
Description | project |
EmailSourceIpAddress | project |
ExpirationDateTime | project |
IndicatorId | project |
NetworkDestinationIP | project |
NetworkIP | project |
NetworkSourceIP | project |
OfficeActivity_TimeGenerated | project |
OfficeObjectId | project |
Operation | project |
RecordType | project |
ResultStatus | project |
TI_ipEntity | project |
ThreatType | project |
Type | project |
Url | project |
UserId | project |
Name | extend |
UPNSuffix | extend |
timestamp | extend |
Hunt for critical credentials on non-TPM enabled devices
#This query searches for devices that does not have a TPM (Trusted Platform Module) enabled but contains critical credentials. The output shows for how many users each non-TPM device has credentials, together with the rules why each user is considered a critical user.
Telemetry Coverage
Rule Body
let no_tpm_devices = (
ExposureGraphNodes
// Get device nodes with their inventory ID
| mv-expand EntityIds
| where EntityIds.type == "DeviceInventoryId"
// Get interesting properties
| extend OnboardingStatus = tostring(parse_json(NodeProperties)["rawData"]["onboardingStatus"]),
TpmSupported = tostring(parse_json(NodeProperties)["rawData"]["tpmData"]["supported"]),
TpmEnabled = tostring(parse_json(NodeProperties)["rawData"]["tpmData"]["enabled"]),
TpmActivated = tostring(parse_json(NodeProperties)["rawData"]["tpmData"]["activated"]),
DeviceName = tostring(parse_json(NodeProperties)["rawData"]["deviceName"]),
DeviceId = tostring(EntityIds.id)
// Search for distinct devices
| distinct NodeId, DeviceName, OnboardingStatus, TpmSupported, TpmEnabled, TpmActivated
// Get device with no TPM enabled
| where TpmSupported != "true" and TpmActivated != "true" and TpmEnabled != "true"
| extend TpmSupported = iff(TpmSupported == "", "unknown", TpmSupported),
TpmActivated = iff(TpmActivated == "", "unknown", TpmActivated),
TpmEnabled = iff(TpmEnabled == "", "unknown", TpmEnabled)
);
let critical_users = toscalar(
// Search for critical users
ExposureGraphNodes
| where NodeLabel == "user"
| extend CriticalityLevel = todynamic(NodeProperties).rawData.criticalityLevel.criticalityLevel
| extend RuleNames = todynamic(NodeProperties).rawData.criticalityLevel.ruleNames
| where CriticalityLevel == 0
| distinct NodeName, NodeId, tostring(CriticalityLevel), tostring(RuleNames)
| summarize make_set(NodeName)
);
// Make graph for max of 3 edges, where we start from a device and end with an user
ExposureGraphEdges
| make-graph SourceNodeId --> TargetNodeId with ExposureGraphNodes on NodeId
| graph-match (SourceNode)-[anyEdge*1..3]->(TargetNode)
where SourceNode.NodeLabel in ("device", "microsoft.compute/virtualmachines") and TargetNode.NodeLabel == "user" and TargetNode.NodeName in ( critical_users )
project SourceNodeName = SourceNode.NodeName,
SourceNodeId = SourceNode.NodeId,
Edges = anyEdge.EdgeLabel,
TargetNodeId = TargetNode.NodeId,
TargetNodeName = TargetNode.NodeName,
TargetNodeLabel = TargetNode.NodeLabel,
TargetCriticalityLevel = TargetNode.NodeProperties.rawData.criticalityLevel.criticalityLevel,
TargetRuleNames = TargetNode.NodeProperties.rawData.criticalityLevel.ruleNames
| distinct SourceNodeId, SourceNodeName, TargetNodeId, TargetNodeName, tostring(TargetCriticalityLevel), tostring(TargetRuleNames)
// Only return devices that does not have a TPM fully enabled
| join kind=inner no_tpm_devices on $left.SourceNodeId == $right.NodeId
// Make JSON of tpm data
| extend TpmState = tostring(bag_pack(
'TpmSupported', TpmSupported,
'TpmEnabled', TpmEnabled,
'TpmActivated', TpmActivated
))
// Make JSON of users data
| extend Json = bag_pack(
'User', TargetNodeName,
'UserCriticalityLevel', TargetCriticalityLevel,
'UserRuleNames', TargetRuleNames
)
// Make list of users per device
| summarize UserList = make_list(Json) by DeviceName, OnboardingStatus, TpmState
// Count amount of exposed users per device
| extend UserCount = array_length(UserList)
| sort by UserCount desc
Stages and Predicates
Let Binding: no_tpm_devices
let no_tpm_devices = (
ExposureGraphNodes
| mv-expand EntityIds
| where EntityIds.type == "DeviceInventoryId"
| extend OnboardingStatus = tostring(parse_json(NodeProperties)["rawData"]["onboardingStatus"]),
TpmSupported = tostring(parse_json(NodeProperties)["rawData"]["tpmData"]["supported"]),
TpmEnabled = tostring(parse_json(NodeProperties)["rawData"]["tpmData"]["enabled"]),
TpmActivated = tostring(parse_json(NodeProperties)["rawData"]["tpmData"]["activated"]),
DeviceName = tostring(parse_json(NodeProperties)["rawData"]["deviceName"]),
DeviceId = tostring(EntityIds.id)
| distinct NodeId, DeviceName, OnboardingStatus, TpmSupported, TpmEnabled, TpmActivated
| where TpmSupported != "true" and TpmActivated != "true" and TpmEnabled != "true"
| extend TpmSupported = iff(TpmSupported == "", "unknown", TpmSupported),
TpmActivated = iff(TpmActivated == "", "unknown", TpmActivated),
TpmEnabled = iff(TpmEnabled == "", "unknown", TpmEnabled)
);
Let Binding: critical_users
let critical_users = toscalar(
ExposureGraphNodes
| where NodeLabel == "user"
| extend CriticalityLevel = todynamic(NodeProperties).rawData.criticalityLevel.criticalityLevel
| extend RuleNames = todynamic(NodeProperties).rawData.criticalityLevel.ruleNames
| where CriticalityLevel == 0
| distinct NodeName, NodeId, tostring(CriticalityLevel), tostring(RuleNames)
| summarize make_set(NodeName)
);
Stage 1: source
let no_tpm_devices
Stage 2: source
ExposureGraphEdges
Stage 3: macro
macro
Stage 4: macro
macro
Stage 5: distinct
distinct SourceNodeId, SourceNodeName, TargetNodeId, TargetNodeName
Stage 6: join
join kind=inner (no_tpm_devices) on $left.SourceNodeId, $right.NodeId
Stage 7: extend
extend TpmState
Stage 8: extend
extend Json
Stage 9: summarize
summarize UserList by DeviceName, OnboardingStatus, TpmState
Stage 10: extend
extend UserCount
Stage 11: sort
sort by UserCount
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EntityIds.type | eq |
| field:"EntityIds.type" kind:eq value:"DeviceInventoryId" |
TpmActivated | ne |
| field:"TpmActivated" kind:ne value:"true" |
TpmEnabled | ne |
| field:"TpmEnabled" kind:ne value:"true" |
TpmSupported | ne |
| field:"TpmSupported" kind:ne value:"true" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DeviceName | summarize |
OnboardingStatus | summarize |
TpmState | summarize |
UserList | summarize |
UserCount | extend |
OCI - Event rule deleted
#'Detects when event rule was deleted.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Stealth |
Rule Body
id: 31b15699-0b55-4246-851e-93f9cefb6f5c
name: OCI - Event rule deleted
description: |
'Detects when event rule was deleted.'
severity: High
status: Available
requiredDataConnectors:
- connectorId: OracleCloudInfrastructureLogsConnector
dataTypes:
- OCILogs
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
relevantTechniques:
- T1070
query: |
OCILogs
| where data_eventName_s =~ 'DeleteRule'
| extend IPCustomEntity = SrcIpAddr
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.1
kind: Scheduled
Stages and Predicates
Stage 1: source
OCILogs
Stage 2: where
| where data_eventName_s =~ 'DeleteRule'
Stage 3: extend
| extend IPCustomEntity = SrcIpAddr
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
data_eventName_s | eq |
| field:"data_eventName_s" kind:eq value:"DeleteRule" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
IPCustomEntity | extend |
OMI Vulnerability Exploitation
#Following the September 14th, 2021 release of three Elevation of Privilege (EoP) vulnerabilities (CVE-2021-38645, CVE-2021-38649, CVE-2021-38648) and one unauthenticated Remote Code Execution (RCE) vulnerability (CVE-2021-38647) in the Open Management Infrastructure (OMI) Framework. This detection validates that any OMS-agent that is reporting to the Microsoft Sentinel workspace is updated with the patch. The detection will go over the heartbeats received from all agents over the last day and will create alert for those agents who are not updated.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: 3cc5ccd8-b416-4141-bb2d-4eba370e37a5
name: OMI Vulnerability Exploitation
description: |
Following the September 14th, 2021 release of three Elevation of Privilege (EoP) vulnerabilities (CVE-2021-38645, CVE-2021-38649, CVE-2021-38648) and one unauthenticated Remote Code Execution (RCE) vulnerability (CVE-2021-38647) in the Open Management Infrastructure (OMI) Framework.
This detection validates that any OMS-agent that is reporting to the Microsoft Sentinel workspace is updated with the patch. The detection will go over the heartbeats received from all agents over the last day and will create alert for those agents who are not updated.
requiredDataConnectors: []
severity: Medium
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1190
tags:
- OMIGOD
- CVE-2021-38647
query: |
let OMIVulnerabilityPatchVersion = "OMIVulnerabilityPatchVersion:1.13.40-0";
Heartbeat
| where Category == "Direct Agent"
| summarize arg_max(TimeGenerated,*) by Computer
| parse strcat("Version:" , Version) with * "Version:" Major:long "."
Minor:long "." Patch:long "-" *
| parse OMIVulnerabilityPatchVersion with * "OMIVulnerabilityPatchVersion:"
OMIVersionMajor:long "." OMIVersionMinor:long "." OMIVersionPatch:long "-" *
| where Major <OMIVersionMajor or (Major==OMIVersionMajor and Minor
<OMIVersionMinor) or (Major==OMIVersionMajor and Minor==OMIVersionMinor and
Patch<OMIVersionPatch)
| project Version, Major,Minor,Patch,
Computer,ComputerIP,OSType,OSName,ResourceId
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: Computer
- entityType: AzureResource
fieldMappings:
- identifier: ResourceId
columnName: ResourceId
customDetails:
HostIp: ComputerIP
OSType: OSType
OSName: OSName
kind: Scheduled
version: 1.1.5
metadata:
source:
kind: Community
author:
name: Ron Marsiano
support:
tier: Community
categories:
domains: [ "Security - Vulnerability Management" ]
Stages and Predicates
Parameters
let OMIVulnerabilityPatchVersion = "OMIVulnerabilityPatchVersion:1.13.40-0";
Stage 1: source
Heartbeat
Stage 2: where
| where Category == "Direct Agent"
Stage 3: summarize
| summarize arg_max(TimeGenerated,*) by Computer
Stage 4: parse
| parse strcat("Version:" , Version) with * "Version:" Major:long "."
Minor:long "." Patch:long "-" *
Stage 5: parse
| parse OMIVulnerabilityPatchVersion with * "OMIVulnerabilityPatchVersion:"
OMIVersionMajor:long "." OMIVersionMinor:long "." OMIVersionPatch:long "-" *
Stage 6: where
| where Major <OMIVersionMajor or (Major==OMIVersionMajor and Minor
<OMIVersionMinor) or (Major==OMIVersionMajor and Minor==OMIVersionMinor and
Patch<OMIVersionPatch)
Stage 7: project
| project Version, Major,Minor,Patch,
Computer,ComputerIP,OSType,OSName,ResourceId
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Category | eq |
| field:"Category" kind:eq value:"Direct Agent" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Computer | project |
ComputerIP | project |
Major | project |
Minor | project |
OSName | project |
OSType | project |
Patch | project |
ResourceId | project |
Version | project |
Pathlock TDnR - Database Cockpit Audit Events
#Detects security-relevant events from the SAP Database Administration Cockpit (DBACOCKPIT), forwarded by Pathlock Threat Detection and Response. Suspicious DBACOCKPIT activity may indicate unauthorized direct database access, privilege escalation, or attempts to bypass SAP application controls.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Privilege Escalation | |
| Discovery |
Rule Body
id: 2a3b4c5d-6e7f-4a0b-8c1d-2e3f4a5b6c23
name: Pathlock TDnR - Database Cockpit Audit Events
kind: Scheduled
description: >-
Detects security-relevant events from the SAP Database Administration Cockpit (DBACOCKPIT),
forwarded by Pathlock Threat Detection and Response. Suspicious DBACOCKPIT activity may indicate
unauthorized direct database access, privilege escalation, or attempts to bypass SAP application controls.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: Pathlock_TDnR
dataTypes:
- Pathlock_TDnR_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Discovery
- PrivilegeEscalation
relevantTechniques:
- T1082
- T1548
query: |
Pathlock_TDnR_CL
| where DataSource == "DBACOCKPIT"
| 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 == "DBACOCKPIT"
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:"DBACOCKPIT" |
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 |
Recorded Future Sandbox - Malicious File in Storage Account
#'Creates incidents when Recorded Future Sandbox detects malicious files from Azure Storage Account'
Rule Body
id: a1b2c3d4-5678-90ab-cdef-333333333333
name: Recorded Future Sandbox - Malicious File in Storage Account
description: |
'Creates incidents when Recorded Future Sandbox detects malicious files from Azure Storage Account'
severity: Medium
status: Available
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics: []
relevantTechniques: []
query: |
RecordedFutureSandboxResults_CL
| where TimeGenerated >= now(-1h)
| where Source_s == "StorageAccount"
| where toint(SandboxScore_s) >= 50
eventGroupingSettings:
aggregationKind: AlertPerResult
alertDetailsOverride:
alertDisplayNameFormat: 'Malicious File in Storage: {{FileName_s}}'
alertDescriptionFormat: |
_Recorded Future Sandbox - Malicious File in Storage Account_
**Sandbox Score:** {{SandboxScore_s}}/100
**Verdict:** {{SandboxVerdict_s}}
**Sample ID:** {{SampleId_s}}
A malicious file was detected in an Azure Storage Account. Investigate the source of this file and review the full sandbox report.
customDetails:
RFLabel: SourceSystem
Source: Source_s
SandboxScore: SandboxScore_s
SandboxVerdict: SandboxVerdict_s
FileName: FileName_s
SampleId: SampleId_s
entityMappings:
- entityType: File
fieldMappings:
- identifier: Name
columnName: FileName_s
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: 1h
matchingMethod: Selected
groupByCustomDetails:
- SandboxVerdict
version: 1.0.0
kind: NRT
Stages and Predicates
Stage 1: source
RecordedFutureSandboxResults_CL
Stage 2: where
| where TimeGenerated >= now(-1h)
Stage 3: where
| where Source_s == "StorageAccount"
Stage 4: where
| where toint(SandboxScore_s) >= 50
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
SandboxScore_s | ge |
| field:"SandboxScore_s" kind:ge value:"50" |
Source_s | eq |
| field:"Source_s" kind:eq value:"StorageAccount" |
Sonrai Ticket Assigned
#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.
'Checks if Sonrai tickets have been assigned. It uses the action type to check if a ticket has been assigned'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Execution | |
| Persistence | |
| Privilege Escalation | |
| Defense Impairment | |
| Credential Access | |
| Discovery | |
| Lateral Movement | |
| Collection | |
| Command & Control | |
| Exfiltration | |
| Impact |
Rule Body
id: 37a8d052-a3db-4dc6-9dca-9390cac6f486
name: Sonrai Ticket Assigned
description: |
'Checks if Sonrai tickets have been assigned.
It uses the action type to check if a ticket has been assigned'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: SonraiDataConnector
dataTypes:
- Sonrai_Tickets_CL
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
tactics:
- Collection
- CommandAndControl
- CredentialAccess
- DefenseEvasion
- Discovery
- Execution
- Exfiltration
- Impact
- InitialAccess
- LateralMovement
- Persistence
- PrivilegeEscalation
relevantTechniques:
- T1566
- T1059
- T1547
- T1548
- T1562
- T1003
- T1087
- T1021
- T1119
- T1071
- T1041
- T1499
query: |
Sonrai_Tickets_CL
| where action_d == 4
entityMappings:
- entityType: CloudApplication
fieldMappings:
- identifier: Name
columnName: digest_criticalResourceName_s
eventGroupingSettings:
aggregationKind: AlertPerResult
customDetails:
ticketName: digest_title_s
ticketStatus: digest_status_s
ticketSeverity: digest_severityCategory_s
resourceLabel: digest_resourceLabel_s
resourceType: digest_resourceType_s
criticalResource: digest_criticalResourceName_s
ticketOrg: digest_org_s
assignedTo: digest_assignedTo_s
alertDetailsOverride:
alertSeverityColumnName: digest_severityCategory_s
alertDisplayNameFormat: Assigned - {{digest_ticketSrn_s}} - {{digest_ticketKeyName_s}}
alertDescriptionFormat: digest_ticketKeyDescription_s
version: 1.0.2
kind: Scheduled
Stages and Predicates
Stage 1: source
Sonrai_Tickets_CL
Stage 2: where
| where action_d == 4
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
action_d | eq |
| field:"action_d" kind:eq value:"4" |
TI map IP entity to Workday(ASimAuditEventLogs)
#Detects a match in Workday activity from any IP Indicator of Compromise (IOC) provided by Threat Intelligence (TI).
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Command & Control |
Rule Body
id: a924d317-03d2-4420-a71f-4d347bda4bd8
name: TI map IP entity to Workday(ASimAuditEventLogs)
description: |
Detects a match in Workday activity from any IP Indicator of Compromise (IOC) provided by Threat Intelligence (TI).
severity: Medium
requiredDataConnectors:
- connectorId: ThreatIntelligence
dataTypes:
- ThreatIntelligenceIndicator
- connectorId: ThreatIntelligenceTaxii
dataTypes:
- ThreatIntelligenceIndicator
- connectorId: Workday
dataTypes:
- Workday
- connectorId: MicrosoftDefenderThreatIntelligence
dataTypes:
- ThreatIntelligenceIndicator
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandAndControl
relevantTechniques:
- T1071
query: |
let dtLookBack = 1h; // Define the lookback period for audit events
let ioc_lookBack = 14d; // Define the lookback period for threat intelligence indicators
ThreatIntelligenceIndicator
| where TimeGenerated >= ago(ioc_lookBack) // Filter threat intelligence indicators within the lookback period
| where isnotempty(NetworkIP)
or isnotempty(EmailSourceIpAddress)
or isnotempty(NetworkDestinationIP)
or isnotempty(NetworkSourceIP) // Filter for indicators with relevant IP fields
| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId // Get the latest indicator time for each IndicatorId
| extend TI_ipEntity = coalesce(NetworkIP, NetworkDestinationIP, NetworkSourceIP, EmailSourceIpAddress) // Combine IP fields into a single entity
| where Active == true and ExpirationDateTime > now() // Filter for active indicators that have not expired
| join kind=inner (
ASimAuditEventLogs
| where EventVendor == "Workday" // Filter for Workday events
| where TimeGenerated >= ago(dtLookBack) // Filter events within the lookback period
| where isnotempty(DvcIpAddr) // Filter for events with a device IP address
| extend WD_TimeGenerated = EventStartTime // Rename the event start time column
| project WD_TimeGenerated, ActorUsername, DvcIpAddr, Operation, Object // Select relevant columns
)
on $left.TI_ipEntity == $right.DvcIpAddr // Join on the IP entity
| project
LatestIndicatorTime,
Description,
ActivityGroupNames,
IndicatorId,
ThreatType,
Url,
ExpirationDateTime,
ConfidenceScore,
WD_TimeGenerated,
ActorUsername,
DvcIpAddr,
Operation,
Object // Select relevant columns after the join
| extend
timestamp = WD_TimeGenerated,
Name = tostring(split(ActorUsername, '@', 0)),
UPNSuffix = tostring(split(ActorUsername, '@', 1)) // Add additional fields for timestamp, name, and UPN suffix
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: ActorUsername
- identifier: Name
columnName: Name
- identifier: UPNSuffix
columnName: UPNSuffix
- entityType: IP
fieldMappings:
- identifier: Address
columnName: DvcIpAddr
version: 1.0.0
kind: Scheduled
Stages and Predicates
Parameters
let dtLookBack = 1h;
let ioc_lookBack = 14d;
Stage 1: source
ThreatIntelligenceIndicator
Stage 2: where
| where TimeGenerated >= ago(ioc_lookBack)
Stage 3: where
| where isnotempty(NetworkIP)
or isnotempty(EmailSourceIpAddress)
or isnotempty(NetworkDestinationIP)
or isnotempty(NetworkSourceIP)
Stage 4: summarize
| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
Stage 5: extend
| extend TI_ipEntity = coalesce(NetworkIP, NetworkDestinationIP, NetworkSourceIP, EmailSourceIpAddress)
Stage 6: where
| where Active == true and ExpirationDateTime > now()
Stage 7: join
| join kind=inner (
ASimAuditEventLogs
| where EventVendor == "Workday"
| where TimeGenerated >= ago(dtLookBack)
| where isnotempty(DvcIpAddr)
| extend WD_TimeGenerated = EventStartTime
| project WD_TimeGenerated, ActorUsername, DvcIpAddr, Operation, Object
)
on $left.TI_ipEntity == $right.DvcIpAddr
Stage 8: project
project ActivityGroupNames, ActorUsername, ConfidenceScore, Description, DvcIpAddr, ExpirationDateTime, IndicatorId, LatestIndicatorTime, Object, Operation, ThreatType, Url, WD_TimeGenerated
Stage 9: extend
extend Name, UPNSuffix, timestamp
Indicators
These rows show field, operator, and value matches.
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ActivityGroupNames | project |
ActorUsername | project |
ConfidenceScore | project |
Description | project |
DvcIpAddr | project |
ExpirationDateTime | project |
IndicatorId | project |
LatestIndicatorTime | project |
Object | project |
Operation | project |
ThreatType | project |
Url | project |
WD_TimeGenerated | project |
Name | extend |
UPNSuffix | extend |
timestamp | extend |
Trend Micro CAS - Ransomware outbreak
#'Triggeres when ransomware was detected on several accounts.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Impact |
Rule Body
id: 38e043ce-a1fd-497b-8d4f-ce5ca2db90cd
name: Trend Micro CAS - Ransomware outbreak
description: |
'Triggeres when ransomware was detected on several accounts.'
severity: High
status: Available
requiredDataConnectors:
- connectorId: TrendMicroCAS
dataTypes:
- TrendMicroCAS
queryFrequency: 10m
queryPeriod: 10m
triggerOperator: gt
triggerThreshold: 0
tactics:
- Impact
relevantTechniques:
- T1486
query: |
TrendMicroCAS
| where EventType =~ 'ransomware'
| summarize count() by DstUserName, bin(TimeGenerated, 2m)
| where count_ >= 2
| extend AccountCustomEntity = DstUserName
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountCustomEntity
version: 1.0.1
kind: Scheduled
Stages and Predicates
Stage 1: source
TrendMicroCAS
Stage 2: where
| where EventType =~ 'ransomware'
Stage 3: summarize
| summarize count() by DstUserName, bin(TimeGenerated, 2m)
Stage 4: where
| where count_ >= 2
Stage 5: extend
| extend AccountCustomEntity = DstUserName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventType | eq |
| field:"EventType" kind:eq value:"ransomware" |
count_ | ge |
| field:"count_" kind:ge value:"2" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DstUserName | summarize |
AccountCustomEntity | extend |
TrendAI Vision One - Create Incident for Workbench Alerts
#Creates an incident based on TrendAI Vision One Workbench Alerts and maps the impacted entities for Microsoft Sentinel usage.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Execution | |
| Persistence | |
| Privilege Escalation | |
| Stealth |
Rule Body
id: 2f668615-c372-4673-a5cd-773e4da715b9
name: TrendAI Vision One - Create Incident for Workbench Alerts
description: |
Creates an incident based on TrendAI Vision One Workbench Alerts and maps the impacted entities for Microsoft Sentinel usage.
severity: High
status: Available
requiredDataConnectors:
- connectorId: TrendAIVisionOneWorkbench
dataTypes:
- TrendAI_XDR_WORKBENCH_V2_CL
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
- Execution
- Persistence
- PrivilegeEscalation
- DefenseEvasion
- CredentialAccess
- Discovery
- LateralMovement
- Collection
- Exfiltration
- CommandAndControl
- Impact
relevantTechniques:
- T1059
- T1566
- T1078
- T1055
suppressionDuration: 5h
suppressionEnabled: false
query: |
TrendAI_XDR_WORKBENCH_V2_CL
| extend Severity = case(severity_s == "low", "Informational",
severity_s == "medium", "Low",
severity_s == "high", "Medium",
"High"
)
| extend
UserAccountName_s = todynamic(column_ifexists("UserAccountName_s", "[]")),
UserAccountNTDomain_s = todynamic(column_ifexists("UserAccountNTDomain_s", "[]")),
FileName_s = todynamic(column_ifexists("FileName_s", "[]")),
FileDirectory_s = todynamic(column_ifexists("FileDirectory_s", "[]")),
ProcessCommandLine_s = todynamic(column_ifexists("ProcessCommandLine_s", "[]")),
RegistryKey_s = todynamic(column_ifexists("RegistryKey_s", "[]")),
RegistryValue_s = todynamic(column_ifexists("RegistryValue_s", "[]")),
RegistryValueName_s = todynamic(column_ifexists("RegistryValueName_s", "[]"))
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: 5m
matchingMethod: Selected
groupByCustomDetails:
- WorkbenchID
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: UserAccountName_s
- identifier: NTDomain
columnName: UserAccountNTDomain_s
- entityType: File
fieldMappings:
- identifier: Name
columnName: FileName_s
- identifier: Directory
columnName: FileDirectory_s
- entityType: Process
fieldMappings:
- identifier: CommandLine
columnName: ProcessCommandLine_s
- entityType: RegistryKey
fieldMappings:
- identifier: Key
columnName: RegistryKey_s
- entityType: RegistryValue
fieldMappings:
- identifier: Name
columnName: RegistryValueName_s
- identifier: Value
columnName: RegistryValue_s
alertDetailsOverride:
alertDisplayNameFormat: '{{workbenchName_s}}'
alertDescriptionFormat: '{{description_s}}'
alertSeverityColumnName: Severity
customDetails:
XDRCustomerID: xdrCustomerID_g
WorkbenchID: workbenchId_s
WorkbenchName: workbenchName_s
WorkbenchLink: workbenchLink_s
PriorityScore: priorityScore_d
CreatedAt: createdTime_t
Severity: severity_s
ImpactScopeSummary: impactScope_Summary_s
Provider: alertProvider_s
eventGroupingSettings:
aggregationKind: AlertPerResult
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
TrendAI_XDR_WORKBENCH_V2_CL
Stage 2: extend
| extend Severity = case(severity_s == "low", "Informational",
severity_s == "medium", "Low",
severity_s == "high", "Medium",
"High"
)
Severity =severity_s == "low""Informational"severity_s == "medium""Low"severity_s == "high""Medium""High"Stage 3: extend
| extend
UserAccountName_s = todynamic(column_ifexists("UserAccountName_s", "[]")),
UserAccountNTDomain_s = todynamic(column_ifexists("UserAccountNTDomain_s", "[]")),
FileName_s = todynamic(column_ifexists("FileName_s", "[]")),
FileDirectory_s = todynamic(column_ifexists("FileDirectory_s", "[]")),
ProcessCommandLine_s = todynamic(column_ifexists("ProcessCommandLine_s", "[]")),
RegistryKey_s = todynamic(column_ifexists("RegistryKey_s", "[]")),
RegistryValue_s = todynamic(column_ifexists("RegistryValue_s", "[]")),
RegistryValueName_s = todynamic(column_ifexists("RegistryValueName_s", "[]"))
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Severity | extend |
FileDirectory_s | extend |
FileName_s | extend |
ProcessCommandLine_s | extend |
RegistryKey_s | extend |
RegistryValueName_s | extend |
RegistryValue_s | extend |
UserAccountNTDomain_s | extend |
UserAccountName_s | extend |
Vaikora - Engine offline
#Identifies a Vaikora for O365 engine outage by absent quarantine telemetry. Fires when a tenant active in the last 24 hours has sent no rows in the last two hours, indicating the customer VM is unhealthy or the Graph subscription has lapsed.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Defense Impairment |
Rule Body
id: 968b70c1-b468-418a-ac02-1eb74783a52a
name: Vaikora - Engine offline
description: |
Identifies a Vaikora for O365 engine outage by absent quarantine telemetry. Fires when a tenant active in the last 24 hours has sent no rows in the last two hours, indicating the customer VM is unhealthy or the Graph subscription has lapsed.
severity: Medium
requiredDataConnectors:
- connectorId: VaikoraO365
dataTypes:
- VaikoraO365_Quarantine_CL
queryFrequency: 30m
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
- DefenseEvasion
relevantTechniques:
- T1562
query: |
let recentTenants = toscalar(
VaikoraO365_Quarantine_CL
| where TimeGenerated >= ago(2h)
| summarize make_set(TenantId_s)
);
VaikoraO365_Quarantine_CL
| where TimeGenerated between (ago(1d) .. ago(2h))
| summarize LastSeen = max(TimeGenerated) by TenantId_s
| where TenantId_s !in (recentTenants)
| project TimeGenerated = now(), TenantId = TenantId_s, LastSeen, HoursOffline = (now() - LastSeen) / 1h
entityMappings:
- entityType: CloudApplication
fieldMappings:
- identifier: Name
columnName: TenantId
alertDetailsOverride:
alertDisplayNameFormat: "Vaikora-O365 engine offline for tenant {{TenantId}}"
alertDescriptionFormat: "No Vaikora-O365 quarantine telemetry has arrived from this tenant in the last 2 hours. Last seen: {{LastSeen}}."
version: 1.0.0
kind: Scheduled
Stages and Predicates
Let Binding: recentTenants
let recentTenants = toscalar(
VaikoraO365_Quarantine_CL
| where TimeGenerated >= ago(2h)
| summarize make_set(TenantId_s)
);
Stage 1: source
VaikoraO365_Quarantine_CL
Stage 2: where
| where TimeGenerated between (ago(1d) .. ago(2h))
Stage 3: summarize
| summarize LastSeen = max(TimeGenerated) by TenantId_s
Stage 4: where
| where TenantId_s !in (recentTenants)
Stage 5: project
| project TimeGenerated = now(), TenantId = TenantId_s, LastSeen, HoursOffline = (now() - LastSeen) / 1h
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
TenantId_s | eq | recentTenants | excludes:TenantId_s field:"TenantId_s" value:"recentTenants" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
HoursOffline | project |
LastSeen | project |
TenantId | project |
TimeGenerated | project |
Vectra Create Incident Based on Priority for Accounts
#Create an incident when an identity is suspected to be compromised. Vectra is using AI to prioritize an entity based on multiple factors (attack rating, velocity, breadth, importance.etc.). This layer of aggregation at the entity level provides a greater signal-to-noise ratio and help analyst focus on what matters.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Persistence |
Rule Body
id: af6f2812-0187-4cc9-822a-952f8b5b6b7e
name: Vectra Create Incident Based on Priority for Accounts
version: 1.1.1
kind: Scheduled
description: Create an incident when an identity is suspected to be compromised. Vectra is using AI to prioritize an entity based on multiple factors (attack rating, velocity, breadth, importance.etc.). This layer of aggregation at the entity level provides a greater signal-to-noise ratio and help analyst focus on what matters.
status: Available
requiredDataConnectors:
- connectorId: VectraXDR
dataTypes:
- Entities_Data_CL
severity: Medium
queryFrequency: 10m
queryPeriod: 10m
suppressionDuration: PT1H
suppressionEnabled: false
triggerOperator: GreaterThan
triggerThreshold: 0
tactics:
- Persistence
relevantTechniques:
- T1546
query: |
Entities_Data_CL
| where entity_type == "account" and is_prioritized == true
| summarize arg_max(['last_modified_timestamp'], *) by ['name']
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: name
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: true
lookbackDuration: P7D
matchingMethod: AllEntities
customDetails:
entity_id: id
tags: tags
entity_type: entity_type
attack_profile: attack_profile
ip_address: ip
alertDetailsOverride:
alertDisplayNameFormat: "Vectra AI Incident- {{name}}"
alertDescriptionFormat: An incident has been generated for Vectra AI entity {{name}} that is presenting an urgency score of {{urgency_score}}.
alertDynamicProperties:
- alertProperty: AlertLink
value: url
eventGroupingSettings:
aggregationKind: AlertPerResult
Stages and Predicates
Stage 1: source
Entities_Data_CL
Stage 2: where
| where entity_type == "account" and is_prioritized == true
Stage 3: summarize
| summarize arg_max(['last_modified_timestamp'], *) by ['name']
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
entity_type | eq |
| field:"entity_type" kind:eq value:"account" |
is_prioritized | eq |
| field:"is_prioritized" kind:eq value:"true" |
Vulnerable Machines related to log4j CVE-2021-44228
#'This query uses the Azure Defender Security Nested Recommendations data to find machines vulnerable to log4j CVE-2021-44228. Log4j is an open-source Apache logging library that is used in many Java-based applications. Security Nested Recommendations data is sent to Microsoft Sentinel using the continuous export feature of Azure Defender(refrence link below). Reference: https://msrc-blog.microsoft.com/2021/12/11/microsofts-response-to-cve-2021-44228-apache-log4j2/ Reference: https://docs.microsoft.com/azure/security-center/continuous-export?tabs=azure-portal Reference: https://techcommunity.microsoft.com/t5/microsoft-defender-for-cloud/how-defender-for-cloud-displays-machines-affected-by-log4j/ba-p/3037271'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Execution |
Rule Body
id: 3d71fc38-f249-454e-8479-0a358382ef9a
name: Vulnerable Machines related to log4j CVE-2021-44228
description: |
'This query uses the Azure Defender Security Nested Recommendations data to find machines vulnerable to log4j CVE-2021-44228.
Log4j is an open-source Apache logging library that is used in many Java-based applications. Security Nested Recommendations data is sent to Microsoft Sentinel using the continuous export feature of Azure Defender(refrence link below).
Reference: https://msrc-blog.microsoft.com/2021/12/11/microsofts-response-to-cve-2021-44228-apache-log4j2/
Reference: https://docs.microsoft.com/azure/security-center/continuous-export?tabs=azure-portal
Reference: https://techcommunity.microsoft.com/t5/microsoft-defender-for-cloud/how-defender-for-cloud-displays-machines-affected-by-log4j/ba-p/3037271'
severity: High
status: Available
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
- Execution
relevantTechniques:
- T1190
- T1203
tags:
- Log4j
- CVE-2021-44228
- Log4shell
query: |
SecurityNestedRecommendation
| where RemediationDescription has 'CVE-2021-44228'
| parse ResourceDetails with * 'virtualMachines/' VirtualMachine '"' *
| summarize arg_min(TimeGenerated, *) by TenantId, RecommendationSubscriptionId, VirtualMachine, RecommendationName,Description,RemediationDescription, tostring(AdditionalData),VulnerabilityId
| extend Timestamp = TimeGenerated
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: VirtualMachine
version: 1.0.3
kind: Scheduled
Stages and Predicates
Stage 1: source
SecurityNestedRecommendation
Stage 2: where
| where RemediationDescription has 'CVE-2021-44228'
Stage 3: parse
| parse ResourceDetails with * 'virtualMachines/' VirtualMachine '"' *
Stage 4: summarize
| summarize arg_min(TimeGenerated, *) by TenantId, RecommendationSubscriptionId, VirtualMachine, RecommendationName,Description,RemediationDescription, tostring(AdditionalData),VulnerabilityId
Stage 5: extend
| extend Timestamp = TimeGenerated
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
RemediationDescription | match |
| field:"RemediationDescription" kind:match value:"CVE-2021-44228" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Description | summarize |
RecommendationName | summarize |
RecommendationSubscriptionId | summarize |
RemediationDescription | summarize |
TenantId | summarize |
VirtualMachine | summarize |
VulnerabilityId | summarize |
Timestamp | extend |
Zscaler - ZPA connections outside operational hours
#'Detects ZAP connections outside operational hours.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: 2859ad22-46c8-4cc7-ad7b-80ce0cba0af3
name: Zscaler - ZPA connections outside operational hours
description: |
'Detects ZAP connections outside operational hours.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: CustomLogsAma
datatypes:
- ZPA_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1190
- T1133
query: |
ZPAEvent
| where DvcAction == 'open'
| where datetime_part("Hour", todatetime(LogTimestamp)) between (datetime_part("Hour", todatetime('19:01:00.7654321')) .. datetime_part("Hour", todatetime('08:01:00.7654321')))
| summarize count() by DstUserName
| project DstUserName
| extend AccountCustomEntity = DstUserName
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountCustomEntity
version: 1.0.2
kind: Scheduled
Stages and Predicates
Stage 1: source
ZPAEvent
Stage 2: where
| where DvcAction == 'open'
Stage 3: where
| where datetime_part("Hour", todatetime(LogTimestamp)) between (datetime_part("Hour", todatetime('19:01:00.7654321')) .. datetime_part("Hour", todatetime('08:01:00.7654321')))
Stage 4: summarize
| summarize count() by DstUserName
Stage 5: project
| project DstUserName
Stage 6: extend
| extend AccountCustomEntity = DstUserName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
DvcAction | eq |
| field:"DvcAction" kind:eq value:"open" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DstUserName | project |
AccountCustomEntity | extend |