Detection rules › Kusto
Kusto rules: 00
A potentially malicious web request was executed against a web server
#'Detects unobstructed Web Application Firewall (WAF) activity in sessions where the WAF blocked incoming requests by computing the ratio between blocked requests and unobstructed WAF requests in these sessions (BlockvsSuccessRatio metric). A high ratio value for a given client IP and hostname calls for further investigation of the WAF data in that session, due to the significantly high number of blocked requests and a few unobstructed logs that may be malicious but have passed undetected through the WAF. The successCode variable defines what the detection thinks is a successful status code and should be altered to fit the environment.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: 46ac55ae-47b8-414a-8f94-89ccd1962178
name: A potentially malicious web request was executed against a web server
description: |
'Detects unobstructed Web Application Firewall (WAF) activity in sessions where the WAF blocked incoming requests by computing the ratio between blocked requests and unobstructed WAF requests in these sessions (BlockvsSuccessRatio metric).
A high ratio value for a given client IP and hostname calls for further investigation of the WAF data in that session, due to the significantly high number of blocked requests and a few unobstructed logs that may be malicious but have passed undetected through the WAF. The successCode variable defines what the detection thinks is a successful status code and should be altered to fit the environment.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: WAF
dataTypes:
- AzureDiagnostics
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1190
query: |
let queryperiod = 1d;
let mode = dynamic(['Blocked', 'Detected']);
let successCode = dynamic(['200', '101','204', '400','504','304','401','500']);
let sessionBin = 30m;
AGWFirewallLogs
| where TimeGenerated > ago(queryperiod)
| where Action in (mode)
| sort by Hostname asc, ClientIp asc, TimeGenerated asc
| extend SessionBlockedStarted = row_window_session(TimeGenerated, queryperiod, 10m, ((ClientIp != prev(ClientIp)) or (Hostname != prev(Hostname))))
| summarize SessionBlockedEnded = max(TimeGenerated), SessionBlockedCount = count() by Hostname, ClientIp, SessionBlockedStarted
| extend TimeKey = range(bin(SessionBlockedStarted, sessionBin), bin(SessionBlockedEnded, sessionBin), sessionBin)
| mv-expand TimeKey to typeof(datetime)
| join kind = inner(
AGWAccessLogs
| where TimeGenerated > ago(queryperiod)
| where (isempty(HttpStatus) or HttpStatus in (successCode))
| extend TimeKey = bin(TimeGenerated, sessionBin)
| extend Hostname = coalesce(Host,OriginalHost)
| extend ClientIp = tostring(ClientIp)
) on TimeKey, Hostname, ClientIp
| where TimeGenerated between (SessionBlockedStarted..SessionBlockedEnded)
| extend
OriginalRequestUriWithArgs = column_ifexists("OriginalRequestUriWithArgs", ""),
ServerStatus = column_ifexists("ServerStatus", "")
| summarize
SuccessfulAccessCount = count(),
UserAgents = make_set(UserAgent, 250),
RequestURIs = make_set(RequestUri, 250),
OriginalRequestURIs = make_set(OriginalRequestUriWithArgs, 250),
SuccessCodes = make_set(HttpStatus, 250),
SuccessCodes_BackendServer = make_set(ServerStatus, 250),
take_any(SessionBlockedEnded, SessionBlockedCount)
by Hostname, ClientIp, SessionBlockedStarted
| where SessionBlockedCount > SuccessfulAccessCount
| extend BlockvsSuccessRatio = SessionBlockedCount/toreal(SuccessfulAccessCount)
| sort by BlockvsSuccessRatio desc, SessionBlockedStarted asc
| project-reorder SessionBlockedStarted, SessionBlockedEnded, Hostname, ClientIp, SessionBlockedCount, SuccessfulAccessCount, BlockvsSuccessRatio, SuccessCodes, RequestURIs, OriginalRequestURIs, UserAgents
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: ClientIp
version: 1.0.6
kind: Scheduled
Stages and Predicates
Parameters
let queryperiod = 1d;
let mode = dynamic(['Blocked', 'Detected']);
let successCode = dynamic(['200', '101','204', '400','504','304','401','500']);
let sessionBin = 30m;
Stage 1: source
AGWFirewallLogs
Stage 2: where
| where TimeGenerated > ago(queryperiod)
Stage 3: where
| where Action in (mode)
Stage 4: sort
| sort by Hostname asc, ClientIp asc, TimeGenerated asc
Stage 5: extend
| extend SessionBlockedStarted = row_window_session(TimeGenerated, queryperiod, 10m, ((ClientIp != prev(ClientIp)) or (Hostname != prev(Hostname))))
Stage 6: summarize
| summarize SessionBlockedEnded = max(TimeGenerated), SessionBlockedCount = count() by Hostname, ClientIp, SessionBlockedStarted
Stage 7: extend
| extend TimeKey = range(bin(SessionBlockedStarted, sessionBin), bin(SessionBlockedEnded, sessionBin), sessionBin)
Stage 8: mv-expand
| mv-expand TimeKey to typeof(datetime)
Stage 9: join
| join kind = inner(
AGWAccessLogs
| where TimeGenerated > ago(queryperiod)
| where (isempty(HttpStatus) or HttpStatus in (successCode))
| extend TimeKey = bin(TimeGenerated, sessionBin)
| extend Hostname = coalesce(Host,OriginalHost)
| extend ClientIp = tostring(ClientIp)
) on TimeKey, Hostname, ClientIp
Stage 10: where
where TimeGenerated >= "SessionBlockedStarted" and TimeGenerated <= "SessionBlockedEnded"
Stage 11: extend
extend OriginalRequestUriWithArgs, ServerStatus
Stage 12: summarize
summarize OriginalRequestURIs, RequestURIs, SuccessCodes, SuccessCodes_BackendServer, SuccessfulAccessCount, UserAgents by Hostname, ClientIp, SessionBlockedStarted
Stage 13: where
where SessionBlockedCount > SuccessfulAccessCount
Stage 14: extend
extend BlockvsSuccessRatio
Stage 15: sort
sort by BlockvsSuccessRatio, SessionBlockedStarted
Stage 16: project-reorder
project-reorder
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Action | in |
| field:"Action" kind:in |
HttpStatus | in |
| field:"HttpStatus" kind:in |
HttpStatus | is_null | field:"HttpStatus" kind:is_null | |
TimeGenerated | ge |
| field:"TimeGenerated" kind:ge value:"SessionBlockedStarted" |
TimeGenerated | le |
| field:"TimeGenerated" kind:le value:"SessionBlockedEnded" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ClientIp | summarize |
Hostname | summarize |
OriginalRequestURIs | summarize |
RequestURIs | summarize |
SessionBlockedStarted | summarize |
SuccessCodes | summarize |
SuccessCodes_BackendServer | summarize |
SuccessfulAccessCount | summarize |
UserAgents | summarize |
BlockvsSuccessRatio | extend |
Acronis - Multiple Endpoints Infected by Ransomware
#Detects when three or more distinct endpoints report ransomware detections within a single day.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Impact |
Rule Body
id: a783ade7-bf43-416d-b809-8f5b06d87790
name: Acronis - Multiple Endpoints Infected by Ransomware
description: Detects when three or more distinct endpoints report ransomware detections within a single day.
severity: High
query: |
CommonSecurityLog
| where DeviceVendor == "Acronis"
| where DeviceEventClassID == "ActiveProtectionBlocksSuspiciousActivity"
| summarize ActiveProtectionBlocksSuspiciousActivity = count() by DeviceName
queryFrequency: 1h
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 2
tactics:
- Impact
relevantTechniques:
- T1486
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: true
lookbackDuration: P1D
matchingMethod: AnyAlert
eventGroupingSettings:
aggregationKind: SingleAlert
customDetails:
DeviceName: DeviceName
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: DeviceName
version: 1.0.0
kind: Scheduled
requiredDataConnectors: []
Stages and Predicates
Stage 1: source
CommonSecurityLog
Stage 2: where
| where DeviceVendor == "Acronis"
Stage 3: where
| where DeviceEventClassID == "ActiveProtectionBlocksSuspiciousActivity"
Stage 4: summarize
| summarize ActiveProtectionBlocksSuspiciousActivity = count() by DeviceName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
DeviceEventClassID | eq |
| field:"DeviceEventClassID" kind:eq value:"ActiveProtectionBlocksSuspiciousActivity" |
DeviceVendor | eq |
| field:"DeviceVendor" kind:eq value:"Acronis" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ActiveProtectionBlocksSuspiciousActivity | summarize |
DeviceName | summarize |
Bitglass - Suspicious file uploads
#'Detects suspicious file upload activity.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Exfiltration |
Rule Body
id: 4b272e82-19f1-40d1-bfdf-74fbb6353e8b
name: Bitglass - Suspicious file uploads
description: |
'Detects suspicious file upload activity.'
severity: High
status: Available
requiredDataConnectors:
- connectorId: Bitglass
dataTypes:
- Bitglass
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Exfiltration
relevantTechniques:
- T1567
query: |
Bitglass
| where EventType =~ 'swgwebdlp'
| where HttpRequestMethod =~ 'POST'
| where isnotempty(DlpPattern)
| summarize count() by User, bin(TimeGenerated, 15m)
| where count_ > 1
| extend AccountCustomEntity = User
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountCustomEntity
version: 1.0.1
kind: Scheduled
Stages and Predicates
Stage 1: source
Bitglass
Stage 2: where
| where EventType =~ 'swgwebdlp'
Stage 3: where
| where HttpRequestMethod =~ 'POST'
Stage 4: where
| where isnotempty(DlpPattern)
Stage 5: summarize
| summarize count() by User, bin(TimeGenerated, 15m)
Stage 6: where
| where count_ > 1
Stage 7: extend
| extend AccountCustomEntity = User
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
DlpPattern | is_not_null | field:"DlpPattern" kind:is_not_null | |
EventType | eq |
| field:"EventType" kind:eq value:"swgwebdlp" |
HttpRequestMethod | eq |
| field:"HttpRequestMethod" kind:eq value:"POST" |
count_ | gt |
| field:"count_" kind:gt value:"1" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
User | summarize |
AccountCustomEntity | extend |
BloodHound Attack Path Finding - Large Default Group With SyncLapsPassword Privileges
#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 - Large Default Group With SyncLapsPassword Privileges
Rule Body
id: af134cb3-a3e7-421c-bcef-0c6c6432a273
name: BloodHound Attack Path Finding - Large Default Group With SyncLapsPassword Privileges
description: BloodHound Attack Path Finding - Large Default Group With SyncLapsPassword
Privileges
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 == "LargeDefaultGroupsSyncLAPSPassword"
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 == "LargeDefaultGroupsSyncLAPSPassword"
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Finding | eq |
| field:"Finding" kind:eq value:"LargeDefaultGroupsSyncLAPSPassword" |
Cisco ASA - threat detection message fired
#'Identifies when the Cisco ASA Threat Detection engine fired an alert based on malicious activity occurring on the network inicated by DeviceEventClassID 733101-733105 Resources: https://www.cisco.com/c/en/us/td/docs/security/asa/syslog/b_syslog/syslogs9.html Details on how to further troubleshoot/investigate: https://www.cisco.com/c/en/us/support/docs/security/asa-5500-x-series-next-generation-firewalls/113685-asa-threat-detection.html'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Discovery | |
| Impact |
Rule Body
id: 795edf2d-cf3e-45b5-8452-fe6c9e6a582e
name: Cisco ASA - threat detection message fired
description: |
'Identifies when the Cisco ASA Threat Detection engine fired an alert based on malicious activity occurring on the network inicated by DeviceEventClassID 733101-733105
Resources: https://www.cisco.com/c/en/us/td/docs/security/asa/syslog/b_syslog/syslogs9.html
Details on how to further troubleshoot/investigate: https://www.cisco.com/c/en/us/support/docs/security/asa-5500-x-series-next-generation-firewalls/113685-asa-threat-detection.html'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: CiscoAsaAma
dataTypes:
- CommonSecurityLog
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Discovery
- Impact
relevantTechniques:
- T1046
- T1498
query: |
CommonSecurityLog
| where isempty(CommunicationDirection)
| where DeviceEventClassID in ("733101","733102","733103","733104","733105")
| extend HostName = tostring(split(DeviceName, ".")[0]), DomainIndex = toint(indexof(DeviceName, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(DeviceName, DomainIndex + 1), DeviceName)
entityMappings:
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: DeviceName
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SourceIP
version: 1.0.3
kind: Scheduled
Stages and Predicates
Stage 1: source
CommonSecurityLog
Stage 2: where
| where isempty(CommunicationDirection)
Stage 3: where
| where DeviceEventClassID in ("733101","733102","733103","733104","733105")
Stage 4: extend
| extend HostName = tostring(split(DeviceName, ".")[0]), DomainIndex = toint(indexof(DeviceName, '.'))
Stage 5: extend
| extend HostNameDomain = iff(DomainIndex != -1, substring(DeviceName, DomainIndex + 1), DeviceName)
HostNameDomain =DomainIndex != -1substring(DeviceName, (DomainIndex + 1))DeviceNameIndicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
CommunicationDirection | is_null | field:"CommunicationDirection" kind:is_null | |
DeviceEventClassID | in |
| field:"DeviceEventClassID" kind:in |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DomainIndex | extend |
HostName | extend |
HostNameDomain | extend |
Configuration Backup Job Settings Updated
#Detects when configuration backup job settings are updated in Veeam Backup & Replication. This might indicate configuration changes that require review.
Rule Body
id: 90039769-0c32-442b-bb12-5b61224a77a0
name: Configuration Backup Job Settings Updated
description: Detects when configuration backup job settings are updated in Veeam Backup
& Replication. This might indicate configuration changes that require review.
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 == 31500\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 == 31500
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:"31500" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DataSource | project |
Date | project |
EventId | project |
MessageDetails | project |
Severity | project |
UserName | project |
ContraForce - Privileged access change
#'Identifies administrative access changes made in the ContraForce workspace: workspace role assignments, changes and removals, organization role changes, member additions and removals, and service provider (MSP) access grants or revocations. Review each change to confirm it was expected and authorized. The affected member and the old and new roles are carried in the event metadata.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Persistence | |
| Privilege Escalation |
Rule Body
id: 3f4bd2a1-7c58-4a83-9c2e-6d1f0a8b5c31
name: ContraForce - Privileged access change
description: |
'Identifies administrative access changes made in the ContraForce workspace: workspace role
assignments, changes and removals, organization role changes, member additions and removals,
and service provider (MSP) access grants or revocations. Review each change to confirm it was
expected and authorized. The affected member and the old and new roles are carried in the
event metadata.'
severity: Medium
requiredDataConnectors:
- connectorId: ContraForceEvents
dataTypes:
- ContraForceEvents_CL
queryFrequency: 5m
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
- PrivilegeEscalation
- Persistence
relevantTechniques:
- T1078
- T1098
query: |
ContraForceEvents_CL
| where ingestion_time() > ago(5m)
| where ActivityType in ("WorkspaceRoleAssigned", "WorkspaceRoleChanged", "WorkspaceRoleRemoved", "OrganizationalRoleChanged", "MemberAdded", "MemberRemoved", "ServiceProviderAdded", "ServiceProviderRemoved")
| extend Meta = parse_json(Metadata)
| extend MemberEmail = tostring(Meta.MemberEmail),
MemberType = tostring(Meta.MemberType),
FromRole = tostring(Meta.FromRole),
ToRole = tostring(Meta.ToRole),
Members = tostring(Meta.Members)
| project TimeGenerated, EventId, CfWorkspaceId, ActivityType, ActivityAction,
ActorName, ActorEmail, TargetResourceType, TargetResourceId, TargetResourceName,
MemberEmail, MemberType, FromRole, ToRole, Members
eventGroupingSettings:
aggregationKind: AlertPerResult
alertDetailsOverride:
alertDisplayNameFormat: 'ContraForce access change: {{ActivityType}} on {{TargetResourceName}}'
alertDescriptionFormat: '{{ActorName}} performed {{ActivityType}} on {{TargetResourceName}}. Member email, old and new roles are in the alert custom details.'
customDetails:
EventId: EventId
ActorEmail: ActorEmail
MemberEmail: MemberEmail
FromRole: FromRole
ToRole: ToRole
CfWorkspaceId: CfWorkspaceId
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: PT2H
matchingMethod: Selected
groupByCustomDetails:
- EventId
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
ContraForceEvents_CL
Stage 2: where
| where ingestion_time() > ago(5m)
Stage 3: where
| where ActivityType in ("WorkspaceRoleAssigned", "WorkspaceRoleChanged", "WorkspaceRoleRemoved", "OrganizationalRoleChanged", "MemberAdded", "MemberRemoved", "ServiceProviderAdded", "ServiceProviderRemoved")
Stage 4: extend
| extend Meta = parse_json(Metadata)
Stage 5: extend
| extend MemberEmail = tostring(Meta.MemberEmail),
MemberType = tostring(Meta.MemberType),
FromRole = tostring(Meta.FromRole),
ToRole = tostring(Meta.ToRole),
Members = tostring(Meta.Members)
Stage 6: project
| project TimeGenerated, EventId, CfWorkspaceId, ActivityType, ActivityAction,
ActorName, ActorEmail, TargetResourceType, TargetResourceId, TargetResourceName,
MemberEmail, MemberType, FromRole, ToRole, Members
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ActivityType | in |
| field:"ActivityType" kind:in |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ActivityAction | project |
ActivityType | project |
ActorEmail | project |
ActorName | project |
CfWorkspaceId | project |
EventId | project |
FromRole | project |
MemberEmail | project |
MemberType | project |
Members | project |
TargetResourceId | project |
TargetResourceName | project |
TargetResourceType | project |
TimeGenerated | project |
ToRole | project |
Google SecOps - Detection Alerts
#Creates one incident per active Google Security Operations detection alert in Microsoft Sentinel. Covers all rule types and severity levels with no additional filtering, providing broad visibility across all Google SecOps alerts. Use alongside focused rules for complete detection coverage.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Privilege Escalation | |
| Stealth | |
| Lateral Movement |
Rule Body
id: f6b0c254-8f7d-4a1b-d5c2-0e4a6b9f2d8a
name: Google SecOps - Detection Alerts
description: |
Creates one incident per active Google Security Operations detection alert in Microsoft Sentinel. Covers all rule types and severity levels with no additional filtering, providing broad visibility across all Google SecOps alerts. Use alongside focused rules for complete detection coverage.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: GSDetectionAlerts
dataTypes:
- DetectionAlerts_CL
queryFrequency: 10m
queryPeriod: 10m
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
- DefenseEvasion
- LateralMovement
- PrivilegeEscalation
- CommandAndControl
relevantTechniques:
- T1078
- T1021
- T1566
query: |
GoogleSecOpsDetectionAlerts
| where alertState == "ALERTING"
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: varPrincipalIp
- entityType: IP
fieldMappings:
- identifier: Address
columnName: varTargetIp
- entityType: IP
fieldMappings:
- identifier: Address
columnName: varSourceIp
- entityType: IP
fieldMappings:
- identifier: Address
columnName: varCorrelationIp
- entityType: URL
fieldMappings:
- identifier: Url
columnName: urlBackToProduct
customDetails:
alert_identifier: id
RuleName: ruleName
RuleId: ruleId
RuleType: ruleType
Severity: severity
RiskScore: riskScore
AlertState: alertState
DetectionType: detectionType
DetectionTime: detectionTime
PrincipalIP: varPrincipalIp
TargetIP: varTargetIp
SourceIP: varSourceIp
CorrelationIP: varCorrelationIp
PrincipalHostname: varPrincipalHostname
TargetHostname: varTargetHostname
SourceHostname: varSourceHostname
PrincipalUser: varPrincipalUserUserid
SourceUser: varSourceUserUserid
TargetUser: varTargetUserUserid
alertDetailsOverride:
alertDisplayNameFormat: "Google SecOps Alert: {{ruleName}} : {{id}}"
alertDescriptionFormat: "Google SecOps detection alert. Rule: {{ruleName}}. Severity: {{severity}}. Type: {{ruleType}}."
eventGroupingSettings:
aggregationKind: AlertPerResult
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: P1D
matchingMethod: Selected
groupByCustomDetails:
- alert_identifier
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
GoogleSecOpsDetectionAlerts
Stage 2: where
| where alertState == "ALERTING"
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
alertState | eq |
| field:"alertState" kind:eq value:"ALERTING" |
High-Risk Admin Activity
#The Okta risk engine auto-assigns risk levels to each login attempt. This rule identifies successful admin operations that correlate with successful high-risk Okta authentication or session start events.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Persistence | |
| Privilege Escalation |
Telemetry Coverage
Rules Detecting the Same Action
These rules filter on the same operation.
- Administrator Privileges Assigned to an Okta Group (Elastic)
- Attempt to Create Okta API Token (Elastic)
- Failed Logins from Unknown or Invalid User (Kusto)
- First Occurrence of Okta User Session Started via Proxy (Elastic)
- Multiple Okta Sessions Detected for a Single User (Elastic)
- Multiple Okta User Authentication Events with Same Device Token Hash (Elastic)
- New Device/Location sign-in along with critical operation (Kusto)
- Okta AD Agent Token Abuse - Behavioral (Panther)
Rule Body
id: 9f82a735-ae43-4c03-afb4-d5d153e1ace1
name: High-Risk Admin Activity
description: |
The Okta risk engine auto-assigns risk levels to each login attempt. This rule identifies successful admin operations that correlate with successful high-risk Okta authentication or session start events.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: OktaSSO
dataTypes:
- Okta_CL
- connectorId: OktaSSOv2
dataTypes:
- OktaSSO
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
- PrivilegeEscalation
relevantTechniques:
- T1098
- T1078.004
query: |
let AdminActivity = dynamic(["iam.role.create","iam.role.permissions.add","user.session.access_admin_app","user.mfa.factor.suspend", "user.account.privilege.grant", "group.privilege.grant", "system.api_token.create", "user.session.impersonation.grant"]);
// Define the list of allowed admins to exclude from the alert. This can be modified to include specific admin accounts that are known to perform high-risk activities as part of their job function.
let AllowedAdmins = dynamic([]);
let AdminOperations = OktaSSO
| where actor_alternateId_s !in (AllowedAdmins)
| where eventType_s in (AdminActivity)
| where outcome_result_s =~ 'SUCCESS'
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by actor_alternateId_s, actor_displayName_s, client_userAgent_os_s, client_userAgent_browser_s, client_device_s, client_userAgent_rawUserAgent_s, client_ipAddress_s, client_geographicalContext_country_s, client_geographicalContext_city_s, displayMessage_s, outcome_result_s, outcome_reason_s, column_ifexists('debugContext_debugData_logOnlySecurityData_s', ""), column_ifexists('debugContext_debugData_threatSuspected_s', ""), client_geographicalContext_geolocation_lat_d, client_geographicalContext_geolocation_lon_d, authenticationContext_externalSessionId_s;
let HighRiskEvents = OktaSSO
| where eventType_s in ('policy.evaluate_sign_on' , 'user.session.start')
| extend debugContext_debugData_logOnlySecurityData_s = column_ifexists('debugContext_debugData_logOnlySecurityData_s', '{}')
| where parse_json(tostring(parse_json(debugContext_debugData_logOnlySecurityData_s).risk)).level =~ "HIGH"
| where outcome_result_s =~ 'SUCCESS'
| extend reasons = tostring(parse_json(tostring(parse_json(debugContext_debugData_logOnlySecurityData_s).risk)).reasons)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by actor_alternateId_s, actor_displayName_s, client_userAgent_os_s, client_userAgent_browser_s, client_device_s, client_userAgent_rawUserAgent_s, client_ipAddress_s, client_geographicalContext_country_s, client_geographicalContext_city_s, displayMessage_s, outcome_result_s, outcome_reason_s, column_ifexists('debugContext_debugData_logOnlySecurityData_s', ""), column_ifexists('debugContext_debugData_threatSuspected_s', ""), client_geographicalContext_geolocation_lat_d, client_geographicalContext_geolocation_lon_d, authenticationContext_externalSessionId_s, reasons;
AdminOperations
| join kind=inner (HighRiskEvents) on actor_displayName_s, client_ipAddress_s, authenticationContext_externalSessionId_s
| project StartTime, EndTime, actor_alternateId_s, actor_displayName_s, client_userAgent_os_s, client_userAgent_browser_s, client_device_s, client_userAgent_rawUserAgent_s, client_ipAddress_s, client_geographicalContext_country_s, client_geographicalContext_city_s, displayMessage_s, outcome_result_s, outcome_reason_s, column_ifexists('debugContext_debugData_logOnlySecurityData_s', ""), column_ifexists('debugContext_debugData_threatSuspected_s', ""), client_geographicalContext_geolocation_lat_d, client_geographicalContext_geolocation_lon_d, authenticationContext_externalSessionId_s, reasons
| extend AccountName = tostring(split(actor_alternateId_s, "@")[0]), AccountUPNSuffix = tostring(split(actor_alternateId_s, "@")[1])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: AccountUPNSuffix
- entityType: IP
fieldMappings:
- identifier: Address
columnName: client_ipAddress_s
customDetails:
SessionId: authenticationContext_externalSessionId_s
AdminDisplayName: actor_displayName_s
AdminDeviceOS: client_userAgent_os_s
AdminDevice: client_device_s
UserAgent: client_userAgent_rawUserAgent_s
alertDetailsOverride:
alertDisplayNameFormat: 'High-Risk admin activity by {{actor_displayName_s}} from IP {{client_ipAddress_s}}'
alertDescriptionFormat: 'High-risk Okta activity by {{actor_displayName_s}} from IP {{client_ipAddress_s}} correlated with admin action during session {{authenticationContext_externalSessionId_s}}'
version: 1.1.3
kind: Scheduled
Stages and Predicates
Parameters
let AllowedAdmins = dynamic([]);
let AdminOperations is inlined into the numbered stages below.
Let Binding: AdminActivity
let AdminActivity = dynamic(["iam.role.create","iam.role.permissions.add","user.session.access_admin_app","user.mfa.factor.suspend", "user.account.privilege.grant", "group.privilege.grant", "system.api_token.create", "user.session.impersonation.grant"]);
Let Binding: HighRiskEvents
let HighRiskEvents = OktaSSO
| where eventType_s in ('policy.evaluate_sign_on' , 'user.session.start')
| extend debugContext_debugData_logOnlySecurityData_s = column_ifexists('debugContext_debugData_logOnlySecurityData_s', '{}')
| where parse_json(tostring(parse_json(debugContext_debugData_logOnlySecurityData_s).risk)).level =~ "HIGH"
| where outcome_result_s =~ 'SUCCESS'
| extend reasons = tostring(parse_json(tostring(parse_json(debugContext_debugData_logOnlySecurityData_s).risk)).reasons)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by actor_alternateId_s, actor_displayName_s, client_userAgent_os_s, client_userAgent_browser_s, client_device_s, client_userAgent_rawUserAgent_s, client_ipAddress_s, client_geographicalContext_country_s, client_geographicalContext_city_s, displayMessage_s, outcome_result_s, outcome_reason_s, column_ifexists('debugContext_debugData_logOnlySecurityData_s', ""), column_ifexists('debugContext_debugData_threatSuspected_s', ""), client_geographicalContext_geolocation_lat_d, client_geographicalContext_geolocation_lon_d, authenticationContext_externalSessionId_s, reasons;
Stages 1 to 5 define let AdminOperations as the rule's main pipeline source. Stages 6 to 8 use it.
Stage 1: source
OktaSSO
Stage 2: where
| where actor_alternateId_s !in (AllowedAdmins)
Stage 3: where
| where eventType_s in (AdminActivity)
Stage 4: where
| where outcome_result_s =~ 'SUCCESS'
Stage 5: summarize
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by actor_alternateId_s, actor_displayName_s, client_userAgent_os_s, client_userAgent_browser_s, client_device_s, client_userAgent_rawUserAgent_s, client_ipAddress_s, client_geographicalContext_country_s, client_geographicalContext_city_s, displayMessage_s, outcome_result_s, outcome_reason_s, column_ifexists('debugContext_debugData_logOnlySecurityData_s', ""), column_ifexists('debugContext_debugData_threatSuspected_s', ""), client_geographicalContext_geolocation_lat_d, client_geographicalContext_geolocation_lon_d, authenticationContext_externalSessionId_s
Stage 6: join
AdminOperations
| join kind=inner (HighRiskEvents) on actor_displayName_s, client_ipAddress_s, authenticationContext_externalSessionId_s
Stage 7: project
project EndTime, StartTime, actor_alternateId_s, actor_displayName_s, authenticationContext_externalSessionId_s, client_device_s, client_geographicalContext_city_s, client_geographicalContext_country_s, client_geographicalContext_geolocation_lat_d, client_geographicalContext_geolocation_lon_d, client_ipAddress_s, client_userAgent_browser_s, client_userAgent_os_s, client_userAgent_rawUserAgent_s, displayMessage_s, outcome_reason_s, outcome_result_s, reasons
Stage 8: extend
extend AccountName, AccountUPNSuffix
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
debugContext_debugData_logOnlySecurityData_s.risk.level | eq |
| field:"debugContext_debugData_logOnlySecurityData_s.risk.level" kind:eq value:"HIGH" |
eventType_s | in |
| field:"okta::eventType" kind:in |
outcome_result_s | eq |
| field:"okta::outcome.result" kind:eq |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
actor_alternateId_s | eq | [] | excludes:actor_alternateId_s field:"actor_alternateId_s" value:"[]" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
EndTime | project |
StartTime | project |
actor_alternateId_s | project |
actor_displayName_s | project |
authenticationContext_externalSessionId_s | project |
client_device_s | project |
client_geographicalContext_city_s | project |
client_geographicalContext_country_s | project |
client_geographicalContext_geolocation_lat_d | project |
client_geographicalContext_geolocation_lon_d | project |
client_ipAddress_s | project |
client_userAgent_browser_s | project |
client_userAgent_os_s | project |
client_userAgent_rawUserAgent_s | project |
displayMessage_s | project |
outcome_reason_s | project |
outcome_result_s | project |
reasons | project |
AccountName | extend |
AccountUPNSuffix | extend |
Palo Alto - potential beaconing detected
#'Identifies beaconing patterns from Palo Alto Network traffic logs based on recurrent timedelta patterns. The query leverages various KQL functions to calculate time deltas and then compares it with total events observed in a day to find percentage of beaconing. This outbound beaconing pattern to untrusted public networks should be investigated for any malware callbacks or data exfiltration attempts. Reference Blog: https://medium.com/@HuntOperator/detect-beaconing-with-flare-elastic-stack-and-intrusion-detection-systems-110dc74e0c56 https://techcommunity.microsoft.com/t5/microsoft-sentinel-blog/detect-network-beaconing-via-intra-request-time-delta-patterns/ba-p/779586'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Command & Control |
Rule Body
id: f0be259a-34ac-4946-aa15-ca2b115d5feb
name: Palo Alto - potential beaconing detected
description: |
'Identifies beaconing patterns from Palo Alto Network traffic logs based on recurrent timedelta patterns.
The query leverages various KQL functions to calculate time deltas and then compares it with total events observed in a day to find percentage of beaconing.
This outbound beaconing pattern to untrusted public networks should be investigated for any malware callbacks or data exfiltration attempts.
Reference Blog:
https://medium.com/@HuntOperator/detect-beaconing-with-flare-elastic-stack-and-intrusion-detection-systems-110dc74e0c56
https://techcommunity.microsoft.com/t5/microsoft-sentinel-blog/detect-network-beaconing-via-intra-request-time-delta-patterns/ba-p/779586'
severity: Low
status: Available
requiredDataConnectors:
- connectorId: CefAma
dataTypes:
- CommonSecurityLog
queryFrequency: 1d
queryPeriod: 2d
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandAndControl
relevantTechniques:
- T1071
- T1571
query: |
let starttime = 2d;
let endtime = 1d;
let TimeDeltaThreshold = 25;
let TotalEventsThreshold = 30;
let MostFrequentTimeDeltaThreshold = 25;
let PercentBeaconThreshold = 80;
CommonSecurityLog
| where DeviceVendor == "Palo Alto Networks" and Activity == "TRAFFIC"
| where TimeGenerated between (startofday(ago(starttime))..startofday(ago(endtime)))
| where ipv4_is_private(DestinationIP)== false
| project TimeGenerated, DeviceName, SourceUserID, SourceIP, SourcePort, DestinationIP, DestinationPort, ReceivedBytes, SentBytes
| sort by SourceIP asc,TimeGenerated asc, DestinationIP asc, DestinationPort asc
| serialize
| extend nextTimeGenerated = next(TimeGenerated, 1), nextSourceIP = next(SourceIP, 1)
| extend TimeDeltainSeconds = datetime_diff('second',nextTimeGenerated,TimeGenerated)
| where SourceIP == nextSourceIP
//Whitelisting criteria/ threshold criteria
| where TimeDeltainSeconds > TimeDeltaThreshold
| summarize count(), sum(ReceivedBytes), sum(SentBytes)
by TimeDeltainSeconds, bin(TimeGenerated, 1h), DeviceName, SourceUserID, SourceIP, DestinationIP, DestinationPort
| summarize (MostFrequentTimeDeltaCount, MostFrequentTimeDeltainSeconds) = arg_max(count_, TimeDeltainSeconds), TotalEvents=sum(count_), TotalSentBytes = sum(sum_SentBytes), TotalReceivedBytes = sum(sum_ReceivedBytes)
by bin(TimeGenerated, 1h), DeviceName, SourceUserID, SourceIP, DestinationIP, DestinationPort
| where TotalEvents > TotalEventsThreshold and MostFrequentTimeDeltaCount > MostFrequentTimeDeltaThreshold
| extend BeaconPercent = MostFrequentTimeDeltaCount/toreal(TotalEvents) * 100
| where BeaconPercent > PercentBeaconThreshold
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: SourceUserID
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: DeviceName
- entityType: IP
fieldMappings:
- identifier: Address
columnName: DestinationIP
version: 1.0.7
kind: Scheduled
Stages and Predicates
Parameters
let starttime = 2d;
let endtime = 1d;
let TimeDeltaThreshold = 25;
let TotalEventsThreshold = 30;
let MostFrequentTimeDeltaThreshold = 25;
let PercentBeaconThreshold = 80;
Stage 1: source
CommonSecurityLog
Stage 2: where
| where DeviceVendor == "Palo Alto Networks" and Activity == "TRAFFIC"
Stage 3: where
| where TimeGenerated between (startofday(ago(starttime))..startofday(ago(endtime)))
Stage 4: where
| where ipv4_is_private(DestinationIP)== false
Stage 5: project
| project TimeGenerated, DeviceName, SourceUserID, SourceIP, SourcePort, DestinationIP, DestinationPort, ReceivedBytes, SentBytes
Stage 6: sort
| sort by SourceIP asc,TimeGenerated asc, DestinationIP asc, DestinationPort asc
Stage 7: kusto:serialize
| serialize
Stage 8: extend
| extend nextTimeGenerated = next(TimeGenerated, 1), nextSourceIP = next(SourceIP, 1)
Stage 9: extend
| extend TimeDeltainSeconds = datetime_diff('second',nextTimeGenerated,TimeGenerated)
Stage 10: where
| where SourceIP == nextSourceIP
Stage 11: where
| where TimeDeltainSeconds > TimeDeltaThreshold
Stage 12: summarize
| summarize count(), sum(ReceivedBytes), sum(SentBytes)
by TimeDeltainSeconds, bin(TimeGenerated, 1h), DeviceName, SourceUserID, SourceIP, DestinationIP, DestinationPort
Stage 13: summarize
| summarize (MostFrequentTimeDeltaCount, MostFrequentTimeDeltainSeconds) = arg_max(count_, TimeDeltainSeconds), TotalEvents=sum(count_), TotalSentBytes = sum(sum_SentBytes), TotalReceivedBytes = sum(sum_ReceivedBytes)
by bin(TimeGenerated, 1h), DeviceName, SourceUserID, SourceIP, DestinationIP, DestinationPort
Stage 14: where
| where TotalEvents > TotalEventsThreshold and MostFrequentTimeDeltaCount > MostFrequentTimeDeltaThreshold
Stage 15: extend
| extend BeaconPercent = MostFrequentTimeDeltaCount/toreal(TotalEvents) * 100
Stage 16: where
| where BeaconPercent > PercentBeaconThreshold
Indicators
These rows show field, operator, and value matches.
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
DestinationIP | 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:DestinationIP |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DestinationIP | summarize |
DestinationPort | summarize |
DeviceName | summarize |
MostFrequentTimeDeltaCount | summarize |
MostFrequentTimeDeltainSeconds | summarize |
SourceIP | summarize |
SourceUserID | summarize |
TotalEvents | summarize |
TotalReceivedBytes | summarize |
TotalSentBytes | summarize |
BeaconPercent | extend |
Pathlock TDnR - Emergency User (AdminTrack) Activity
#Detects activity from emergency user accounts tracked by Pathlock AdminTrack in SAP, forwarded by Pathlock Threat Detection and Response. Emergency user (firefighter) account usage should always be reviewed as these accounts carry broad privileges and any unauthorized or unreviewed use may indicate insider threat or account takeover.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Persistence | |
| Privilege Escalation |
Rule Body
id: 2a3b4c5d-6e7f-4a0b-8c1d-2e3f4a5b6c50
name: Pathlock TDnR - Emergency User (AdminTrack) Activity
kind: Scheduled
description: >-
Detects activity from emergency user accounts tracked by Pathlock AdminTrack in SAP,
forwarded by Pathlock Threat Detection and Response. Emergency user (firefighter) account usage
should always be reviewed as these accounts carry broad privileges and any unauthorized or
unreviewed use may indicate insider threat or account takeover.
severity: High
status: Available
requiredDataConnectors:
- connectorId: Pathlock_TDnR
dataTypes:
- Pathlock_TDnR_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
- PrivilegeEscalation
relevantTechniques:
- T1078
- T1548
query: |
Pathlock_TDnR_CL
| where DataSource == "SAST_AT"
| 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 == "SAST_AT"
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:"SAST_AT" |
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 |
Pathlock TDnR - SAP BTP Cloud Foundry Events
#Detects security events from SAP BTP Cloud Foundry environments, forwarded by Pathlock Threat Detection and Response. Anomalous BTP Cloud Foundry activity may indicate unauthorized application deployments, service account abuse, or data exfiltration from cloud-native SAP workloads.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Discovery |
Rule Body
id: 2a3b4c5d-6e7f-4a0b-8c1d-2e3f4a5b6c22
name: Pathlock TDnR - SAP BTP Cloud Foundry Events
kind: Scheduled
description: >-
Detects security events from SAP BTP Cloud Foundry environments, forwarded by Pathlock Threat
Detection and Response. Anomalous BTP Cloud Foundry activity may indicate unauthorized application
deployments, service account abuse, or data exfiltration from cloud-native SAP workloads.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: Pathlock_TDnR
dataTypes:
- Pathlock_TDnR_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Discovery
relevantTechniques:
- T1082
query: |
Pathlock_TDnR_CL
| where DataSource == "CLOUD_FOUNDRY_LOGS"
| 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 == "CLOUD_FOUNDRY_LOGS"
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:"CLOUD_FOUNDRY_LOGS" |
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 |
Pathlock TDnR - Spool Job Changes
#Detects changes to SAP spool jobs, forwarded by Pathlock Threat Detection and Response. Unauthorized spool job manipulations may indicate tampering with scheduled output, redirection of sensitive reports, or data collection activity involving SAP output management.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Collection |
Rule Body
id: 2a3b4c5d-6e7f-4a0b-8c1d-2e3f4a5b6c61
name: Pathlock TDnR - Spool Job Changes
kind: Scheduled
description: >-
Detects changes to SAP spool jobs, forwarded by Pathlock Threat Detection and Response.
Unauthorized spool job manipulations may indicate tampering with scheduled output, redirection
of sensitive reports, or data collection activity involving SAP output management.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: Pathlock_TDnR
dataTypes:
- Pathlock_TDnR_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Collection
relevantTechniques:
- T1213
query: |
Pathlock_TDnR_CL
| where DataSource == "SPOOL_REQUEST"
| 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 == "SPOOL_REQUEST"
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:"SPOOL_REQUEST" |
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 |
Rare client observed with high reverse DNS lookup count - Anomaly based (ASIM DNS Solution)
#This rule makes use of the series decompose anomaly method to identify clients with high reverse DNS counts. This helps in detecting the possible initial phases of an attack, like discovery and reconnaissance. It utilizes ASIM normalization and is applied to any source that supports the ASIM DNS schema.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Reconnaissance |
Telemetry Coverage
| Provider | Record / event type |
|---|---|
| Sysmon | Event ID 22: DNSEvent (DNS query) |
Rule Body
id: 0fe6bde4-b215-480c-99b4-84a96edcdbd7
name: Rare client observed with high reverse DNS lookup count - Anomaly based (ASIM DNS Solution)
description: |
'This rule makes use of the series decompose anomaly method to identify clients with high reverse DNS counts. This helps in detecting the possible initial phases of an attack, like discovery and reconnaissance. It utilizes [ASIM](https://aka.ms/AboutASIM) normalization and is applied to any source that supports the ASIM DNS schema.'
severity: Medium
status: Available
tags:
- Schema: ASimDns
SchemaVersion: 0.1.6
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Reconnaissance
relevantTechniques:
- T1590
query: |
let threshold = 2.5;
let SearchDomain = dynamic(["in-addr.arpa"]);
let min_t = ago(14d);
let max_t = now();
let timeframe = 1d;
let DNSEvents=(stime: datetime, etime: datetime) {
_Im_Dns(starttime=stime, endtime=etime, domain_has_any=SearchDomain)
};
DNSEvents(stime=min_t, etime=max_t)
| make-series QueryCount=dcount(DnsQuery) on TimeGenerated from min_t to max_t step timeframe by SrcIpAddr
| extend (anomalies, score, baseline) = series_decompose_anomalies(QueryCount, threshold, -1, 'linefit')
| mv-expand anomalies, score, baseline, TimeGenerated, QueryCount
| extend
anomalies = toint(anomalies),
score = toint(score),
baseline = toint(baseline),
EventTime = todatetime(TimeGenerated),
Total = tolong(QueryCount)
| where EventTime >= ago(timeframe)
| where score >= threshold * 2
| join kind = inner (DNSEvents(stime=ago(timeframe), etime=max_t)
| summarize DNSQueries=make_set(DnsQuery, 1000) by SrcIpAddr)
on SrcIpAddr
| project-away SrcIpAddr1
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SrcIpAddr
eventGroupingSettings:
aggregationKind: AlertPerResult
customDetails:
DNSQueries: DNSQueries
AnomalyScore: score
baseline: baseline
Total: Total
alertDetailsOverride:
alertDisplayNameFormat: "[Anomaly] Rare client has been observed as making high reverse DNS lookup count - client IP: '{{SrcIpAddr}}'"
alertDescriptionFormat: "Client has been identified as making high reverse DNS counts which could be carrying out reconnaissance or discovery activity.\n\nReverse DNS lookup count baseline for this client: '{{baseline}}'\n\nCurrent reverse DNS lookup count by this client showing as: '{{Total}}'\n\nDNS queries requested by this client inlcude: '{{DNSQueries}}'"
version: 1.0.2
kind: Scheduled
Stages and Predicates
Parameters
let threshold = 2.5;
let SearchDomain = dynamic(["in-addr.arpa"]);
let min_t = ago(14d);
let max_t = now();
let timeframe = 1d;
Let Binding: DNSEvents
let DNSEvents = (stime: datetime, etime: datetime) {
_Im_Dns(starttime=stime, endtime=etime, domain_has_any=SearchDomain)
};
Stage 1: source
DNSEvents(stime=min_t, etime=max_t)
The stages below score time-series anomalies (make-series, series_decompose_anomalies).
Stage 2: make-series
| make-series QueryCount=dcount(DnsQuery) on TimeGenerated from min_t to max_t step timeframe by SrcIpAddr
Stage 3: extend
| extend (anomalies, score, baseline) = series_decompose_anomalies(QueryCount, threshold, -1, 'linefit')
Stage 4: mv-expand
| mv-expand anomalies, score, baseline, TimeGenerated, QueryCount
Stage 5: extend
| extend
anomalies = toint(anomalies),
score = toint(score),
baseline = toint(baseline),
EventTime = todatetime(TimeGenerated),
Total = tolong(QueryCount)
Stage 6: where
| where EventTime >= ago(timeframe)
Stage 7: where
| where score >= threshold * 2
Stage 8: join
| join kind = inner (DNSEvents(stime=ago(timeframe), etime=max_t)
| summarize DNSQueries=make_set(DnsQuery, 1000) by SrcIpAddr)
on SrcIpAddr
Stage 9: project-away
project-away SrcIpAddr1
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
score | ge |
| field:"score" kind:ge value:"5" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
QueryCount | summarize |
SrcIpAddr | summarize |
anomalies | extend |
baseline | extend |
score | extend |
EventTime | extend |
Total | extend |
TI Map URL Entity to UrlClickEvents
#This query identifies any URL indicators of compromise (IOCs) from threat intelligence (TI) by searching for matches in UrlClickEvents.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Command & Control |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Microsoft Defender for Endpoint | UrlClickEvents action any: URL click activity |
Rule Body
id: 23391c84-87d8-452f-a84c-47a62f01e115
name: TI Map URL Entity to UrlClickEvents
description: |
'This query identifies any URL indicators of compromise (IOCs) from threat intelligence (TI) by searching for matches in UrlClickEvents.'
severity: Medium
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- UrlClickEvents
- connectorId: ThreatIntelligence
dataTypes:
- ThreatIntelligenceIndicator
- connectorId: ThreatIntelligenceTaxii
dataTypes:
- ThreatIntelligenceIndicator
- connectorId: MicrosoftDefenderThreatIntelligence
dataTypes:
- ThreatIntelligenceIndicator
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandAndControl
relevantTechniques:
- T1071
query: |
let dt_lookBack = 1h;
let ioc_lookBack = 14d;
let UrlClickEvents_ = materialize(UrlClickEvents
| where TimeGenerated >= ago(dt_lookBack)
| extend UrlClickEvents_TimeGenerated = TimeGenerated);
let ChainReportID = UrlClickEvents_
| mv-expand todynamic(UrlChain)
| extend UrlChain = tolower(UrlChain)
| project ReportId, Url, UrlChain;
// Url is not always in UrlChain, so we need to check both
let ClickedUrls =
(union isfuzzy=false (ChainReportID), (ChainReportID | project Url = UrlChain))
| distinct Url
| summarize make_list(Url);
let TI = materialize(ThreatIntelligenceIndicator
| where TimeGenerated >= ago(ioc_lookBack)
| where isnotempty(Url) and tolower(Url) in (ClickedUrls)
| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
| where Active == true and ExpirationDateTime > now()
| project-rename TI_Url = Url, TI_Type = Type
);
(union isfuzzy=false (TI | join kind=innerunique (ChainReportID) on $left.TI_Url == $right.UrlChain),
(TI | join kind=innerunique (ChainReportID) on $left.TI_Url == $right.Url))
| project-away UrlChain
| join kind=innerunique (UrlClickEvents_) on ReportId
| where UrlClickEvents_TimeGenerated < ExpirationDateTime
| summarize UrlClickEvents_TimeGenerated = arg_max(UrlClickEvents_TimeGenerated, *) by IndicatorId
| project UrlClickEvents_TimeGenerated, AccountUpn, Description, ActivityGroupNames, IndicatorId, ThreatType, ExpirationDateTime, ConfidenceScore, Url, NetworkMessageId
| extend timestamp = UrlClickEvents_TimeGenerated
| extend timestamp = UrlClickEvents_TimeGenerated, Name = tostring(split(AccountUpn, '@', 0)[0]), UPNSuffix = tostring(split(AccountUpn, '@', 1)[0])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountUpn
- identifier: Name
columnName: Name
- identifier: UPNSuffix
columnName: UPNSuffix
- entityType: URL
fieldMappings:
- identifier: Url
columnName: Url
version: 1.0.2
kind: Scheduled
Stages and Predicates
Parameters
let dt_lookBack = 1h;
let ioc_lookBack = 14d;
Let Binding: UrlClickEvents_
let UrlClickEvents_ = materialize(UrlClickEvents
| where TimeGenerated >= ago(dt_lookBack)
| extend UrlClickEvents_TimeGenerated = TimeGenerated);
Let Binding: ChainReportID
let ChainReportID = UrlClickEvents_
| mv-expand todynamic(UrlChain)
| extend UrlChain = tolower(UrlChain)
| project ReportId, Url, UrlChain;
Let Binding: ClickedUrls
let ClickedUrls = (union isfuzzy=false (ChainReportID), (ChainReportID | project Url = UrlChain))
| distinct Url
| summarize make_list(Url);
Union isfuzzy=false (2 Sources)
Each leg below queries one source; the rule matches if any leg does. Sources: TI, TI
Leg 1: TI
TI | join kind=innerunique (ChainReportID) on $left.TI_Url == $right.UrlChain
Leg 2: TI
TI | join kind=innerunique (ChainReportID) on $left.TI_Url == $right.Url
Applied to the Combined Result
| project-away UrlChain
| join kind=innerunique (UrlClickEvents_) on ReportId
| where UrlClickEvents_TimeGenerated < ExpirationDateTime
| summarize UrlClickEvents_TimeGenerated = arg_max(UrlClickEvents_TimeGenerated, *) by IndicatorId
| project UrlClickEvents_TimeGenerated, AccountUpn, Description, ActivityGroupNames, IndicatorId, ThreatType, ExpirationDateTime, ConfidenceScore, Url, NetworkMessageId
| extend timestamp = UrlClickEvents_TimeGenerated
| extend timestamp = UrlClickEvents_TimeGenerated, Name = tostring(split(AccountUpn, '@', 0)[0]), UPNSuffix = tostring(split(AccountUpn, '@', 1)[0])
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Active | eq |
| field:"Active" kind:eq value:"true" |
Url | in |
| field:"Url" kind:in value:"ClickedUrls" |
Url | is_not_null | field:"Url" kind:is_not_null |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AccountUpn | project |
ActivityGroupNames | project |
ConfidenceScore | project |
Description | project |
ExpirationDateTime | project |
IndicatorId | project |
NetworkMessageId | project |
ThreatType | project |
Url | project |
UrlClickEvents_TimeGenerated | project |
timestamp | extend |
Name | extend |
UPNSuffix | extend |
Tomcat - Sql injection patterns
#'Detects possible sql injection patterns'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: ce84741e-4875-11ec-81d3-0242ac130003
name: Tomcat - Sql injection patterns
description: |
'Detects possible sql injection patterns'
severity: High
status: Available
requiredDataConnectors:
- connectorId: CustomLogsAma
datatypes:
- Tomcat_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1190
query: |
let commands = dynamic(["1/*'*/", "1'||'asd'||'", "'1'='1", "1' or '1'='1", "1 or 1=1", "1=1", "1/*!1111'*/", "'or''='"]);
TomcatEvent
| where UrlOriginal has_any (commands)
| extend UrlCustomEntity = UrlOriginal
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: UrlCustomEntity
version: 1.0.2
kind: Scheduled
Stages and Predicates
Let Binding: commands
let commands = dynamic(["1/*'*/", "1'||'asd'||'", "'1'='1", "1' or '1'='1", "1 or 1=1", "1=1", "1/*!1111'*/", "'or''='"]);
Stage 1: source
TomcatEvent
Stage 2: where
| where UrlOriginal has_any (commands)
Stage 3: extend
| extend UrlCustomEntity = UrlOriginal
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
UrlOriginal | match |
| field:"UrlOriginal" kind:match |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
UrlCustomEntity | extend |
Uniqkey - Excessive credential access
#Detects an actor reading an abnormally large number of credentials from Uniqkey within a single hour (default threshold: more than 50 access events). Bulk credential reads are rarely part of normal daily work and can indicate a compromised session harvesting secrets, or an insider collecting credentials ahead of departure. Tune the threshold to your organization's baseline, and consider a lower threshold for actors of type scim or system that normally never read credentials interactively.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Credential Access |
Rule Body
id: 755c7adb-1015-4be3-9e56-55e72009c088
name: Uniqkey - Excessive credential access
version: 1.0.0
kind: Scheduled
description: |-
Detects an actor reading an abnormally large number of credentials from Uniqkey within a single hour (default threshold: more than 50 access events). Bulk credential reads are rarely part of normal daily work and can indicate a compromised session harvesting secrets, or an insider collecting credentials ahead of departure. Tune the threshold to your organization's baseline, and consider a lower threshold for actors of type scim or system that normally never read credentials interactively.
severity: Medium
requiredDataConnectors:
- connectorId: UniqkeyEventsConnector
dataTypes:
- UniqkeyEvents_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- CredentialAccess
relevantTechniques:
- T1555
query: |-
let threshold = 50;
UniqkeyEvents_CL
| where Category == "credential_access"
| summarize AccessCount = count(), DistinctTargets = dcount(TargetId), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), SrcIpAddr = take_any(SrcIpAddr) by ActorEmail, ActorType
| where AccessCount > threshold
| project StartTime, EndTime, ActorEmail, ActorType, AccessCount, DistinctTargets, SrcIpAddr
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: ActorEmail
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SrcIpAddr
suppressionEnabled: false
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: 1h
matchingMethod: AllEntities
suppressionDuration: 5h
eventGroupingSettings:
aggregationKind: AlertPerResult
Stages and Predicates
Parameters
let threshold = 50;
Stage 1: source
UniqkeyEvents_CL
Stage 2: where
| where Category == "credential_access"
Stage 3: summarize
| summarize AccessCount = count(), DistinctTargets = dcount(TargetId), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), SrcIpAddr = take_any(SrcIpAddr) by ActorEmail, ActorType
Stage 4: where
| where AccessCount > threshold
Stage 5: project
| project StartTime, EndTime, ActorEmail, ActorType, AccessCount, DistinctTargets, SrcIpAddr
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
AccessCount | gt |
| field:"AccessCount" kind:gt value:"50" |
Category | eq |
| field:"Category" kind:eq value:"credential_access" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AccessCount | project |
ActorEmail | project |
ActorType | project |
DistinctTargets | project |
EndTime | project |
SrcIpAddr | project |
StartTime | project |
Vectra RUX - Create Incident for Escalated Host Detection or Unresolved Priority Host
#This query creates a Microsoft Sentinel incident when a detection on a host entity has been escalated in Vectra (investigation_status = escalated). Escalation indicates that a human analyst or MDR service has reviewed the detection and determined it requires immediate host attention or notification. One incident is created per detection - grouping is based on alert display name so that repeated rule evaluations against the same detection do not create duplicate incidents. This query creates a Microsoft Sentinel incident when Vectra AI identifies a host entity with one or more detections marked as unresolved and prioritized (unresolved_priority = true). Vectra's AI engine assigns priority based on attack rating, velocity, breadth, and host privilege level. This rule surfaces host-based threats that require analyst attention. Incidents are grouped per host entity and remain open while the threat persists. Once all associated detections are resolved in Vectra, the incident can be closed in Microsoft Sentinel.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Credential Access | |
| Discovery | |
| Lateral Movement | |
| Command & Control | |
| Exfiltration |
Rule Body
id: 231904f5-b670-4223-9bec-2e9aeca9cf5b
name: Vectra RUX - Create Incident for Escalated Host Detection or Unresolved Priority Host
version: 1.0.0
kind: Scheduled
description: |
This query creates a Microsoft Sentinel incident when a detection on a host entity has been escalated in Vectra
(investigation_status = escalated). Escalation indicates that a human analyst or MDR service
has reviewed the detection and determined it requires immediate host attention or notification.
One incident is created per detection - grouping is based on alert display name so that
repeated rule evaluations against the same detection do not create duplicate incidents.
This query creates a Microsoft Sentinel incident when Vectra AI identifies a host entity with one or more detections
marked as unresolved and prioritized (unresolved_priority = true). Vectra's AI engine assigns
priority based on attack rating, velocity, breadth, and host privilege level. This rule surfaces
host-based threats that require analyst attention.
Incidents are grouped per host entity and remain open while the threat persists. Once all associated
detections are resolved in Vectra, the incident can be closed in Microsoft Sentinel.
status: Available
requiredDataConnectors:
- connectorId: VectraRUXConnector
dataTypes:
- VectraDetectionsCombined
severity: High
queryFrequency: 10m
queryPeriod: 10m
suppressionDuration: PT1H
suppressionEnabled: false
triggerOperator: GreaterThan
triggerThreshold: 0
tactics:
- Discovery
- LateralMovement
- CredentialAccess
- Exfiltration
- CommandAndControl
- Persistence
relevantTechniques:
- T1046
- T1021
- T1003
- T1041
- T1071
query: |
VectraDetectionsCombined
| where ["Entity Type"] == "host"
| summarize arg_max(TimeGenerated, *) by ["Detection ID"]
| where ["Investigation Status"] == "escalated" or ["Unresolved Priority"] == true
| extend
detection_name = ["D Type Vname"],
detection_category = ["Detection Category"],
entity_url = replace_string(replace_string(URL, "api/v3.4/", ""), "api/v3.5/", ""),
mitre_techniques = tostring(Mitre),
detection_tags = tostring(Tags),
assigned_to = ["Assigned To"],
entity_name = ["Entity Name"],
entity_uid = ["Entity UID"],
entity_id = ["Entity ID"],
detection_id = ["Detection ID"],
external_reference = ["External Reference ID"],
investigation_status = ["Investigation Status"],
entity_type = ["Entity Type"]
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: entity_name
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: P7D
matchingMethod: Selected
groupByEntities:
- Host
groupByAlertDetails:
- DisplayName
customDetails:
detection_name: detection_name
assigned_to: assigned_to
entity_uid: entity_uid
entity_url: entity_url
entity_id: entity_id
detection_id: detection_id
external_reference: external_reference
investigation_status: investigation_status
category: detection_category
tags: detection_tags
mitre_techniques: mitre_techniques
entity_type: entity_type
alertDetailsOverride:
alertDisplayNameFormat: "Vectra AI - {{detection_name}} on {{entity_name}}"
alertDescriptionFormat: >
Vectra AI has escalated detection {{detection_name}} ({{detection_category}}) on host or identified
host {{entity_name}} as a priority threat. See custom details for full context.
alertDynamicProperties:
- alertProperty: AlertLink
value: entity_url
- alertProperty: Techniques
value: mitre_techniques
eventGroupingSettings:
aggregationKind: AlertPerResult
Stages and Predicates
Stage 1: source
VectraDetectionsCombined
Stage 2: where
| where ["Entity Type"] == "host"
Stage 3: summarize
| summarize arg_max(TimeGenerated, *) by ["Detection ID"]
Stage 4: where
| where ["Investigation Status"] == "escalated" or ["Unresolved Priority"] == true
Stage 5: extend
| extend
detection_name = ["D Type Vname"],
detection_category = ["Detection Category"],
entity_url = replace_string(replace_string(URL, "api/v3.4/", ""), "api/v3.5/", ""),
mitre_techniques = tostring(Mitre),
detection_tags = tostring(Tags),
assigned_to = ["Assigned To"],
entity_name = ["Entity Name"],
entity_uid = ["Entity UID"],
entity_id = ["Entity ID"],
detection_id = ["Detection ID"],
external_reference = ["External Reference ID"],
investigation_status = ["Investigation Status"],
entity_type = ["Entity Type"]
Indicators
These rows show field, operator, and value matches.
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
assigned_to | extend |
detection_category | extend |
detection_id | extend |
detection_name | extend |
detection_tags | extend |
entity_id | extend |
entity_name | extend |
entity_type | extend |
entity_uid | extend |
entity_url | extend |
external_reference | extend |
investigation_status | extend |
mitre_techniques | extend |
Virtual Lab Settings Updated
#Detects when virtual lab settings are updated in Veeam Backup & Replication. This might indicate configuration changes that require review.
Rule Body
id: a21eccd5-0148-4f88-a5d7-a8f86e9e4d8e
name: Virtual Lab Settings Updated
description: Detects when virtual lab settings are updated in Veeam Backup & Replication.
This might indicate configuration changes that require review.
severity: Low
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 == 30700\n| project\n Date\
\ = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),\n DataSource = original_host,\n\
\ EventId = instanceId,\n [\"User Name\"] = user,\n MessageDetails = Description,\n\
\ Severity = SeverityDescription"
version: 1.0.1
kind: Scheduled
customDetails:
Date: Date
VbrHostName: DataSource
EventId: EventId
MessageDetails: MessageDetails
Severity: Severity
Stages and Predicates
Stage 1: source
Veeam_GetSecurityEvents
Stage 2: where
| where instanceId == 30700
Stage 3: project
| project
Date = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),
DataSource = original_host,
EventId = instanceId,
["User Name"] = user,
MessageDetails = Description,
Severity = SeverityDescription
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
instanceId | eq |
| field:"instanceId" kind:eq value:"30700" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DataSource | project |
Date | project |
EventId | project |
MessageDetails | project |
Severity | project |
User Name | project |
Whisper Security - Newly Registered Domain on Threat ASN
#Identifies newly registered domains (under 7 days old) hosted on autonomous systems with elevated threat scores. This combination often indicates adversary infrastructure staging for phishing, malware delivery, or C2 operations.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Resource Development |
Rule Body
id: 4f80ee8e-901f-538a-8603-cc4b49e80164
name: Whisper Security - Newly Registered Domain on Threat ASN
description: |
Identifies newly registered domains (under 7 days old) hosted on autonomous systems with elevated threat scores. This combination often indicates adversary infrastructure staging for phishing, malware delivery, or C2 operations.
severity: High
status: Available
requiredDataConnectors:
- connectorId: WhisperSecurityConnector
dataTypes:
- WhisperASNReputation_CL
- WhisperInfraContext_CL
queryFrequency: 1h
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- ResourceDevelopment
relevantTechniques:
- T1583
query: |
// MITRE ATT&CK: T1583.001 - Acquire Infrastructure: Domains
// Tactic: Resource Development
// Correlates newly registered domains with high-threat ASN reputation data
let maxDomainAgeDays = 7;
let asnThreatThreshold = 50;
// Defensive: WhisperInfraChainPipeline currently emits domainAge=-1 as a
// sentinel when the create date is unknown (tracked bug - proper fix needs
// CALL whisper.history() integration). Filter the sentinel out so the rule
// does not fire on every domain with an ASN.
let newDomains = WhisperInfraContext_CL
| where TimeGenerated > ago(1d)
| where domainAge >= 0 and domainAge < maxDomainAgeDays
| where isnotempty(asns)
| extend parsedAsn = tostring(split(asns, ",")[0])
| extend parsedIp = tostring(split(ipAddresses, ",")[0])
| project TimeGenerated, indicator, domainAge, parsedAsn, parsedIp, registrar, countries;
let threatAsns = WhisperASNReputation_CL
| where TimeGenerated > ago(1d)
| where maxThreatScore > asnThreatThreshold
| project asn, asnName, reputationScore, reputationLevel, maxThreatScore;
newDomains
| join kind=inner (threatAsns) on $left.parsedAsn == $right.asn
| extend DnsDomain = indicator, IPAddress = parsedIp
| project TimeGenerated, DnsDomain, IPAddress, domainAge, registrar, countries, asn, asnName, reputationScore, reputationLevel, maxThreatScore
entityMappings:
- entityType: DNS
fieldMappings:
- identifier: DomainName
columnName: DnsDomain
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPAddress
customDetails:
DomainAgeDays: domainAge
ASNName: asnName
ReputationScore: reputationScore
MaxThreatScore: maxThreatScore
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: PT5H
matchingMethod: AllEntities
version: 1.0.0
kind: Scheduled
Stages and Predicates
Parameters
let maxDomainAgeDays = 7;
let asnThreatThreshold = 50;
let newDomains is inlined into the numbered stages below.
Let Binding: threatAsns
let threatAsns = WhisperASNReputation_CL
| where TimeGenerated > ago(1d)
| where maxThreatScore > asnThreatThreshold
| project asn, asnName, reputationScore, reputationLevel, maxThreatScore;
Stages 1 to 7 define let newDomains as the rule's main pipeline source. Stages 8 to 10 use it.
Stage 1: source
WhisperInfraContext_CL
Stage 2: where
| where TimeGenerated > ago(1d)
Stage 3: where
| where domainAge >= 0 and domainAge < maxDomainAgeDays
Stage 4: where
| where isnotempty(asns)
Stage 5: extend
| extend parsedAsn = tostring(split(asns, ",")[0])
Stage 6: extend
| extend parsedIp = tostring(split(ipAddresses, ",")[0])
Stage 7: project
| project TimeGenerated, indicator, domainAge, parsedAsn, parsedIp, registrar, countries
Stage 8: join
newDomains
| join kind=inner (threatAsns) on $left.parsedAsn == $right.asn
Stage 9: extend
extend DnsDomain, IPAddress
Stage 10: project
project DnsDomain, IPAddress, TimeGenerated, asn, asnName, countries, domainAge, maxThreatScore, registrar, reputationLevel, reputationScore
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
asns | is_not_null | field:"asns" kind:is_not_null | |
domainAge | ge |
| field:"domainAge" kind:ge value:"0" |
domainAge | lt |
| field:"domainAge" kind:lt value:"7" |
maxThreatScore | gt |
| field:"maxThreatScore" kind:gt value:"50" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DnsDomain | project |
IPAddress | project |
TimeGenerated | project |
asn | project |
asnName | project |
countries | project |
domainAge | project |
maxThreatScore | project |
registrar | project |
reputationLevel | project |
reputationScore | project |