Detection rules › Kusto

Kusto rules: 31

App Gateway WAF - SQLi Detection

#
Status
available
Severity
high
Time window
6h
Group by
Action, ClientIp, TransactionId, Uri
Source
github.com/Azure/Azure-Sentinel

'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

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.

Output Fields

These fields are emitted when the rule matches.

FieldSource
Actionsummarize
ClientIpsummarize
EndTimesummarize
Messagesummarize
StartTimesummarize
Total_TransactionIdsummarize
TransactionIDsummarize
Urisummarize

Attempt to Delete Backup Failed

#
Status
available
Severity
high
Time window
5m
Source
github.com/Azure/Azure-Sentinel

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.

Output Fields

These fields are emitted when the rule matches.

FieldSource
DataSourceproject
Dateproject
Endpointproject
EventIdproject
MessageDetailsproject
Severityproject
User Nameproject

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.

Status
available
Severity
medium
Time window
1h
Source
github.com/Azure/Azure-Sentinel

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.

FieldKindValuesSearch
Findingeq
  • T0WriteDACL
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.

Status
available
Severity
low
Time window
5h
Source
github.com/Azure/Azure-Sentinel

'Display incidents in which low sensitivity business information] was placed at risk by user sharing.'

MITRE ATT&CK Coverage

TacticTechniques
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.

Output Fields

These fields are emitted when the rule matches.

FieldSource
AccountCustomEntityextend

Contrast Blocks

#
Status
available
Severity
low
Time window
5m
Source
github.com/Azure/Azure-Sentinel

'Creates Incidents for Blocked events sourced from the Contrast Protect agent.'

MITRE ATT&CK Coverage

TacticTechniques
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 used in Stage 4

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.

Output Fields

These fields are emitted when the rule matches.

FieldSource
DeviceProductextend
SourceIPextend
DeviceVersionextend
Activityextend
ApplicationProtocolextend
RequestURLextend
RequestMethodextend
Ruleextend

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.

Severity
medium
Time window
5m
Source
github.com/Azure/Azure-Sentinel

"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

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.

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
patterncontainsfile:hashesexcludes:pattern field:"pattern" value:"file:hashes"

Output Fields

These fields are emitted when the rule matches.

FieldSource
ConfidenceScoreproject
Countryproject
Descriptionproject
Domainproject
IPAbuseproject
IPv4project
IPv6project
IndicatorIDproject
ProductNameproject
ProviderNameproject
RecommendedActionsproject
Rolesproject
SecurityVendorsproject
Sourcesproject
Tagsproject
ThreatActorsproject
ThreatTypeproject
TimeGeneratedproject
URLproject
createdproject
modifiedproject
nameproject
valid_fromproject

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.

Status
available
Severity
medium
Time window
5m
Source
github.com/Azure/Azure-Sentinel

"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

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.

Output Fields

These fields are emitted when the rule matches.

FieldSource
AlertTitleproject
AlertUIDproject
AssetTypeproject
AssetValueproject
Descriptionproject
FirstSeenproject
Impactproject
LastSeenproject
PostedDateproject
ProductNameproject
ProviderNameproject
Recommendationproject
RiskScoreproject
Sourceproject
TimeGeneratedproject
UIDproject

Cynerio - Exploitation Attempt of IoT device

#
Severity
high
Time window
5h
Source
github.com/Azure/Azure-Sentinel

Exploitation Attempt of IoT device - Attack detection

MITRE ATT&CK Coverage

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.

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.

Status
available
Severity
medium
Time window
1h
Source
github.com/Azure/Azure-Sentinel

'This query searches for infected device events on Darkweb or Telegram.'

MITRE ATT&CK Coverage

TacticTechniques
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.

FieldKindValuesSearch
RiskScorege
  • 3 transforms: number
field:"RiskScore" kind:ge value:"3"
index_namein
  • bot
  • stealer_log
field:"index_name" kind:in
uidis_not_null
  • (no value, null check)
field:"uid" kind:is_not_null

Output Fields

These fields are emitted when the rule matches.

FieldSource
index_nameextend

Google DNS - Multiple errors to same domain

#
Severity
medium
Time window
10m
Group by
Query
Source
github.com/Azure/Azure-Sentinel

