Detection rules › Kusto
Kusto rules: 32
AWS Security Hub - Detect IAM root user Access Key existence
#This query detects AWS Security Hub control IAM.4 findings indicating that an AWS account root user Access Key exists. A root user Access Key presents a high risk of privilege abuse and should be removed.
MITRE ATT&CK Coverage
Rule Body
id: 171cbece-be87-4467-8754-63d82b3d3dfb
name: AWS Security Hub - Detect IAM root user Access Key existence
description: |
This query detects AWS Security Hub control IAM.4 findings indicating that an AWS account root user Access Key exists.
A root user Access Key presents a high risk of privilege abuse and should be removed.
severity: High
status: Available
requiredDataConnectors:
- connectorId: AWSSecurityHub
dataTypes:
- AWSSecurityHubFindings
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- PrivilegeEscalation
- Persistence
relevantTechniques:
- T1134.001
- T1134.003
- T1098.001
tags:
- PCI DSS v3.2.1
- NIST 800-53 r5
- CIS AWS Foundations Benchmark v1.4.0
query: |
AWSSecurityHubFindings
| where RecordState == "ACTIVE" and ComplianceStatus == "FAILED"
| where tostring(AwsSecurityFindingGeneratorId) == "security-control/IAM.4"
or tostring(ComplianceSecurityControlId) == "IAM.4"
| extend RootUserARN = tostring(Resources[0].Id)
| summarize TimeGenerated = max(TimeGenerated) by AwsAccountId, AwsRegion, AwsSecurityFindingTitle, AwsSecurityFindingDescription, AwsSecurityFindingId, ComplianceSecurityControlId, RootUserARN
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AwsAccountId
- identifier: CloudAppAccountId
columnName: RootUserARN
customDetails:
ComplianceControlId: ComplianceSecurityControlId
Region: AwsRegion
FindingId: AwsSecurityFindingId
RootUserARN: RootUserARN
alertDetailsOverride:
alertDisplayNameFormat: "AWS Account {{AwsAccountId}} root access key exists"
alertDescriptionFormat: "AWS Account {{AwsAccountId}} has a root user access key (Resource: {{RootUserARN}})."
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
AWSSecurityHubFindings
Stage 2: where
| where RecordState == "ACTIVE" and ComplianceStatus == "FAILED"
Stage 3: where
| where tostring(AwsSecurityFindingGeneratorId) == "security-control/IAM.4"
or tostring(ComplianceSecurityControlId) == "IAM.4"
Stage 4: extend
| extend RootUserARN = tostring(Resources[0].Id)
Stage 5: summarize
| summarize TimeGenerated = max(TimeGenerated) by AwsAccountId, AwsRegion, AwsSecurityFindingTitle, AwsSecurityFindingDescription, AwsSecurityFindingId, ComplianceSecurityControlId, RootUserARN
Indicators
These rows show field, operator, and value matches.
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AwsAccountId | summarize |
AwsRegion | summarize |
AwsSecurityFindingDescription | summarize |
AwsSecurityFindingId | summarize |
AwsSecurityFindingTitle | summarize |
ComplianceSecurityControlId | summarize |
RootUserARN | summarize |
TimeGenerated | summarize |
AWS Security Hub - Detect SQS Queue policy allowing public access
#This query detects Amazon SQS queues with access policies that allow public (unauthenticated or cross-account unrestricted) access, using AWS Security Hub control SQS.3 findings. Publicly accessible queues can enable data exfiltration, unauthorized message injection, or disruption of workflows.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Collection | |
| Exfiltration |
Rule Body
id: 4f0f3c2a-8d44-43f8-9d9a-5b1e0d5f2c11
name: AWS Security Hub - Detect SQS Queue policy allowing public access
description: |
This query detects Amazon SQS queues with access policies that allow public (unauthenticated or cross-account unrestricted) access, using AWS Security Hub control SQS.3 findings.
Publicly accessible queues can enable data exfiltration, unauthorized message injection, or disruption of workflows.
severity: High
status: Available
requiredDataConnectors:
- connectorId: AWSSecurityHub
dataTypes:
- AWSSecurityHubFindings
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Exfiltration
- Collection
relevantTechniques:
- T1567
- T1530
tags:
- AWS Foundational Security Best Practices v1.0.0
query: |
AWSSecurityHubFindings
| where RecordState == "ACTIVE" and ComplianceStatus == "FAILED"
| where tostring(AwsSecurityFindingGeneratorId) == "security-control/SQS.3"
or tostring(ComplianceSecurityControlId) == "SQS.3"
| mv-expand Resource = Resources
| where tostring(Resource.Type) == "AwsSqsQueue"
| extend QueueArn = tostring(Resource.Id)
| summarize TimeGenerated = max(TimeGenerated)
by AwsAccountId, AwsRegion, AwsSecurityFindingTitle, AwsSecurityFindingDescription,
AwsSecurityFindingId, ComplianceSecurityControlId, QueueArn
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AwsAccountId
- identifier: CloudAppAccountId
columnName: AwsAccountId
- entityType: CloudApplication
fieldMappings:
- identifier: Name
columnName: QueueArn
customDetails:
ComplianceControlId: ComplianceSecurityControlId
Region: AwsRegion
FindingId: AwsSecurityFindingId
QueueArn: QueueArn
alertDetailsOverride:
alertDisplayNameFormat: "Public access detected for SQS queue {{QueueArn}}"
alertDescriptionFormat: |-
AWS Account {{AwsAccountId}} has an SQS queue ({{QueueArn}}) with a policy permitting public access. Review and restrict the queue access policy.
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
AWSSecurityHubFindings
Stage 2: where
| where RecordState == "ACTIVE" and ComplianceStatus == "FAILED"
Stage 3: where
| where tostring(AwsSecurityFindingGeneratorId) == "security-control/SQS.3"
or tostring(ComplianceSecurityControlId) == "SQS.3"
Stage 4: mv-expand
| mv-expand Resource = Resources
Stage 5: where
| where tostring(Resource.Type) == "AwsSqsQueue"
Stage 6: extend
| extend QueueArn = tostring(Resource.Id)
Stage 7: summarize
| summarize TimeGenerated = max(TimeGenerated)
by AwsAccountId, AwsRegion, AwsSecurityFindingTitle, AwsSecurityFindingDescription,
AwsSecurityFindingId, ComplianceSecurityControlId, QueueArn
Indicators
These rows show field, operator, and value matches.
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AwsAccountId | summarize |
AwsRegion | summarize |
AwsSecurityFindingDescription | summarize |
AwsSecurityFindingId | summarize |
AwsSecurityFindingTitle | summarize |
ComplianceSecurityControlId | summarize |
QueueArn | summarize |
TimeGenerated | summarize |
BloodHound Attack Path Finding - GenericAll 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 - GenericAll Privileges on Tier Zero Objects
Rule Body
id: 5ae4f7e1-b14c-45fe-8d38-f409e148c1da
name: BloodHound Attack Path Finding - GenericAll Privileges on Tier Zero Objects
description: BloodHound Attack Path Finding - GenericAll 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 \n| where Finding == \"T0GenericAll\""
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 == "T0GenericAll"
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Finding | eq |
| field:"Finding" kind:eq value:"T0GenericAll" |
Cognni Incidents for Medium Sensitivity Governance 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 medium sensitivity governance information was placed at risk by user sharing.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Collection |
Rule Body
id: c1d4a005-e220-4d06-9e53-7326a22b8fe4
name: Cognni Incidents for Medium Sensitivity Governance Information
description: |
'Display incidents in which medium sensitivity governance information was placed at risk by user sharing.'
severity: Medium
requiredDataConnectors:
- connectorId: CognniSentinelDataConnector
dataTypes:
- CognniIncidents_CL
queryFrequency: 5h
queryPeriod: 5h
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
- Collection
relevantTechniques:
- T1530
query: |
let mediumRisk = 2;
let goverence = 'Goverence Information';
CognniIncidents_CL
| where Severity == mediumRisk
| where informationType_s == goverence
| 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 mediumRisk = 2;
let goverence = 'Goverence Information';
Stage 1: source
CognniIncidents_CL
Stage 2: where
| where Severity == mediumRisk
Stage 3: where
| where informationType_s == goverence
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:"2" |
informationType_s | eq |
| field:"informationType_s" kind:eq value:"Goverence Information" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AccountCustomEntity | extend |
F&O - Reverted bank account number modifications
#Identifies changes to bank account numbers in Finance & Operations, whereby a bank account number is modified but then subsequently reverted a short time later.
MITRE ATT&CK Coverage
Rule Body
id: 44b1021c-d517-4b7a-9ba6-a91eab94e632
kind: Scheduled
name: F&O - Reverted bank account number modifications
description: Identifies changes to bank account numbers in Finance & Operations, whereby
a bank account number is modified but then subsequently reverted a short time later.
severity: Low
status: Available
requiredDataConnectors:
- connectorId: Dynamics365Finance
dataTypes:
- FinanceOperationsActivity_CL
queryFrequency: 15m
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Impact
relevantTechniques:
- T1565
- T1496
- T0828
- T0831
query: |
let detection_window = 24h;
let query_frequency = 15m;
let bank_changes = FinanceOperationsActivity_CL
| where LogType == "Update" and TableName == "BankAccountTable"
| extend AccountId = tostring(parse_json(tostring(FormattedData.AccountID)).NewData)
| extend AccountNum = parse_json(tostring(FormattedData.AccountNum))
| extend
CurrentAccountNum = tostring(AccountNum.NewData),
OldAccountNum = tostring(AccountNum.OldData)
| where CurrentAccountNum != OldAccountNum;
bank_changes
| join kind=inner (bank_changes
| where TimeGenerated >= ago(query_frequency)
| project-rename UpdatedTime = LogCreatedDateTime, UpdatedAccount = CurrentAccountNum)
on $left.OldAccountNum == $right.UpdatedAccount
| where UpdatedTime between (LogCreatedDateTime .. (LogCreatedDateTime + detection_window))
| extend FinOpsAppId = 32780
| project
TimeGenerated,
LogCreatedDateTime,
LogType,
TableName,
Username,
AccountId,
CurrentAccountNum,
OldAccountNum,
FinOpsAppId
eventGroupingSettings:
aggregationKind: SingleAlert
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: Username
- entityType: CloudApplication
fieldMappings:
- identifier: AppId
columnName: FinOpsAppId
alertDetailsOverride:
alertDisplayNameFormat: F&O - Suspicious bank account number changes
alertDescriptionFormat: A suspicous bank account change was made in F&O, the bank
account number was updated and then changed back to the orginal number a short
time later. {{AccountId}} was changed by {{Username}}
version: 3.2.0
Stages and Predicates
Parameters
let detection_window = 24h;
let query_frequency = 15m;
let bank_changes is inlined into the numbered stages below.
Stages 1 to 4 define let bank_changes as the rule's main pipeline source. Stages 5 to 8 use it.
Stage 1: source
FinanceOperationsActivity_CL
Stage 2: where
| where LogType == "Update" and TableName == "BankAccountTable"
Stage 3: extend (3 consecutive steps)
| extend AccountId = tostring(parse_json(tostring(FormattedData.AccountID)).NewData)
| extend AccountNum = parse_json(tostring(FormattedData.AccountNum))
| extend
CurrentAccountNum = tostring(AccountNum.NewData),
OldAccountNum = tostring(AccountNum.OldData)
Stage 4: where
| where CurrentAccountNum != OldAccountNum
Stage 5: join
bank_changes
| join kind=inner (bank_changes
| where TimeGenerated >= ago(query_frequency)
| project-rename UpdatedTime = LogCreatedDateTime, UpdatedAccount = CurrentAccountNum)
on $left.OldAccountNum == $right.UpdatedAccount
Stage 6: where UpdatedTime - LogCreatedDateTime >= 0s AND UpdatedTime - LogCreatedDateTime <= 1d
where UpdatedTime - LogCreatedDateTime >= 0s AND UpdatedTime - LogCreatedDateTime <= 1d
Stage 7: extend
extend FinOpsAppId
Stage 8: project
project AccountId, CurrentAccountNum, FinOpsAppId, LogCreatedDateTime, LogType, OldAccountNum, TableName, TimeGenerated, Username
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
LogType | eq |
| field:"LogType" kind:eq value:"Update" |
TableName | eq |
| field:"TableName" kind:eq value:"BankAccountTable" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AccountId | project |
CurrentAccountNum | project |
FinOpsAppId | project |
LogCreatedDateTime | project |
LogType | project |
OldAccountNum | project |
TableName | project |
TimeGenerated | project |
Username | project |
Flare leaked credentials 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 leaked credential events.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Credential Access |
Rule Body
id: 9cb7c337-f170-4af6-b0e8-b6b7552d762d
name: Flare leaked credentials results
description: |
'This query searches for leaked credential events.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: Flare
dataTypes:
- FireworkV2_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- CredentialAccess
relevantTechniques:
- T1110
query: |
FireworkV2_CL
| where notempty(uid) and RiskScore >= 3
| extend index_name = split(uid, "/")[0]
| where index_name == "leaked_credential"
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 == "leaked_credential"
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
RiskScore | ge |
| field:"RiskScore" kind:ge value:"3" |
index_name | eq |
| field:"index_name" kind:eq value:"leaked_credential" |
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 |
Gambit Security - Critical Policy Issue Promotion
#'Creates an incident when Gambit Security reports an Active, High-severity policy issue in Microsoft Sentinel.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Impact |
Rule Body
id: 8d2b6f4c-1a37-4e9b-b5c8-7f0e3a2d9c14
name: Gambit Security - Critical Policy Issue Promotion
description: |
'Creates an incident when Gambit Security reports an Active, High-severity policy issue in Microsoft Sentinel.'
severity: High
status: Available
requiredDataConnectors:
- connectorId: GambitSecurityPush
dataTypes:
- GambitPoliciesIssues_CL
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Impact
relevantTechniques:
- T1490
query: |
GambitPoliciesIssues
| where State == "Active" and Severity == "High"
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: false
reopenClosedIncident: false
lookbackDuration: PT5H
matchingMethod: AllEntities
eventGroupingSettings:
aggregationKind: AlertPerResult
customDetails:
PolicyName: PolicyName
PolicyCategories: PolicyCategories
IssueStatus: IssueStatus
AffectedSystems: AffectedSystems
Environment: Environment
RemediationSteps: RemediationSteps
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: ResourceDisplayId
- entityType: AzureResource
fieldMappings:
- identifier: ResourceId
columnName: ResourceDisplayId
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
GambitPoliciesIssues
Stage 2: where
| where State == "Active" and Severity == "High"
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Severity | eq |
| field:"Severity" kind:eq value:"High" |
State | eq |
| field:"State" kind:eq value:"Active" |
GCP Security Command Center - Detect projects with API Keys present
#Detects Google Cloud projects that have API Keys present using Security Command Center API_KEY_EXISTS findings. Projects with API Keys may expose credentials that enable unauthorized access if keys are leaked.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Credential Access |
Rule Body
id: 395f3ced-3923-4b83-b05d-8d077fd48c1e
name: GCP Security Command Center - Detect projects with API Keys present
description: |
Detects Google Cloud projects that have API Keys present using Security Command Center API_KEY_EXISTS findings.
Projects with API Keys may expose credentials that enable unauthorized access if keys are leaked.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: GoogleSCCDefinition
dataTypes:
- GoogleCloudSCC
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- CredentialAccess
relevantTechniques:
- T1552
tags:
- CIS GCP Foundation 3.0 1.12
- NIST 800-53 R5 PL-8, SA-8
- PCI-DSS v4.0 2.2.2, 6.2.1
- ISO-27001 v2022 A.8.27
- Cloud Controls Matrix 4 DSP-07
- NIST Cybersecurity Framework 1.0 PR-IP-2
- CIS Controls 8.0 16.10
query: |
GoogleCloudSCC
| where tostring(Findings.state) == "ACTIVE"
| extend FindingCategory = tostring(Findings.category)
| where FindingCategory == "API_KEY_EXISTS"
| extend FindingsJson = parse_json(Findings), FindingsResourceJson = parse_json(FindingsResource)
| extend ResourceName = tostring(FindingsJson.resourceName)
| extend ProjectId = extract(@"projects/([^/]+)", 1, ResourceName)
| extend ProjectName = tostring(FindingsResourceJson.displayName)
| extend Severity = tostring(FindingsJson.severity),
FindingName = tostring(FindingsJson.name),
ExternalUri = tostring(FindingsJson.externalUri),
Description = tostring(FindingsJson.description)
// Produce one row per project with an API key finding
| summarize TimeGenerated = max(TimeGenerated),
FindingsCount = count(),
ExternalUri = any(ExternalUri),
Description = any(Description)
by ProjectId, ProjectName, Severity, ResourceName
| project TimeGenerated, ProjectId, ProjectName, ResourceName, FindingsCount, Severity, ExternalUri, Description
entityMappings:
- entityType: CloudApplication
fieldMappings:
- identifier: Name
columnName: ProjectName
- identifier: AppId
columnName: ProjectId
customDetails:
ProjectId: ProjectId
ProjectName: ProjectName
FindingsCount: FindingsCount
SampleExternalUri: ExternalUri
SampleDescription: Description
alertDetailsOverride:
alertDisplayNameFormat: "GCP project {{ProjectName}} has API key(s) present"
alertDescriptionFormat: |-
Project {{ProjectName}} ({{ProjectId}}) has {{FindingsCount}} API key finding(s). Review API keys and consider rotating or removing keys and using IAM-based authentication.
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
GoogleCloudSCC
Stage 2: where
| where tostring(Findings.state) == "ACTIVE"
Stage 3: extend
| extend FindingCategory = tostring(Findings.category)
Stage 4: where
| where FindingCategory == "API_KEY_EXISTS"
Stage 5: extend (5 consecutive steps)
| extend FindingsJson = parse_json(Findings), FindingsResourceJson = parse_json(FindingsResource)
| extend ResourceName = tostring(FindingsJson.resourceName)
| extend ProjectId = extract(@"projects/([^/]+)", 1, ResourceName)
| extend ProjectName = tostring(FindingsResourceJson.displayName)
| extend Severity = tostring(FindingsJson.severity),
FindingName = tostring(FindingsJson.name),
ExternalUri = tostring(FindingsJson.externalUri),
Description = tostring(FindingsJson.description)
Stage 6: summarize
| summarize TimeGenerated = max(TimeGenerated),
FindingsCount = count(),
ExternalUri = any(ExternalUri),
Description = any(Description)
by ProjectId, ProjectName, Severity, ResourceName
Stage 7: project
| project TimeGenerated, ProjectId, ProjectName, ResourceName, FindingsCount, Severity, ExternalUri, Description
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
FindingCategory | eq |
| field:"FindingCategory" kind:eq value:"API_KEY_EXISTS" |
Findings.state | eq |
| field:"Findings.state" kind:eq value:"ACTIVE" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Description | project |
ExternalUri | project |
FindingsCount | project |
ProjectId | project |
ProjectName | project |
ResourceName | project |
Severity | project |
TimeGenerated | project |
Job Deleted
#Detects when a job is deleted from Veeam Backup & Replication. This might indicate unauthorized removal of critical components.
Rule Body
id: b4ea5da0-77a8-400e-ae2b-3ca8fdb779ef
name: Job Deleted
description: Detects when a job is deleted from Veeam Backup & Replication. This might
indicate unauthorized removal of critical components.
severity: High
status: Available
requiredDataConnectors:
- connectorId: Syslog
dataTypes:
- Syslog
- connectorId: SyslogAma
dataTypes:
- Syslog
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
eventGroupingSettings:
aggregationKind: AlertPerResult
tactics: []
relevantTechniques: []
query: "Veeam_GetSecurityEvents\n| where instanceId == 23090\n| project\n Date\
\ = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),\n DataSource = original_host,\n\
\ EventId = instanceId,\n UserName = user,\n [\"Job Name\"] = \"\",\n \
\ MessageDetails = Description,\n Severity = SeverityDescription\n| project Date,\
\ DataSource, EventId, UserName, [\"Job Name\"],MessageDetails,Severity"
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 == 23090
Stage 3: project
| project
Date = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),
DataSource = original_host,
EventId = instanceId,
UserName = user,
["Job Name"] = "",
MessageDetails = Description,
Severity = SeverityDescription
Stage 4: project
| project Date, DataSource, EventId, UserName, ["Job Name"],MessageDetails,Severity
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
instanceId | eq |
| field:"instanceId" kind:eq value:"23090" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DataSource | project |
Date | project |
EventId | project |
Job Name | project |
MessageDetails | project |
Severity | project |
UserName | project |
NDMP Server Deleted
#Detects when an NDMP server is deleted from Veeam Backup & Replication. This might indicate unauthorized removal of critical components.
Rule Body
id: e92ba6bb-53ea-4347-b1a6-2e015298bbdc
name: NDMP Server Deleted
description: Detects when an NDMP server is deleted from Veeam Backup & Replication.
This might indicate unauthorized removal of critical components.
severity: Informational
status: Available
requiredDataConnectors:
- connectorId: Syslog
dataTypes:
- Syslog
- connectorId: SyslogAma
dataTypes:
- Syslog
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
eventGroupingSettings:
aggregationKind: AlertPerResult
tactics: []
relevantTechniques: []
query: "Veeam_GetSecurityEvents\n| where instanceId == 28850\n| project\n Date\
\ = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),\n DataSource = original_host,\n\
\ EventId = instanceId,\n UserName = user,\n MessageDetails = Description,\n\
\ Severity = SeverityDescription"
version: 1.0.1
kind: Scheduled
customDetails:
Date: Date
VbrHostName: DataSource
EventId: EventId
MessageDetails: MessageDetails
Severity: Severity
Stages and Predicates
Stage 1: source
Veeam_GetSecurityEvents
Stage 2: where
| where instanceId == 28850
Stage 3: project
| project
Date = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),
DataSource = original_host,
EventId = instanceId,
UserName = user,
MessageDetails = Description,
Severity = SeverityDescription
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
instanceId | eq |
| field:"instanceId" kind:eq value:"28850" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DataSource | project |
Date | project |
EventId | project |
MessageDetails | project |
Severity | project |
UserName | project |
NRT Creation of expensive computes in Azure
#Identifies the creation of large size or expensive VMs (with GPUs or with a large number of virtual CPUs) in Azure. An adversary may create new or update existing virtual machines to evade defenses or use them for cryptomining purposes. For Windows/Linux Vm Sizes, see https://docs.microsoft.com/azure/virtual-machines/windows/sizes Azure VM Naming Conventions, see https://docs.microsoft.com/azure/virtual-machines/vm-naming-conventions
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Defense Impairment |
Telemetry Coverage
Rule Body
id: 56fe0db0-6779-46fa-b3c5-006082a53064
name: NRT Creation of expensive computes in Azure
description: |
'Identifies the creation of large size or expensive VMs (with GPUs or with a large number of virtual CPUs) in Azure.
An adversary may create new or update existing virtual machines to evade defenses or use them for cryptomining purposes.
For Windows/Linux Vm Sizes, see https://docs.microsoft.com/azure/virtual-machines/windows/sizes
Azure VM Naming Conventions, see https://docs.microsoft.com/azure/virtual-machines/vm-naming-conventions'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: AzureActivity
dataTypes:
- AzureActivity
tactics:
- DefenseEvasion
relevantTechniques:
- T1578
query: |
let tokens = dynamic(["416","208","192","128","120","96","80","72","64","48","44","40","nc12","nc24","nv24"]);
let operationList = dynamic(["microsoft.compute/virtualmachines/write", "microsoft.resources/deployments/write"]);
AzureActivity
| where OperationNameValue in~ (operationList)
| where ActivityStatusValue startswith "Accept"
| where Properties has 'vmSize'
| extend parsed_property= parse_json(tostring((parse_json(Properties).responseBody))).properties
| extend vmSize = tostring((parsed_property.hardwareProfile).vmSize)
| mv-apply token=tokens to typeof(string) on (where vmSize contains token)
| extend ComputerName = tostring((parsed_property.osProfile).computerName)
| project TimeGenerated, OperationNameValue, ActivityStatusValue, Caller, CallerIpAddress, ComputerName, vmSize
| extend Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: Caller
- identifier: Name
columnName: Name
- identifier: UPNSuffix
columnName: UPNSuffix
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: ComputerName
- entityType: IP
fieldMappings:
- identifier: Address
columnName: CallerIpAddress
version: 2.0.3
kind: NRT
Stages and Predicates
Parameters
let tokens = dynamic(["416","208","192","128","120","96","80","72","64","48","44","40","nc12","nc24","nv24"]);
let operationList = dynamic(["microsoft.compute/virtualmachines/write", "microsoft.resources/deployments/write"]);
Stage 1: source
AzureActivity
Stage 2: where
| where OperationNameValue in~ (operationList)
Stage 3: where
| where ActivityStatusValue startswith "Accept"
Stage 4: where
| where Properties has 'vmSize'
Stage 5: extend
| extend parsed_property= parse_json(tostring((parse_json(Properties).responseBody))).properties
Stage 6: extend
| extend vmSize = tostring((parsed_property.hardwareProfile).vmSize)
Stage 7: kusto:mv-apply
| mv-apply token=tokens to typeof(string) on (where vmSize contains token)
Stage 8: extend
| extend ComputerName = tostring((parsed_property.osProfile).computerName)
Stage 9: project
| project TimeGenerated, OperationNameValue, ActivityStatusValue, Caller, CallerIpAddress, ComputerName, vmSize
Stage 10: extend
| extend Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ActivityStatusValue | starts_with |
| field:"ActivityStatusValue" kind:starts_with value:"Accept" |
OperationNameValue | in |
| field:"azure_ad::operation_name_value" kind:in |
Properties | match |
| field:"Properties" kind:match value:"vmSize" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ActivityStatusValue | project |
Caller | project |
CallerIpAddress | project |
ComputerName | project |
OperationNameValue | project |
TimeGenerated | project |
vmSize | project |
Name | extend |
UPNSuffix | extend |
Pathlock TDnR - DDIC Table Utility Changes (SE14)
#Detects changes made using the DDIC table utility tool SE14 in SAP, forwarded by Pathlock Threat Detection and Response. SE14 operations can delete or restructure database tables, making this one of the highest-risk actions an SAP user can perform - often used to destroy audit trails or manipulate historical data.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Defense Impairment |
Rule Body
id: 2a3b4c5d-6e7f-4a0b-8c1d-2e3f4a5b6c69
name: Pathlock TDnR - DDIC Table Utility Changes (SE14)
kind: Scheduled
description: >-
Detects changes made using the DDIC table utility tool SE14 in SAP, forwarded by Pathlock
Threat Detection and Response. SE14 operations can delete or restructure database tables,
making this one of the highest-risk actions an SAP user can perform - often used to destroy
audit trails or manipulate historical data.
severity: High
status: Available
requiredDataConnectors:
- connectorId: Pathlock_TDnR
dataTypes:
- Pathlock_TDnR_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
relevantTechniques:
- T1562
query: |
Pathlock_TDnR_CL
| where DataSource == "TABLE_UTILITY"
| 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 == "TABLE_UTILITY"
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:"TABLE_UTILITY" |
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 |
SAP BTP - Mass user deletion in a sub account
#Identifies user account deletion activity where the amount of deleted users exceeds a predefined threshold.
MITRE ATT&CK Coverage
Rule Body
id: 6f1e58bd-cd95-4dfb-8883-94207f30929a
kind: Scheduled
name: SAP BTP - Mass user deletion in a sub account
description: Identifies user account deletion activity where the amount of deleted
users exceeds a predefined threshold.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: SAPBTPAuditEvents
dataTypes:
- SAPBTPAuditLog_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Impact
relevantTechniques:
- T1531
- T1485
- T1489
- T0813
- T0826
- T0827
query: |
let bulk_delete_threshold = 10;
SAPBTPAuditLog_CL
| where isnotnull(Message.object)
| where Message.object has "scim user" and Message.object has "DELETE"
| mv-expand Attributes = Message.attributes
| where isnotempty(Attributes.old)
| extend DeletedUserName = tostring(parse_json(tostring(Attributes.old)).userName)
| where isnotempty(DeletedUserName)
| summarize
Start = min(UpdatedOn),
End = max(UpdatedOn),
DeletedUsers = make_set(DeletedUserName, 100)
by UserName, Tenant, SpaceId
| where array_length(DeletedUsers) > bulk_delete_threshold
| project Start, End, UserName, DeletedUsers, Tenant, SpaceId, CloudApp = "SAP BTP"
| extend AccountName = split(UserName, "@")[0], UPNSuffix = split(UserName, "@")[1]
eventGroupingSettings:
aggregationKind: SingleAlert
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: UPNSuffix
- entityType: CloudApplication
fieldMappings:
- identifier: Name
columnName: CloudApp
version: 3.0.6
Stages and Predicates
Parameters
let bulk_delete_threshold = 10;
Stage 1: source
SAPBTPAuditLog_CL
Stage 2: where
| where isnotnull(Message.object)
Stage 3: where
| where Message.object has "scim user" and Message.object has "DELETE"
Stage 4: mv-expand
| mv-expand Attributes = Message.attributes
Stage 5: where
| where isnotempty(Attributes.old)
Stage 6: extend
| extend DeletedUserName = tostring(parse_json(tostring(Attributes.old)).userName)
Stage 7: where
| where isnotempty(DeletedUserName)
Stage 8: summarize
| summarize
Start = min(UpdatedOn),
End = max(UpdatedOn),
DeletedUsers = make_set(DeletedUserName, 100)
by UserName, Tenant, SpaceId
Stage 9: where
| where array_length(DeletedUsers) > bulk_delete_threshold
Stage 10: project
| project Start, End, UserName, DeletedUsers, Tenant, SpaceId, CloudApp = "SAP BTP"
Stage 11: extend
| extend AccountName = split(UserName, "@")[0], UPNSuffix = split(UserName, "@")[1]
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Attributes.old | is_not_null | field:"Attributes.old" kind:is_not_null | |
DeletedUserName | is_not_null | field:"DeletedUserName" kind:is_not_null | |
Message.object | is_not_null | field:"Message.object" kind:is_not_null | |
Message.object | match |
| field:"Message.object" kind:match |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
CloudApp | project |
DeletedUsers | project |
End | project |
SpaceId | project |
Start | project |
Tenant | project |
UserName | project |
AccountName | extend |
UPNSuffix | extend |
Stale AWS policy attachment to identity
#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.
The policy detects 'AWS policies' attached to IAM users or roles that have not used it during the last X days. It is recommended to remove unused policies from identities to reduce risk.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: 766a3b1b-0d5b-4a8d-b0d6-7dd379e73567
name: Stale AWS policy attachment to identity
kind: Scheduled
description: |2-
The policy detects 'AWS policies' attached to IAM users or roles that have not used it during the last X days. It is recommended to remove unused policies from identities to reduce risk.
severity: Low
status: Available
queryFrequency: 30m
queryPeriod: 30m
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1078
query: |-
Authomize_v2_CL
| where ingestion_time() >= ago(30m)
| extend EventID = id_s, Policy = policy_name_s, Severity = severity_s,Description = description_s,Recommendation = recommendation_s,URL = url_s,Tactics = tactics_s
| where Policy has "Stale AWS policy attachment to identity"
| project EventID, Policy, Severity, Description, Recommendation, URL, Category, Tactics
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: URL
requiredDataConnectors:
- connectorId: Authomize
dataTypes: [ "Authomize_v2_CL" ]
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: 5h
matchingMethod: AnyAlert
groupByEntities: []
groupByAlertDetails: []
groupByCustomDetails: []
eventGroupingSettings:
aggregationKind: SingleAlert
alertDetailsOverride:
alertnameFormat: Alert from Authomize - Stale AWS policy attachment to identity
alertDescriptionFormat: Stale AWS policy attachment to identity. The policy detects 'AWS policies' attached to IAM users or roles that have not used it during the last X days. It is recommended to remove unused policies from identities to reduce risk.
alertSeverity: Severity
alertTactics: Tactics
alertDynamicProperties:
- alertProperty: AlertLink
value: URL
customDetails:
AuthomizeEventID: EventID
EventName: Policy
EventDescription: Description
EventRecommendation: Recommendation
ReferencedURL: URL
suppressionDuration: 5h
suppressionEnabled: false
version: 1.0.2
Stages and Predicates
Stage 1: source
Authomize_v2_CL
Stage 2: where
| where ingestion_time() >= ago(30m)
Stage 3: extend
| extend EventID = id_s, Policy = policy_name_s, Severity = severity_s,Description = description_s,Recommendation = recommendation_s,URL = url_s,Tactics = tactics_s
Stage 4: where
| where Policy has "Stale AWS policy attachment to identity"
Stage 5: project
| project EventID, Policy, Severity, Description, Recommendation, URL, Category, Tactics
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Policy | match |
| field:"policy_name_s" kind:match value:"Stale AWS policy attachment to identity" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Category | project |
Description | project |
EventID | project |
Policy | project |
Recommendation | project |
Severity | project |
Tactics | project |
URL | project |
SUPERNOVA webshell
#'Identifies SUPERNOVA webshell based on W3CIISLog data. References: - https://unit42.paloaltonetworks.com/solarstorm-supernova/'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Persistence | |
| Command & Control |
Rule Body
id: 2acc91c3-17c2-4388-938e-4eac2d5894e8
name: SUPERNOVA webshell
description: |
'Identifies SUPERNOVA webshell based on W3CIISLog data.
References:
- https://unit42.paloaltonetworks.com/solarstorm-supernova/'
severity: High
requiredDataConnectors:
- connectorId: AzureMonitor(IIS)
dataTypes:
- W3CIISLog
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
- CommandAndControl
relevantTechniques:
- T1505
- T1071
query: |
W3CIISLog
| where csMethod == 'GET'
| where isnotempty(csUriStem) and isnotempty(csUriQuery)
| where csUriStem contains "logoimagehandler.ashx"
| where csUriQuery contains "codes" and csUriQuery contains "clazz" and csUriQuery contains "method" and csUriQuery contains "args"
| extend timestamp = TimeGenerated
| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
| extend AccountName = tostring(split(csUserName, "@")[0]), AccountUPNSuffix = tostring(split(csUserName, "@")[1])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: csUserName
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: AccountUPNSuffix
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: Computer
- identifier: HostName
columnName: HostName
- identifier: DnsDomain
columnName: HostNameDomain
- entityType: IP
fieldMappings:
- identifier: Address
columnName: cIP
version: 1.0.4
kind: Scheduled
metadata:
source:
kind: Scheduled
author:
name: Microsoft Security Research
support:
tier: Community
categories:
domains: [ "Security - Others" ]
Stages and Predicates
Stage 1: source
W3CIISLog
Stage 2: where
| where csMethod == 'GET'
Stage 3: where
| where isnotempty(csUriStem) and isnotempty(csUriQuery)
Stage 4: where
| where csUriStem contains "logoimagehandler.ashx"
Stage 5: where
| where csUriQuery contains "codes" and csUriQuery contains "clazz" and csUriQuery contains "method" and csUriQuery contains "args"
Stage 6: extend (4 consecutive steps)
| extend timestamp = TimeGenerated
| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
| extend AccountName = tostring(split(csUserName, "@")[0]), AccountUPNSuffix = tostring(split(csUserName, "@")[1])
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
csMethod | eq |
| field:"csMethod" kind:eq value:"GET" |
csUriQuery | contains |
| field:"csUriQuery" kind:contains |
csUriQuery | is_not_null | field:"csUriQuery" kind:is_not_null | |
csUriStem | contains |
| field:"csUriStem" kind:contains value:"logoimagehandler.ashx" |
csUriStem | is_not_null | field:"csUriStem" kind:is_not_null |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
timestamp | extend |
DomainIndex | extend |
HostName | extend |
HostNameDomain | extend |
AccountName | extend |
AccountUPNSuffix | extend |
Tailscale: Policy file (ACL) modified
#Identifies when the tailnet ACL/policy file is modified. Review the diff - incorrect ACLs can silently expand blast radius across the tailnet.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Persistence |
Rule Body
id: 1e7249c2-1a9d-05fd-45cb-c859eef5b8ae
name: "Tailscale: Policy file (ACL) modified"
description: |
Identifies when the tailnet ACL/policy file is modified. Review the diff - incorrect ACLs can silently expand blast radius across the tailnet.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: TailscaleCCF
dataTypes:
- Tailscale_Audit_CL
queryFrequency: 15m
queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
- Persistence
relevantTechniques:
- T1556
query: |
Tailscale_Audit_CL
| where Action == "UPDATE"
| where tostring(Target.type) == "TAILNET"
| where tostring(Target.property) == "ACL"
| extend ActorLogin = tostring(Actor.loginName)
| project TimeGenerated, ActorLogin, Action, Target, Origin, Old, New
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: ActorLogin
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: PT5H
matchingMethod: AllEntities
kind: Scheduled
version: 1.0.0
Stages and Predicates
Stage 1: source
Tailscale_Audit_CL
Stage 2: where
| where Action == "UPDATE"
Stage 3: where
| where tostring(Target.type) == "TAILNET"
Stage 4: where
| where tostring(Target.property) == "ACL"
Stage 5: extend
| extend ActorLogin = tostring(Actor.loginName)
Stage 6: project
| project TimeGenerated, ActorLogin, Action, Target, Origin, Old, New
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Action | eq |
| field:"Action" kind:eq value:"UPDATE" |
Target.property | eq |
| field:"Target.property" kind:eq value:"ACL" |
Target.type | eq |
| field:"Target.type" kind:eq value:"TAILNET" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Action | project |
ActorLogin | project |
New | project |
Old | project |
Origin | project |
Target | project |
TimeGenerated | project |
TI map IP entity to DNS Events (ASIM DNS schema)
#This rule identifies DNS requests for which response IP address is a known IoC. This analytic rule uses ASIM and supports any built-in or custom source that supports the ASIM DNS schema.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Command & Control |
Telemetry Coverage
| Provider | Record / event type |
|---|---|
| Sysmon | Event ID 22: DNSEvent (DNS query) |
Rule Body
id: 67775878-7f8b-4380-ac54-115e1e828901
name: TI map IP entity to DNS Events (ASIM DNS schema)
description: |
'This rule identifies DNS requests for which response IP address is a known IoC. This analytic rule uses [ASIM](https://aka.ms/AboutASIM) and supports any built-in or custom source that supports the ASIM DNS schema.'
severity: Medium
requiredDataConnectors:
- connectorId: ThreatIntelligence
dataTypes:
- ThreatIntelligenceIndicator
- connectorId: ThreatIntelligenceTaxii
dataTypes:
- ThreatIntelligenceIndicator
- connectorId: DNS
dataTypes:
- DnsEvents
- connectorId: AzureFirewall
dataTypes:
- AzureDiagnostics
- connectorId: Zscaler
dataTypes:
- CommonSecurityLog
- connectorId: InfobloxNIOS
dataTypes:
- Syslog
- connectorId: GCPDNSDataConnector
dataTypes:
- GCP_DNS_CL
- connectorId: NXLogDnsLogs
dataTypes:
- NXLog_DNS_Server_CL
- connectorId: CiscoUmbrellaDataConnector
dataTypes:
- Cisco_Umbrella_dns_CL
- connectorId: MicrosoftDefenderThreatIntelligence
dataTypes:
- ThreatIntelligenceIndicator
- connectorId: Corelight
dataTypes:
- Corelight_CL
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandAndControl
relevantTechniques:
- T1071
tags:
- ParentAlert: https://github.com/Azure/Azure-Sentinel/blob/master/Detections/ThreatIntelligenceIndicator/IPEntity_DnsEvents.yaml
version: 1.0.0
- Schema: ASIMDns
SchemaVersion: 0.1.1
query: |
let dt_lookBack = 1h;
let ioc_lookBack = 14d;
let IP_TI =
ThreatIntelligenceIndicator
| where TimeGenerated >= ago(ioc_lookBack)
| extend IoC = coalesce(NetworkIP, NetworkDestinationIP, NetworkSourceIP,EmailSourceIpAddress,"NO_IP")
| where IoC != "NO_IP"
| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
| where Active == true and ExpirationDateTime > now();
IP_TI
| join kind=innerunique // using innerunique to keep perf fast and result set low, we only need one match to indicate potential malicious activity that needs to be investigated
(
_Im_Dns(starttime=ago(dt_lookBack))
| where isnotempty(DnsResponseName)
| summarize imDns_mintime=min(TimeGenerated), imDns_maxtime=max(TimeGenerated) by SrcIpAddr, DnsQuery, DnsResponseName, Dvc, EventProduct, EventVendor
| extend addresses = extract_all (@'(\d+\.\d+\.\d+\.\d+)', DnsResponseName)
| mv-expand IoC = addresses to typeof(string)
)
on IoC
| where imDns_mintime < ExpirationDateTime
| project imDns_mintime, imDns_maxtime, Description, ActivityGroupNames, IndicatorId, ThreatType, LatestIndicatorTime, ExpirationDateTime, ConfidenceScore, SrcIpAddr, IoC, Dvc, EventVendor, EventProduct, DnsQuery, DnsResponseName
entityMappings:
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: Dvc
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IoC
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SrcIpAddr
customDetails:
LatestIndicatorTime: LatestIndicatorTime
Description: Description
ActivityGroupNames: ActivityGroupNames
IndicatorId: IndicatorId
ThreatType: ThreatType
ExpirationDateTime: ExpirationDateTime
ConfidenceScore: ConfidenceScore
DNSRequestTime: imDns_mintime
SourceIPAddress: SrcIpAddr
DnsQuery: DnsQuery
alertDetailsOverride:
alertDisplayNameFormat: The response {{IoC}} to DNS query matched an IoC
alertDescriptionFormat: The response address {{IoC}} to a DNS query matched a known indicator of compromise of {{ThreatType}}. Consult the threat intelligence blade for more information on the indicator.
version: 1.2.4
kind: Scheduled
Stages and Predicates
Parameters
let dt_lookBack = 1h;
let ioc_lookBack = 14d;
let IP_TI is inlined into the numbered stages below.
Stages 1 to 6 define let IP_TI as the rule's main pipeline source. Stages 7 to 9 use it.
Stage 1: source
ThreatIntelligenceIndicator
Stage 2: where
| where TimeGenerated >= ago(ioc_lookBack)
Stage 3: extend
| extend IoC = coalesce(NetworkIP, NetworkDestinationIP, NetworkSourceIP,EmailSourceIpAddress,"NO_IP")
Stage 4: where
| where IoC != "NO_IP"
Stage 5: summarize
| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
Stage 6: where
| where Active == true and ExpirationDateTime > now()
Stage 7: join
IP_TI
| join kind=innerunique
(
_Im_Dns(starttime=ago(dt_lookBack))
| where isnotempty(DnsResponseName)
| summarize imDns_mintime=min(TimeGenerated), imDns_maxtime=max(TimeGenerated) by SrcIpAddr, DnsQuery, DnsResponseName, Dvc, EventProduct, EventVendor
| extend addresses = extract_all (@'(\d+\.\d+\.\d+\.\d+)', DnsResponseName)
| mv-expand IoC = addresses to typeof(string)
)
on IoC
Stage 8: where
where imDns_mintime < ExpirationDateTime
Stage 9: project
project ActivityGroupNames, ConfidenceScore, Description, DnsQuery, DnsResponseName, Dvc, EventProduct, EventVendor, ExpirationDateTime, IndicatorId, IoC, LatestIndicatorTime, SrcIpAddr, ThreatType, imDns_maxtime, imDns_mintime
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Active | eq |
| field:"Active" kind:eq value:"true" |
DnsResponseName | is_not_null | field:"DnsResponseName" kind:is_not_null | |
IoC | ne |
| field:"IoC" kind:ne value:"NO_IP" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ActivityGroupNames | project |
ConfidenceScore | project |
Description | project |
DnsQuery | project |
DnsResponseName | project |
Dvc | project |
EventProduct | project |
EventVendor | project |
ExpirationDateTime | project |
IndicatorId | project |
IoC | project |
LatestIndicatorTime | project |
SrcIpAddr | project |
ThreatType | project |
imDns_maxtime | project |
imDns_mintime | project |
Ubiquiti - Unusual DNS connection
#'Detects unusual remote to local (R2L) DNS connections.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Command & Control |
Rule Body
id: 14a23ded-7fb9-48ee-ba39-859517a49b51
name: Ubiquiti - Unusual DNS connection
description: |
'Detects unusual remote to local (R2L) DNS connections.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: CustomLogsAma
dataTypes:
- Ubiquiti_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandAndControl
relevantTechniques:
- T1090
- T1572
query: |
let threshold = 50;
UbiquitiAuditEvent
| where EventCategory =~ 'firewall'
| where ipv4_is_private(SrcIpAddr) == 'False'
| where ipv4_is_private(DstIpAddr)
| where DstPortNumber == '53'
| summarize count() by SrcIpAddr, DstIpAddr
| where count_ > threshold
| extend IPCustomEntity = DstIpAddr
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.2
kind: Scheduled
Stages and Predicates
Parameters
let threshold = 50;
Stage 1: source
UbiquitiAuditEvent
Stage 2: where
| where EventCategory =~ 'firewall'
Stage 3: where
| where ipv4_is_private(SrcIpAddr) == 'False'
Stage 4: where
| where ipv4_is_private(DstIpAddr)
Stage 5: where
| where DstPortNumber == '53'
Stage 6: summarize
| summarize count() by SrcIpAddr, DstIpAddr
Stage 7: where
| where count_ > threshold
Stage 8: extend
| extend IPCustomEntity = DstIpAddr
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
DstIpAddr | cidr_match |
| field:"dest_ip" kind:cidr_match |
DstPortNumber | eq |
| field:"DstPortNumber" kind:eq value:"53" |
EventCategory | eq |
| field:"EventCategory" kind:eq value:"firewall" |
count_ | gt |
| field:"count_" kind:gt value:"50" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
SrcIpAddr | 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:SrcIpAddr |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DstIpAddr | summarize |
SrcIpAddr | summarize |
IPCustomEntity | extend |