'Detects multiple errors to same domain.'

MITRE ATT&CK Coverage

TacticTechniques
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.

FieldKindValuesSearch
EventResultDetailsin
  • NXDOMAIN
  • REFUSED
  • SERVFAIL
field:"EventResultDetails" kind:in

Output Fields

These fields are emitted when the rule matches.

FieldSource
Querysummarize
ipssummarize
DNSCustomEntityextend
IPCustomEntityextend

GreyNoise TI map IP entity to OfficeActivity

#
Severity
medium
Time window
14d
Group by
$left.TI_ipEntity, $right.IPAddress, IndicatorId
Source
github.com/Azure/Azure-Sentinel

This query maps any GreyNoise IP indicators of compromise (IOCs) from threat intelligence (TI), by searching for matches in OfficeActivity.

MITRE ATT&CK Coverage

TacticTechniques
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 =
ifisnotempty(NetworkIP)NetworkIP
elseNetworkDestinationIP

Stage 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.

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
TI_ipEntitycidr_match10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16, 127.0.0.0/8excludes:TI_ipEntity
TI_ipEntitystarts_with127.excludes:TI_ipEntity field:"TI_ipEntity" value:"127."
TI_ipEntitystarts_with::excludes:TI_ipEntity field:"TI_ipEntity" value:"::"
TI_ipEntitystarts_withfe80excludes:TI_ipEntity field:"TI_ipEntity" value:"fe80"

Output Fields

These fields are emitted when the rule matches.

FieldSource
ActivityGroupNamesproject
ClientIPproject
ConfidenceScoreproject
Descriptionproject
EmailSourceIpAddressproject
ExpirationDateTimeproject
IndicatorIdproject
NetworkDestinationIPproject
NetworkIPproject
NetworkSourceIPproject
OfficeActivity_TimeGeneratedproject
OfficeObjectIdproject
Operationproject
RecordTypeproject
ResultStatusproject
TI_ipEntityproject
ThreatTypeproject
Typeproject
Urlproject
UserIdproject
Nameextend
UPNSuffixextend
timestampextend

Hunt for critical credentials on non-TPM enabled devices

#
Group by
$left.SourceNodeId, $right.NodeId, DeviceName, OnboardingStatus, TpmState
Author
Robbe Van den Daele
Source
github.com/HybridBrothers/Hunting-Queries-Detection-Rules

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 used in Stages 1, 6

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.

Output Fields

These fields are emitted when the rule matches.

FieldSource
DeviceNamesummarize
OnboardingStatussummarize
TpmStatesummarize
UserListsummarize
UserCountextend

OCI - Event rule deleted

#
Status
available
Severity
high
Time window
1h
Source
github.com/Azure/Azure-Sentinel

'Detects when event rule was deleted.'

MITRE ATT&CK Coverage

TacticTechniques
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.

Output Fields

These fields are emitted when the rule matches.

FieldSource
IPCustomEntityextend

OMI Vulnerability Exploitation

#
Severity
medium
Time window
1d
Group by
Computer
Author
Ron Marsiano
Source
github.com/Azure/Azure-Sentinel

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

TacticTechniques
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.

Output Fields

These fields are emitted when the rule matches.

FieldSource
Computerproject
ComputerIPproject
Majorproject
Minorproject
OSNameproject
OSTypeproject
Patchproject
ResourceIdproject
Versionproject

Pathlock TDnR - Database Cockpit Audit Events

#
Status
available
Severity
medium
Time window
1h
Source
github.com/Azure/Azure-Sentinel

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

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.

Output Fields

These fields are emitted when the rule matches.

FieldSource
AffectedUserproject
Areaproject
Bnameproject
CentralTsproject
DataSourceproject
DestIpproject
Eventidproject
Hostnameproject
Instanceproject
LogLineproject
MessageV1project
MessageV2project
MessageV3project
MessageV4project
MsgIdproject
MsgNoproject
MsgTypeproject
Reportproject
SrcIpproject
Subidproject
Sysidproject
Tcodeproject
TimeGeneratedproject

Recorded Future Sandbox - Malicious File in Storage Account

#
Status
available
Severity
medium
Time window
1h
Source
github.com/Azure/Azure-Sentinel

'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.

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.

Status
available
Severity
medium
Time window
5m
Source
github.com/Azure/Azure-Sentinel

'Checks if Sonrai tickets have been assigned. It uses the action type to check if a ticket has been assigned'

MITRE ATT&CK Coverage

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.

TI map IP entity to Workday(ASimAuditEventLogs)

#
Severity
medium
Time window
14d
Group by
$left.TI_ipEntity, $right.DvcIpAddr, IndicatorId
Source
github.com/Azure/Azure-Sentinel

Detects a match in Workday activity from any IP Indicator of Compromise (IOC) provided by Threat Intelligence (TI).

MITRE ATT&CK Coverage

TacticTechniques
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.

FieldSource
ActivityGroupNamesproject
ActorUsernameproject
ConfidenceScoreproject
Descriptionproject
DvcIpAddrproject
ExpirationDateTimeproject
IndicatorIdproject
LatestIndicatorTimeproject
Objectproject
Operationproject
ThreatTypeproject
Urlproject
WD_TimeGeneratedproject
Nameextend
UPNSuffixextend
timestampextend

Trend Micro CAS - Ransomware outbreak

#
Status
available
Severity
high
Time window
2m
Group by
DstUserName
Source
github.com/Azure/Azure-Sentinel

'Triggeres when ransomware was detected on several accounts.'

MITRE ATT&CK Coverage

TacticTechniques
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.

FieldKindValuesSearch
EventTypeeq
  • ransomware corpus 2 (kusto 2)
field:"EventType" kind:eq value:"ransomware"
count_ge
  • 2 transforms: number
field:"count_" kind:ge value:"2"

Output Fields

These fields are emitted when the rule matches.

FieldSource
DstUserNamesummarize
AccountCustomEntityextend

TrendAI Vision One - Create Incident for Workbench Alerts

#
Status
available
Severity
high
Time window
5m
Source
github.com/Azure/Azure-Sentinel

Creates an incident based on TrendAI Vision One Workbench Alerts and maps the impacted entities for Microsoft Sentinel usage.

MITRE ATT&CK Coverage

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 =
ifseverity_s == "low""Informational"
elifseverity_s == "medium""Low"
elifseverity_s == "high""Medium"
else"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.

FieldSource
Severityextend
FileDirectory_sextend
FileName_sextend
ProcessCommandLine_sextend
RegistryKey_sextend
RegistryValueName_sextend
RegistryValue_sextend
UserAccountNTDomain_sextend
UserAccountName_sextend

Vaikora - Engine offline

#
Status
available
Severity
medium
Time window
1d
Group by
TenantId_s
Source
github.com/Azure/Azure-Sentinel

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

TacticTechniques
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 used in Stage 4

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.

FieldKindExcluded valuesSearch
TenantId_seqrecentTenantsexcludes:TenantId_s field:"TenantId_s" value:"recentTenants"

Output Fields

These fields are emitted when the rule matches.

FieldSource
HoursOfflineproject
LastSeenproject
TenantIdproject
TimeGeneratedproject

Vectra Create Incident Based on Priority for Accounts

#
Status
available
Severity
medium
Time window
10m
Source
github.com/Azure/Azure-Sentinel

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

TacticTechniques
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.

Vulnerable Machines related to log4j CVE-2021-44228

#
Status
available
Severity
high
Time window
1d
Group by
Description, RecommendationName, RecommendationSubscriptionId, RemediationDescription, TenantId, VirtualMachine, VulnerabilityId
Source
github.com/Azure/Azure-Sentinel

'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

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.

Output Fields

These fields are emitted when the rule matches.

FieldSource
Descriptionsummarize
RecommendationNamesummarize
RecommendationSubscriptionIdsummarize
RemediationDescriptionsummarize
TenantIdsummarize
VirtualMachinesummarize
VulnerabilityIdsummarize
Timestampextend

Zscaler - ZPA connections outside operational hours

#
Status
available
Severity
medium
Time window
1h
Group by
DstUserName
Source
github.com/Azure/Azure-Sentinel

'Detects ZAP connections outside operational hours.'

MITRE ATT&CK Coverage

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.

Output Fields

These fields are emitted when the rule matches.

FieldSource
DstUserNameproject
AccountCustomEntityextend

Back to all Kusto rules