Detection rules › Kusto
Kusto rules: 20
AWSCloudTrail - CloudFormation policy created then used for privilege escalation
#Identifies creation of IAM policies that grant CloudFormation and IAM permissions commonly used for privilege escalation, followed by attachment activity to a user, role, or group. Review whether the new policy and any subsequent attachment were authorized because this pattern can enable an attacker to create or elevate access.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Persistence | |
| Privilege Escalation |
Telemetry Coverage
Rules Detecting the Same Action
These rules filter on the same operation.
- ASL AWS Create Policy Version to allow all resources (Splunk)
- AWS IAM CompromisedKeyQuarantine Policy Attached to User (Elastic)
- AWS Lateral Movement from Kubernetes SA via AssumeRoleWithWebIdentity (Elastic)
- AWSCloudTrail - Created CRUD S3 policy and then privilege escalation (Kusto)
- AWSCloudTrail - Creation of CRUD DynamoDB policy and then privilege escalation (Kusto)
- AWSCloudTrail - Creation of CRUD KMS policy and then privilege escalation (Kusto)
- AWSCloudTrail - Creation of CRUD Lambda policy and then privilege escalation (Kusto)
- AWSCloudTrail - Creation of DataPipeline policy and then privilege escalation (Kusto)
Rule Body
id: efdc3cff-f006-426f-97fd-4657862f7b9a
name: AWSCloudTrail - CloudFormation policy created then used for privilege escalation
description: |
Identifies creation of IAM policies that grant CloudFormation and IAM permissions commonly used for privilege
escalation, followed by attachment activity to a user, role, or group. Review whether the new policy and any
subsequent attachment were authorized because this pattern can enable an attacker to create or elevate access.
severity: High
status: Available
requiredDataConnectors:
- connectorId: AWS
dataTypes:
- AWSCloudTrail
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
- PrivilegeEscalation
- Persistence
relevantTechniques:
- T1484
- T1098.003
query: |
let EventNameList = dynamic(["AttachUserPolicy","AttachRolePolicy","AttachGroupPolicy"]);
let createPolicy = dynamic(["CreatePolicy", "CreatePolicyVersion"]);
let timeframe = 1d;
let lookback = 14d;
// Creating Master table with all the events to use with materialize for better performance
let EventInfo = AWSCloudTrail
| where TimeGenerated >= ago(lookback)
| where EventName in (EventNameList) or EventName in (createPolicy)
| extend UserIdentityArn = iif(isempty(UserIdentityArn), tostring(parse_json(Resources)[0].ARN), UserIdentityArn)
| extend UserName = tostring(split(UserIdentityArn, '/')[-1])
| extend AccountName = case( UserIdentityPrincipalid == "Anonymous", "Anonymous", isempty(UserIdentityUserName), UserName, UserIdentityUserName)
| extend AccountName = iif(AccountName contains "@", tostring(split(AccountName, '@', 0)[0]), AccountName),
AccountUPNSuffix = iif(AccountName contains "@", tostring(split(AccountName, '@', 1)[0]), "");
//Checking for Policy creation event with Full Admin Privileges since lookback period.
let FullAdminPolicyEvents = materialize( EventInfo
| where TimeGenerated >= ago(lookback)
| where EventName in (createPolicy)
| extend PolicyName = tostring(parse_json(RequestParameters).policyName)
| extend Statement = parse_json(tostring((parse_json(RequestParameters).policyDocument))).Statement
| mvexpand Statement
| extend Action = parse_json(Statement).Action , Effect = tostring(parse_json(Statement).Effect), Resource = tostring(parse_json(Statement).Resource), Condition = tostring(parse_json(Statement).Condition)
| extend Action = tostring(Action)
| where Effect =~ "Allow" and (((Action has "iam:*" or Action has "iam:PassRole") and Action has "cloudformation:*") or ((Action has "iam:*" or Action has "iam:PassRole") and Action contains "cloudformation:DescribeStacks" and Action contains "cloudformation:CreateStack") or ((Action contains "iam:*" or Action contains "iam:PassRole") and Action contains "cloudformation:Describe*" and Action contains "cloudformation:Create*")) and Resource == "*" and Condition == ""
| distinct TimeGenerated, EventName, PolicyName, SourceIpAddress, UserIdentityArn, RecipientAccountId, AccountName, AccountUPNSuffix
| project-rename StartTime = TimeGenerated );
let PolicyAttach = materialize( EventInfo
| where TimeGenerated >= ago(timeframe)
| where EventName in (EventNameList) and isempty(ErrorCode) and isempty(ErrorMessage)
| extend PolicyName = tostring(split(tostring(parse_json(RequestParameters).policyArn),"/")[1])
| summarize AttachEventCount=count(), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventSource, EventName, RecipientAccountId, AccountName, AccountUPNSuffix, UserIdentityType , UserIdentityArn, SourceIpAddress, PolicyName
| extend AttachEvent = pack("StartTime", StartTime, "EndTime", EndTime, "EventName", EventName, "UserIdentityType", UserIdentityType, "SourceIpAddress", SourceIpAddress, "AccountName", AccountName, "AccountUPNSuffix", AccountUPNSuffix, "RecipientAccountId", RecipientAccountId, "UserIdentityArn", UserIdentityArn)
| project EventSource, PolicyName, AttachEvent, AttachEventCount, RecipientAccountId, AccountName, AccountUPNSuffix
);
// Joining the list of PolicyNames and checking if it has been attached to any Roles/Users/Groups.
// These Roles/Users/Groups will be Privileged and can be used by adversaries as pivot point for privilege escalation via multiple ways.
FullAdminPolicyEvents
| join kind=leftouter
(
PolicyAttach
)
on PolicyName
| project-away PolicyName1
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: AccountUPNSuffix
- identifier: CloudAppAccountId
columnName: RecipientAccountId
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SourceIpAddress
customDetails:
PolicyName: PolicyName
EventName: EventName
RecipientAccountId: RecipientAccountId
UserIdentityArn: UserIdentityArn
alertDetailsOverride:
alertDisplayNameFormat: 'AWS CloudFormation privilege escalation policy activity: {{PolicyName}} by {{AccountName}}'
alertDescriptionFormat: 'Detected {{EventName}} for policy {{PolicyName}} from {{SourceIpAddress}}.'
version: 1.0.4
kind: Scheduled
Stages and Predicates
Parameters
let EventNameList = dynamic(["AttachUserPolicy","AttachRolePolicy","AttachGroupPolicy"]);
let createPolicy = dynamic(["CreatePolicy", "CreatePolicyVersion"]);
let timeframe = 1d;
let lookback = 14d;
let EventInfo and let FullAdminPolicyEvents are inlined into the numbered stages below.
Let Binding: PolicyAttach
let PolicyAttach = materialize( EventInfo
| where TimeGenerated >= ago(timeframe)
| where EventName in (EventNameList) and isempty(ErrorCode) and isempty(ErrorMessage)
| extend PolicyName = tostring(split(tostring(parse_json(RequestParameters).policyArn),"/")[1])
| summarize AttachEventCount=count(), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventSource, EventName, RecipientAccountId, AccountName, AccountUPNSuffix, UserIdentityType , UserIdentityArn, SourceIpAddress, PolicyName
| extend AttachEvent = pack("StartTime", StartTime, "EndTime", EndTime, "EventName", EventName, "UserIdentityType", UserIdentityType, "SourceIpAddress", SourceIpAddress, "AccountName", AccountName, "AccountUPNSuffix", AccountUPNSuffix, "RecipientAccountId", RecipientAccountId, "UserIdentityArn", UserIdentityArn)
| project EventSource, PolicyName, AttachEvent, AttachEventCount, RecipientAccountId, AccountName, AccountUPNSuffix
);
Stages 1 to 14 define let FullAdminPolicyEvents as the rule's main pipeline source. Stages 15 to 17 use it.
Stage 1: source
AWSCloudTrail
Stage 2: where
| where TimeGenerated >= ago(lookback)
Stage 3: where
| where EventName in (EventNameList) or EventName in (createPolicy)
Stage 4: extend (4 consecutive steps)
| extend UserIdentityArn = iif(isempty(UserIdentityArn), tostring(parse_json(Resources)[0].ARN), UserIdentityArn)
| extend UserName = tostring(split(UserIdentityArn, '/')[-1])
| extend AccountName = case( UserIdentityPrincipalid == "Anonymous", "Anonymous", isempty(UserIdentityUserName), UserName, UserIdentityUserName)
| extend AccountName = iif(AccountName contains "@", tostring(split(AccountName, '@', 0)[0]), AccountName),
AccountUPNSuffix = iif(AccountName contains "@", tostring(split(AccountName, '@', 1)[0]), "")
Stage 5: where
| where TimeGenerated >= ago(lookback)
Stage 6: where
| where EventName in (createPolicy)
Stage 7: extend
| extend PolicyName = tostring(parse_json(RequestParameters).policyName)
Stage 8: extend
| extend Statement = parse_json(tostring((parse_json(RequestParameters).policyDocument))).Statement
Stage 9: mv-expand
| mvexpand Statement
Stage 10: extend
| extend Action = parse_json(Statement).Action , Effect = tostring(parse_json(Statement).Effect), Resource = tostring(parse_json(Statement).Resource), Condition = tostring(parse_json(Statement).Condition)
Stage 11: extend
| extend Action = tostring(Action)
Stage 12: where
| where Effect =~ "Allow" and (((Action has "iam:*" or Action has "iam:PassRole") and Action has "cloudformation:*") or ((Action has "iam:*" or Action has "iam:PassRole") and Action contains "cloudformation:DescribeStacks" and Action contains "cloudformation:CreateStack") or ((Action contains "iam:*" or Action contains "iam:PassRole") and Action contains "cloudformation:Describe*" and Action contains "cloudformation:Create*")) and Resource == "*" and Condition == ""
Stage 13: distinct
| distinct TimeGenerated, EventName, PolicyName, SourceIpAddress, UserIdentityArn, RecipientAccountId, AccountName, AccountUPNSuffix
Stage 14: project-rename
| project-rename StartTime = TimeGenerated
Stage 15: join
FullAdminPolicyEvents
| join kind=leftouter
(
PolicyAttach
)
on PolicyName
Stage 16: project-away
project-away PolicyName1
Stage 17: summarize aggregation inside the join branch
summarize by EventSource, EventName, RecipientAccountId, AccountName, AccountUPNSuffix, UserIdentityType, UserIdentityArn, SourceIpAddress, PolicyName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Action | contains |
| field:"Action" kind:contains |
Action | match |
| field:"Action" kind:match |
Effect | eq |
| field:"Effect" kind:eq value:"Allow" |
ErrorCode | is_null | field:"ErrorCode" kind:is_null | |
ErrorMessage | is_null | field:"ErrorMessage" kind:is_null | |
EventName | in |
| field:"aws::eventName" kind:in |
Resource | eq |
| field:"Resource" kind:eq value:"*" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AccountName | summarize |
AccountUPNSuffix | summarize |
EventName | summarize |
EventSource | summarize |
PolicyName | summarize |
RecipientAccountId | summarize |
SourceIpAddress | summarize |
UserIdentityArn | summarize |
UserIdentityType | summarize |
Azure DevOps Build Variable Modified by New User
#'Variables can be configured and used at any stage of the build process in Azure DevOps to inject values. An attacker with the required permissions could modify or add to these variables to conduct malicious activity such as changing paths or remote endpoints called during the build. As variables are often changed by users, just detecting these changes would have a high false positive rate. This detection looks for modifications to variable groups where that user has not been observed modifying them before.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Defense Impairment |
Rule Body
id: 3b9a44d7-c651-45ed-816c-eae583a6f2f1
name: Azure DevOps Build Variable Modified by New User
description: |
'Variables can be configured and used at any stage of the build process in Azure DevOps to inject values. An attacker with the required permissions could modify or add to these variables to conduct malicious activity such as changing paths or remote endpoints called during the build.
As variables are often changed by users, just detecting these changes would have a high false positive rate. This detection looks for modifications to variable groups where that user has not been observed modifying them before.'
severity: Medium
status: Available
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
relevantTechniques:
- T1578
query: |
let lookback = 14d;
let timeframe = 1d;
let historical_data =
ADOAuditLogs
| where TimeGenerated > ago(lookback) and TimeGenerated < ago(timeframe)
| where OperationName =~ "Library.VariableGroupModified"
| extend variables = Data.Variables
| extend VariableGroupId = tostring(Data.VariableGroupId)
| extend UserKey = strcat(VariableGroupId, "-", ActorUserId)
| project UserKey;
ADOAuditLogs
| where TimeGenerated > ago(timeframe)
| where OperationName =~ "Library.VariableGroupModified"
| extend VariableGroupName = tostring(Data.VariableGroupName)
| extend VariableGroupId = tostring(Data.VariableGroupId)
| extend UserKey = strcat(VariableGroupId, "-", ActorUserId)
| where UserKey !in (historical_data)
| project-away UserKey
| project-reorder TimeGenerated, VariableGroupName, ActorUPN, IpAddress, UserAgent
| extend timestamp = TimeGenerated
| extend AccountName = tostring(split(ActorUPN, "@")[0]), AccountUPNSuffix = tostring(split(ActorUPN, "@")[1])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: ActorUPN
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: AccountUPNSuffix
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IpAddress
version: 1.0.6
kind: Scheduled
Stages and Predicates
Parameters
let lookback = 14d;
let timeframe = 1d;
Let Binding: historical_data
let historical_data = ADOAuditLogs
| where TimeGenerated > ago(lookback) and TimeGenerated < ago(timeframe)
| where OperationName =~ "Library.VariableGroupModified"
| extend variables = Data.Variables
| extend VariableGroupId = tostring(Data.VariableGroupId)
| extend UserKey = strcat(VariableGroupId, "-", ActorUserId)
| project UserKey;
Stage 1: source
ADOAuditLogs
Stage 2: where
| where TimeGenerated > ago(timeframe)
Stage 3: where
| where OperationName =~ "Library.VariableGroupModified"
Stage 4: extend (3 consecutive steps)
| extend VariableGroupName = tostring(Data.VariableGroupName)
| extend VariableGroupId = tostring(Data.VariableGroupId)
| extend UserKey = strcat(VariableGroupId, "-", ActorUserId)
Stage 5: where
| where UserKey !in (historical_data)
Stage 6: project-away
| project-away UserKey
Stage 7: project-reorder
| project-reorder TimeGenerated, VariableGroupName, ActorUPN, IpAddress, UserAgent
Stage 8: extend
| extend timestamp = TimeGenerated
Stage 9: extend
| extend AccountName = tostring(split(ActorUPN, "@")[0]), AccountUPNSuffix = tostring(split(ActorUPN, "@")[1])
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
OperationName | eq |
| field:"OperationName" kind:eq value:"Library.VariableGroupModified" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
UserKey | eq | historical_data | excludes:UserKey field:"UserKey" value:"historical_data" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
VariableGroupName | extend |
VariableGroupId | extend |
timestamp | extend |
AccountName | extend |
AccountUPNSuffix | extend |
BloodHound Attack Path Finding - Large Default Groups With WriteOwnerLimitedRights 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 Groups With WriteOwnerLimitedRights Privileges
Rule Body
id: b26a44aa-aec3-4cfe-aa75-e41104f97a9a
name: BloodHound Attack Path Finding - Large Default Groups With WriteOwnerLimitedRights
Privileges
description: BloodHound Attack Path Finding - Large Default Groups With WriteOwnerLimitedRights
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 == "LargeDefaultGroupsWriteOwnerLimitedRights"
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 == "LargeDefaultGroupsWriteOwnerLimitedRights"
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Finding | eq |
| field:"Finding" kind:eq value:"LargeDefaultGroupsWriteOwnerLimitedRights" |
Brute force attack against an Entra-authenticated Windows device
#Identifies evidence of brute force activity against Windows devices authenticated via Entra ID (including Entra-joined, hybrid-joined, and Windows 365 Cloud PCs) by detecting multiple authentication failures followed by a successful authentication within a defined time window.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Credential Access |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Entra ID | SigninLogs sign-in event: Sign-in naming a target application |
Rule Body
id: 3fbc20a4-04c4-464e-8fcb-6667f53e4987
name: Brute force attack against an Entra-authenticated Windows device
description: |
'Identifies evidence of brute force activity against Windows devices authenticated via Entra ID (including Entra-joined, hybrid-joined, and Windows 365 Cloud PCs) by detecting multiple authentication failures followed by a successful authentication within a defined time window.'
severity: Medium
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- SigninLogs
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
- CredentialAccess
relevantTechniques:
- T1110
query: |
let authenticationWindow = 20m;
let sensitivity = 2.5;
SigninLogs
| where AppDisplayName =~ "Windows Sign In"
| extend FailureOrSuccess = iff(ResultType in ("0", "50125", "50140", "70043", "70044"), "Success", "Failure")
| summarize FailureCount = countif(FailureOrSuccess=="Failure"), SuccessCount = countif(FailureOrSuccess=="Success"), IPAddresses = make_set(IPAddress,1000)
by bin(TimeGenerated, authenticationWindow), UserDisplayName, UserPrincipalName
| extend FailureSuccessDiff = FailureCount - SuccessCount
| where FailureSuccessDiff > 0
| sort by UserPrincipalName asc, TimeGenerated asc
| serialize
| summarize Diff = make_list(FailureSuccessDiff, 10000), TimeStamp = make_list(TimeGenerated, 10000) by UserDisplayName, UserPrincipalName//, tostring(IPAddresses)
| extend (Anomalies, Score, Baseline) = series_decompose_anomalies(Diff, sensitivity, -1, 'linefit')
| mv-expand Diff to typeof(double), TimeStamp to typeof(datetime), Anomalies to typeof(double), Score to typeof(double), Baseline to typeof(long)
| where Anomalies > 0
| summarize by UserDisplayName, UserPrincipalName, Anomalies, Score, Baseline, FailureToSuccessDiff = Diff
| join kind=leftouter (
SigninLogs
| where AppDisplayName =~ "Windows Sign In"
| extend OS = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser
| extend StatusCode = tostring(Status.errorCode), StatusDetails = tostring(Status.additionalDetails)
| extend State = tostring(LocationDetails.state), City = tostring(LocationDetails.city)
| summarize StartTime = min(TimeGenerated),
EndTime = max(TimeGenerated),
IPAddresses = make_set(IPAddress,100),
OS = make_set(OS,20),
Browser = make_set(Browser,20),
City = make_set(City,100),
ResultType = make_set(ResultType,100)
by UserDisplayName, UserPrincipalName, UserId, AppDisplayName
) on UserDisplayName, UserPrincipalName
| project-away UserDisplayName1, UserPrincipalName1
| extend IPAddressFirst = tostring(IPAddresses[0])
| extend Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: UserPrincipalName
- identifier: Name
columnName: Name
- identifier: UPNSuffix
columnName: UPNSuffix
- entityType: Account
fieldMappings:
- identifier: AadUserId
columnName: UserId
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPAddressFirst
version: 2.0.3
kind: Scheduled
Stages and Predicates
Parameters
let authenticationWindow = 20m;
let sensitivity = 2.5;
Stage 1: source
SigninLogs
Stage 2: where
| where AppDisplayName =~ "Windows Sign In"
Stage 3: extend
| extend FailureOrSuccess = iff(ResultType in ("0", "50125", "50140", "70043", "70044"), "Success", "Failure")
FailureOrSuccess =ResultType in (0, 50125, 50140, 70043, 70044)"Success""Failure"Stage 4: summarize
| summarize FailureCount = countif(FailureOrSuccess=="Failure"), SuccessCount = countif(FailureOrSuccess=="Success"), IPAddresses = make_set(IPAddress,1000)
by bin(TimeGenerated, authenticationWindow), UserDisplayName, UserPrincipalName
Stage 5: extend
| extend FailureSuccessDiff = FailureCount - SuccessCount
Stage 6: where
| where FailureSuccessDiff > 0
Stage 7: sort
| sort by UserPrincipalName asc, TimeGenerated asc
Stage 8: kusto:serialize
| serialize
Stage 9: summarize
| summarize Diff = make_list(FailureSuccessDiff, 10000), TimeStamp = make_list(TimeGenerated, 10000) by UserDisplayName, UserPrincipalName
The stages below score time-series anomalies (make-series, series_decompose_anomalies).
Stage 10: extend
| extend (Anomalies, Score, Baseline) = series_decompose_anomalies(Diff, sensitivity, -1, 'linefit')
Stage 11: mv-expand
| mv-expand Diff to typeof(double), TimeStamp to typeof(datetime), Anomalies to typeof(double), Score to typeof(double), Baseline to typeof(long)
Stage 12: where
| where Anomalies > 0
Stage 13: summarize
| summarize by UserDisplayName, UserPrincipalName, Anomalies, Score, Baseline, FailureToSuccessDiff = Diff
Stage 14: join
| join kind=leftouter (
SigninLogs
| where AppDisplayName =~ "Windows Sign In"
| extend OS = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser
| extend StatusCode = tostring(Status.errorCode), StatusDetails = tostring(Status.additionalDetails)
| extend State = tostring(LocationDetails.state), City = tostring(LocationDetails.city)
| summarize StartTime = min(TimeGenerated),
EndTime = max(TimeGenerated),
IPAddresses = make_set(IPAddress,100),
OS = make_set(OS,20),
Browser = make_set(Browser,20),
City = make_set(City,100),
ResultType = make_set(ResultType,100)
by UserDisplayName, UserPrincipalName, UserId, AppDisplayName
) on UserDisplayName, UserPrincipalName
Stage 15: project-away
project-away UserDisplayName1, UserPrincipalName1
Stage 16: extend
extend IPAddressFirst
Stage 17: extend
extend Name, UPNSuffix
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Anomalies | gt |
| field:"Anomalies" kind:gt value:"0" |
AppDisplayName | eq |
| field:"Application" kind:eq value:"Windows Sign In" |
FailureSuccessDiff | gt |
| field:"FailureSuccessDiff" kind:gt value:"0" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Anomalies | summarize |
Baseline | summarize |
FailureToSuccessDiff | summarize |
Score | summarize |
UserDisplayName | summarize |
UserPrincipalName | summarize |
IPAddressFirst | extend |
Name | extend |
UPNSuffix | extend |
CYFIRMA - High severity Malicious Network Indicators Associated with Malware - Block Recommended Rule
#This is a third-party alert feed, not a detection over modeled telemetry. The vendor product raised the finding; this rule forwards it into the SIEM. It is searchable for reference but is excluded from the detection-rule browse and the ATT&CK coverage matrix.
"This analytics rule detects network-based indicators identified by CYFIRMA threat intelligence as associated with Command & Control (C2) infrastructure. These may represent attacker-controlled endpoints used to maintain persistence, exfiltrate data, or receive commands from malware-infected hosts."
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Execution | |
| Command & Control |
Rule Body
id: c7c02bbf-b775-4e85-a3c7-7f8a9318fd2f
name: CYFIRMA - High severity Malicious Network Indicators Associated with Malware - Block Recommended Rule
description: |
"This analytics rule detects network-based indicators identified by CYFIRMA threat intelligence as associated with Command & Control (C2) infrastructure.
These may represent attacker-controlled endpoints used to maintain persistence, exfiltrate data, or receive commands from malware-infected hosts."
version: 1.0.1
kind: Scheduled
severity: High
enabled: false
requiredDataConnectors:
- connectorId: CyfirmaCyberIntelligenceDC
dataTypes:
- CyfirmaIndicators_CL
query: |
//Network Indicators Associated with Malware - Block Recommended Rule
let timeFrame= 5m;
CyfirmaIndicators_CL
| where ConfidenceScore >= 80
and TimeGenerated between (ago(timeFrame) .. now())
and pattern !contains 'file:hashes' and RecommendedActions has 'Block' and Roles has 'Malware'
| extend IPv4 = extract(@"ipv4-addr:value\s*=\s*'([^']+)'", 1, pattern)
| extend IPv6 = extract(@"ipv6-addr:value\s*=\s*'([^']+)'", 1, pattern)
| extend URL = extract(@"url:value\s*=\s*'([^']+)'", 1, pattern)
| extend Domain = extract(@"domain-name:value\s*=\s*'([^']+)'", 1, pattern)
| extend parsed = parse_json(extensions)
| extend extensionKeys = bag_keys(parsed)
| mv-expand extensionKeys
| extend extensionKeyStr = tostring(extensionKeys)
| extend ext = parsed[extensionKeyStr]
| extend props = ext.properties
| extend
extension_id = extensionKeyStr,
ASN_Owner = props.asn_owner,
ASN = props.asn,
ProviderName = 'CYFIRMA',
ProductName = 'DeCYFIR/DeTCT'
| project
IPv4,
IPv6,
URL,
Domain,
ThreatActors,
RecommendedActions,
Sources,
Roles,
Country,
IPAbuse,
name,
Description,
ConfidenceScore,
IndicatorID,
created,
modified,
valid_from,
Tags,
ThreatType,
TimeGenerated,
SecurityVendors,
ProductName,
ProviderName
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: GreaterThan
triggerThreshold: 0
suppressionDuration: 5m
suppressionEnabled: true
tactics:
- InitialAccess
- Execution
- CommandAndControl
relevantTechniques:
- T1566
- T1189
- T1204
- T1071
- T1090
- T1059
- T1568
- T1566.002
- T1204.001
- T1071.001
- T1568.002
alertDetailsOverride:
alertDisplayNameFormat: "High-Confidence Malicious Network Indicators Associated with Malware - Block Recommended - {{name}} "
alertDescriptionFormat: "{{Description}} - {{name}} "
alertDynamicProperties:
- alertProperty: ProductName
value: ProductName
- alertProperty: ProviderName
value: ProviderName
customDetails:
ThreatActors: ThreatActors
Sources: Sources
RecommendedActions: RecommendedActions
Roles: Roles
Country: Country
Description: Description
ConfidenceScore: ConfidenceScore
SecurityVendors: SecurityVendors
IndicatorID: IndicatorID
Created: created
Modified: modified
ValidFrom: valid_from
Tags: Tags
ThreatType: ThreatType
TimeGenerated: TimeGenerated
IPAbuse: IPAbuse
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPv4
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPv6
- entityType: DNS
fieldMappings:
- identifier: DomainName
columnName: Domain
- entityType: URL
fieldMappings:
- identifier: Url
columnName: URL
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: false
reopenClosedIncident: false
lookbackDuration: PT5H
matchingMethod: AllEntities
eventGroupingSettings:
aggregationKind: AlertPerResult
Stages and Predicates
Parameters
let timeFrame = 5m;
Stage 1: source
CyfirmaIndicators_CL
Stage 2: where
| where ConfidenceScore >= 80
and TimeGenerated between (ago(timeFrame) .. now())
and pattern !contains 'file:hashes' and RecommendedActions has 'Block' and Roles has 'Malware'
Stage 3: extend (6 consecutive steps)
| extend IPv4 = extract(@"ipv4-addr:value\s*=\s*'([^']+)'", 1, pattern)
| extend IPv6 = extract(@"ipv6-addr:value\s*=\s*'([^']+)'", 1, pattern)
| extend URL = extract(@"url:value\s*=\s*'([^']+)'", 1, pattern)
| extend Domain = extract(@"domain-name:value\s*=\s*'([^']+)'", 1, pattern)
| extend parsed = parse_json(extensions)
| extend extensionKeys = bag_keys(parsed)
Stage 4: mv-expand
| mv-expand extensionKeys
Stage 5: extend (4 consecutive steps)
| extend extensionKeyStr = tostring(extensionKeys)
| extend ext = parsed[extensionKeyStr]
| extend props = ext.properties
| extend
extension_id = extensionKeyStr,
ASN_Owner = props.asn_owner,
ASN = props.asn,
ProviderName = 'CYFIRMA',
ProductName = 'DeCYFIR/DeTCT'
Stage 6: project
| project
IPv4,
IPv6,
URL,
Domain,
ThreatActors,
RecommendedActions,
Sources,
Roles,
Country,
IPAbuse,
name,
Description,
ConfidenceScore,
IndicatorID,
created,
modified,
valid_from,
Tags,
ThreatType,
TimeGenerated,
SecurityVendors,
ProductName,
ProviderName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ConfidenceScore | ge |
| field:"ConfidenceScore" kind:ge value:"80" |
RecommendedActions | match |
| field:"RecommendedActions" kind:match value:"Block" |
Roles | match |
| field:"Roles" kind:match value:"Malware" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
pattern | contains | file:hashes | excludes:pattern field:"pattern" value:"file:hashes" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ConfidenceScore | project |
Country | project |
Description | project |
Domain | project |
IPAbuse | project |
IPv4 | project |
IPv6 | project |
IndicatorID | project |
ProductName | project |
ProviderName | project |
RecommendedActions | project |
Roles | project |
SecurityVendors | project |
Sources | project |
Tags | project |
ThreatActors | project |
ThreatType | project |
TimeGenerated | project |
URL | project |
created | project |
modified | project |
name | project |
valid_from | project |
Detect Rare scheduled task created
#Persistence via Scheduled Tasks is a well-known technique used by adversaries to make sure their malware programs keep running an the compromised device. With this detection rule, you can search for scheduled tasks being created by processes that did not performed this before. > [!WARNING] > This detection rule is the base for the detection. You will need to add environment specific finetuning in order to limit the BP detections on legitimate processes
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Execution | |
| Persistence | |
| Privilege Escalation |
References
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Microsoft Defender for Endpoint | DeviceProcessEvents action any: Process activity |
Rule Body
let lolbins = toscalar(externaldata(FileName:string, Description:string, Author:string, Date:datetime, Command:string, CommandDescription:string, CommandUsecase:string, CommandCategory:string)
["https://lolbas-project.github.io/api/lolbas.csv"] with(format="csv", ignoreFirstRecord=true)
| extend FileName = tolower(FileName)
| summarize make_set(FileName)
);
// Setting up the rare ones.
let rareScheduledTaskRegistrations = toscalar(
DeviceProcessEvents
| where Timestamp > ago(14d)
| where ProcessCommandLine has_all ("schtasks", "/create")
| summarize count() by ProcessCommandLine
| where count_ < 5
| summarize make_set(ProcessCommandLine)
);
DeviceProcessEvents
| where Timestamp > ago(1d)
| where ProcessCommandLine has_all ("schtasks", "/create")
| extend ProcessCommandLine = replace_regex(ProcessCommandLine, @"C:\\Users\\[^\\]+", "C:\\Users\\<USERNAME>")
// Only take the ones in the last day we find rare within the organization.
| where ProcessCommandLine in (rareScheduledTaskRegistrations)
| invoke FileProfile(InitiatingProcessSHA256, 1000)
| where not(GlobalPrevalence > 1000 and tolower(InitiatingProcessFileName) !in (lolbins))
Stages and Predicates
Let Binding: lolbins
let lolbins = toscalar(externaldata(FileName:string, Description:string, Author:string, Date:datetime, Command:string, CommandDescription:string, CommandUsecase:string, CommandCategory:string)
["https://lolbas-project.github.io/api/lolbas.csv"] with(format="csv", ignoreFirstRecord=true)
| extend FileName = tolower(FileName)
| summarize make_set(FileName)
);
Let Binding: rareScheduledTaskRegistrations
let rareScheduledTaskRegistrations = toscalar(
DeviceProcessEvents
| where Timestamp > ago(14d)
| where ProcessCommandLine has_all ("schtasks", "/create")
| summarize count() by ProcessCommandLine
| where count_ < 5
| summarize make_set(ProcessCommandLine)
);
Stage 1: source
DeviceProcessEvents
Stage 2: where
| where Timestamp > ago(1d)
Stage 3: where
| where ProcessCommandLine has_all ("schtasks", "/create")
Stage 4: extend
| extend ProcessCommandLine = replace_regex(ProcessCommandLine, @"C:\\Users\\[^\\]+", "C:\\Users\\<USERNAME>")
Stage 5: where
| where ProcessCommandLine in (rareScheduledTaskRegistrations)
Stage 6: invoke
| invoke FileProfile(InitiatingProcessSHA256, 1000)
Stage 7: where
| where not(GlobalPrevalence > 1000 and tolower(InitiatingProcessFileName) !in (lolbins))
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
InitiatingProcessFileName | in |
| field:"parent_process_basename" kind:in value:"lolbins" |
ProcessCommandLine | in |
| field:"ProcessCommandLine" kind:in value:"rareScheduledTaskRegistrations" |
ProcessCommandLine | match |
| field:"CommandLine" kind:match |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
InitiatingProcessFileName | eq | lolbins | excludes:InitiatingProcessFileName field:"InitiatingProcessFileName" value:"lolbins" |
GlobalPrevalence | gt | 1000 | excludes:GlobalPrevalence field:"GlobalPrevalence" value:"1000" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ProcessCommandLine | extend |
Multiple scans in the network (Microsoft Defender for IoT)
#'This alert leverages Defender for IoT to detect multiple scans on the network indicating new devices, functionality, application misconfiguration, or malicious reconnaissance activity on the network.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Discovery |
Rule Body
id: 493916d5-a094-4bfa-bdd1-d983a063ea3d
name: Multiple scans in the network (Microsoft Defender for IoT)
description: |
'This alert leverages Defender for IoT to detect multiple scans on the network indicating new devices, functionality, application misconfiguration, or malicious reconnaissance activity on the network.'
severity: High
status: Available
requiredDataConnectors:
- connectorId: IoT
dataTypes:
- SecurityAlert (ASC for IoT)
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
tactics:
- Discovery
relevantTechniques:
- T0842
query: |
SecurityAlert
| where ProviderName == "IoTSecurity"
| where AlertName has "Scan"
| extend ExtendedProperties = parse_json(ExtendedProperties)
| where tostring(ExtendedProperties.isNew) == "True"
| extend DeviceId = tostring(ExtendedProperties.DeviceId),
SourceDeviceAddress = tostring(ExtendedProperties.SourceDeviceAddress),
DestDeviceAddress = tostring(ExtendedProperties.DestinationDeviceAddress),
RemediationSteps = tostring(parse_json(RemediationSteps)[0]),
Protocol = tostring(ExtendedProperties.Protocol),
AlertManagementUri = tostring(ExtendedProperties.AlertManagementUri)
| project
TimeGenerated,
DeviceId,
ProductName,
ProductComponentName,
AlertSeverity,
AlertName,
Description,
Protocol,
SourceDeviceAddress,
DestDeviceAddress,
RemediationSteps,
Tactics,
Entities,
VendorOriginalId,
AlertLink,
AlertManagementUri,
Techniques
entityMappings:
sentinelEntitiesMappings:
- columnName: Entities
eventGroupingSettings:
aggregationKind: AlertPerResult
customDetails:
Sensor: DeviceId
Protocol: Protocol
VendorOriginalId: VendorOriginalId
AlertManagementUri: AlertManagementUri
alertDetailsOverride:
alertDisplayNameFormat: (MDIoT) {{AlertName}}
alertDescriptionFormat: (MDIoT) {{Description}}
alertTacticsColumnName: Tactics
alertSeverityColumnName: AlertSeverity
alertDynamicProperties:
- alertProperty: ProductName
value: ProductName
- alertProperty: RemediationSteps
value: RemediationSteps
- alertProperty: Techniques
value: Techniques
- alertProperty: ProductComponentName
value: ProductComponentName
- alertProperty: AlertLink
value: AlertLink
version: 1.0.3
kind: Scheduled
Stages and Predicates
Stage 1: source
SecurityAlert
Stage 2: where
| where ProviderName == "IoTSecurity"
Stage 3: where
| where AlertName has "Scan"
Stage 4: extend
| extend ExtendedProperties = parse_json(ExtendedProperties)
Stage 5: where
| where tostring(ExtendedProperties.isNew) == "True"
Stage 6: extend
| extend DeviceId = tostring(ExtendedProperties.DeviceId),
SourceDeviceAddress = tostring(ExtendedProperties.SourceDeviceAddress),
DestDeviceAddress = tostring(ExtendedProperties.DestinationDeviceAddress),
RemediationSteps = tostring(parse_json(RemediationSteps)[0]),
Protocol = tostring(ExtendedProperties.Protocol),
AlertManagementUri = tostring(ExtendedProperties.AlertManagementUri)
Stage 7: project
| project
TimeGenerated,
DeviceId,
ProductName,
ProductComponentName,
AlertSeverity,
AlertName,
Description,
Protocol,
SourceDeviceAddress,
DestDeviceAddress,
RemediationSteps,
Tactics,
Entities,
VendorOriginalId,
AlertLink,
AlertManagementUri,
Techniques
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
AlertName | match |
| field:"AlertName" kind:match value:"Scan" |
ExtendedProperties.isNew | eq |
| field:"ExtendedProperties.isNew" kind:eq value:"True" |
ProviderName | eq |
| field:"ProviderName" kind:eq value:"IoTSecurity" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AlertLink | project |
AlertManagementUri | project |
AlertName | project |
AlertSeverity | project |
Description | project |
DestDeviceAddress | project |
DeviceId | project |
Entities | project |
ProductComponentName | project |
ProductName | project |
Protocol | project |
RemediationSteps | project |
SourceDeviceAddress | project |
Tactics | project |
Techniques | project |
TimeGenerated | project |
VendorOriginalId | project |
OCI - Multiple instances launched
#'Detects when multiple instances were launched.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Impact |
Rule Body
id: a79cf2b9-a511-4282-ba5d-812e14b07831
name: OCI - Multiple instances launched
description: |
'Detects when multiple instances were launched.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: OracleCloudInfrastructureLogsConnector
dataTypes:
- OCILogs
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Impact
relevantTechniques:
- T1496
query: |
let threshold = 5;
OCILogs
| where data_eventName_s =~ 'LaunchInstance'
| summarize count() by SrcIpAddr, bin(TimeGenerated, 10m)
| where count_ >= threshold
| extend IPCustomEntity = SrcIpAddr
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.0
kind: Scheduled
Stages and Predicates
Parameters
let threshold = 5;
Stage 1: source
OCILogs
Stage 2: where
| where data_eventName_s =~ 'LaunchInstance'
Stage 3: summarize
| summarize count() by SrcIpAddr, bin(TimeGenerated, 10m)
Stage 4: where
| where count_ >= threshold
Stage 5: extend
| extend IPCustomEntity = SrcIpAddr
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
count_ | ge |
| field:"count_" kind:ge value:"5" |
data_eventName_s | eq |
| field:"data_eventName_s" kind:eq value:"LaunchInstance" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
SrcIpAddr | summarize |
IPCustomEntity | extend |
Refactor AWS policy based on activities in the last 60 days
#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 is a recommended update to IAM policy on AWS. Review the policy and apply it according to change control process. Authomize will have a recommended policy to be downloaded.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Privilege Escalation |
Rule Body
id: 642de064-c67b-4eb7-98bd-3f8cd51f282c
name: Refactor AWS policy based on activities in the last 60 days
kind: Scheduled
description: This is a recommended update to IAM policy on AWS. Review the policy and apply it according to change control process. Authomize will have a recommended policy to be downloaded.
severity: High
status: Available
queryFrequency: 30m
queryPeriod: 30m
triggerOperator: gt
triggerThreshold: 0
tactics:
- PrivilegeEscalation
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 "Refactor AWS policy based on activities in the last 60 days."
| 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 - Refactor AWS policy based on activities in the last 60 days
alertDescriptionFormat: Refactor AWS policy based on activities in the last 60 days. This is a recommended update to IAM policy on AWS. Review the policy and apply it according to change control process. Authomize will have a recommended policy to be downloaded.
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 "Refactor AWS policy based on activities in the last 60 days."
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:"Refactor AWS policy based on activities in the last 60 days." |
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 |
SAP BTP - Cloud Integration access policy tampering
#Identifies changes to access policies in SAP Cloud Integration. Access policies control authorization for integration artifacts, defining which users and roles can access specific integration flows and related content. Unauthorized access policy manipulation could indicate: - Attacker granting themselves access to sensitive integration artifacts - Removal of security controls to enable further malicious activity - Defense evasion by modifying artifact references to hide unauthorized access
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Privilege Escalation | |
| Defense Impairment |
Rule Body
id: 9e6f4b2c-0d3e-5a8f-c9b7-2f5d8a1e4c6b
kind: Scheduled
name: SAP BTP - Cloud Integration access policy tampering
description: |
Identifies changes to access policies in SAP Cloud Integration. Access policies control
authorization for integration artifacts, defining which users and roles can access specific
integration flows and related content.
Unauthorized access policy manipulation could indicate:
- Attacker granting themselves access to sensitive integration artifacts
- Removal of security controls to enable further malicious activity
- Defense evasion by modifying artifact references to hide unauthorized access
severity: High
status: Available
requiredDataConnectors:
- connectorId: SAPBTPAuditEvents
dataTypes:
- SAPBTPAuditLog_CL
queryFrequency: 15m
queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
- PrivilegeEscalation
relevantTechniques:
- T1548
- T1222
query: |
let accessPolicyTypes = dynamic(["Access Policy", "Artifact Reference"]);
let monitoredActions = dynamic(["Create", "Change", "Delete"]);
SAPBTPAuditLog_CL
| where Category == "audit.security-events"
| extend data_s = tostring(Message.data),
ipAddress = tostring(Message.ip)
| extend parsedData = parse_json(data_s)
| extend action = tostring(parsedData.action),
objectType = tostring(parsedData.objectType),
objectId = tostring(parsedData.objectId),
policyMessage = tostring(parsedData.attributes.message)
| where objectType in (accessPolicyTypes)
| where action in (monitoredActions)
| extend normalizedAction = case(
action == "Create", "created",
action == "Change", "modified",
action == "Delete", "deleted",
action
)
| extend MessageText = case(
objectType == "Access Policy", strcat("Access policy '", objectId, "' was ", normalizedAction),
objectType == "Artifact Reference", strcat("Artifact reference '", objectId, "' was ", normalizedAction),
strcat(objectType, " '", objectId, "' was ", normalizedAction)
)
| project
UpdatedOn,
UserName,
MessageText,
ObjectType = objectType,
ObjectId = objectId,
Action = action,
PolicyMessage = policyMessage,
Tenant,
ipAddress,
CloudApp = "SAP Cloud Integration"
| 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: IP
fieldMappings:
- identifier: Address
columnName: ipAddress
- entityType: CloudApplication
fieldMappings:
- identifier: Name
columnName: CloudApp
alertDetailsOverride:
alertDisplayNameFormat: 'SAP Cloud Integration: {{MessageText}}'
alertDescriptionFormat: |
{{MessageText}} by {{UserName}} from IP {{ipAddress}}.
This could indicate:
- Legitimate access policy administration
- Unauthorized privilege escalation attempt
- Attacker modifying security controls to access sensitive integrations
customDetails:
ObjectType: ObjectType
ObjectId: ObjectId
Action: Action
PolicyMessage: PolicyMessage
SourceIP: ipAddress
version: 1.0.1
Stages and Predicates
Parameters
let accessPolicyTypes = dynamic(["Access Policy", "Artifact Reference"]);
let monitoredActions = dynamic(["Create", "Change", "Delete"]);
Stage 1: source
SAPBTPAuditLog_CL
Stage 2: where
| where Category == "audit.security-events"
Stage 3: extend (3 consecutive steps)
| extend data_s = tostring(Message.data),
ipAddress = tostring(Message.ip)
| extend parsedData = parse_json(data_s)
| extend action = tostring(parsedData.action),
objectType = tostring(parsedData.objectType),
objectId = tostring(parsedData.objectId),
policyMessage = tostring(parsedData.attributes.message)
Stage 4: where
| where objectType in (accessPolicyTypes)
Stage 5: where
| where action in (monitoredActions)
Stage 6: extend
| extend normalizedAction = case(
action == "Create", "created",
action == "Change", "modified",
action == "Delete", "deleted",
action
)
normalizedAction =action == "Create""created"action == "Change""modified"action == "Delete""deleted"actionStage 7: extend
| extend MessageText = case(
objectType == "Access Policy", strcat("Access policy '", objectId, "' was ", normalizedAction),
objectType == "Artifact Reference", strcat("Artifact reference '", objectId, "' was ", normalizedAction),
strcat(objectType, " '", objectId, "' was ", normalizedAction)
)
MessageText =objectType == "Access Policy"strcat("Access policy '", objectId, "' was ", normalizedAction)objectType == "Artifact Reference"strcat("Artifact reference '", objectId, "' was ", normalizedAction)strcat(objectType, " '", objectId, "' was ", normalizedAction)Stage 8: project
| project
UpdatedOn,
UserName,
MessageText,
ObjectType = objectType,
ObjectId = objectId,
Action = action,
PolicyMessage = policyMessage,
Tenant,
ipAddress,
CloudApp = "SAP Cloud Integration"
Stage 9: extend
| extend AccountName = split(UserName, "@")[0], UPNSuffix = split(UserName, "@")[1]
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Category | eq |
| field:"Category" kind:eq value:"audit.security-events" |
action | in |
| field:"action" kind:in |
objectType | in |
| field:"objectType" kind:in |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Action | project |
CloudApp | project |
MessageText | project |
ObjectId | project |
ObjectType | project |
PolicyMessage | project |
Tenant | project |
UpdatedOn | project |
UserName | project |
ipAddress | project |
AccountName | extend |
UPNSuffix | extend |
Secret Exposure with Anomalous SPN Sign-In
#Detects applications with open hardcoded-secret findings (CWE-798, CWE-259, CWE-321, CWE-522) that have associated service principal sign-in anomalies. Correlates StratoSecure secret findings with AAD SPN sign-in failures.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Stealth | |
| Credential Access |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Azure | Conditional Access status: Sign-in recording a Conditional Access status |
Rule Body
id: a91e677a-46b5-428e-8a7d-29a2bb33bb6f
name: Secret Exposure with Anomalous SPN Sign-In
description: |
Detects applications with open hardcoded-secret findings (CWE-798, CWE-259,
CWE-321, CWE-522) that have associated service principal sign-in anomalies.
Correlates StratoSecure secret findings with AAD SPN sign-in failures.
severity: High
status: Available
requiredDataConnectors:
- connectorId: StratoSecurePush
dataTypes:
- StratoSecure_Findings_CL
queryFrequency: 1h
queryPeriod: 1455m
triggerOperator: gt
triggerThreshold: 0
tactics:
- CredentialAccess
- DefenseEvasion
relevantTechniques:
- T1552
- T1078.004
query: |
let lookback = 1d;
let SecretFindings = StratoSecure_Findings_CL
| where TimeGenerated >= ago(lookback)
| where FixStatus =~ "open"
| where CweId in ("CWE-798", "CWE-259", "CWE-321", "CWE-522")
| where Severity in ("Critical", "High")
| summarize FindingCount = count(), RuleIds = make_set(RuleId), Repos = make_set(Repository)
by ApplicationId, StraTenantId;
let AnomalousSignins = AADServicePrincipalSignInLogs
| where TimeGenerated >= ago(lookback)
| where ResultType != "0" or ConditionalAccessStatus =~ "failure"
| summarize FailedAttempts = count(), DistinctIPs = dcount(IPAddress),
FirstAttempt = min(TimeGenerated), LastAttempt = max(TimeGenerated)
by ServicePrincipalId, ServicePrincipalName
| where FailedAttempts > 5 or DistinctIPs > 3;
SecretFindings
| join kind=inner AnomalousSignins on $left.ApplicationId == $right.ServicePrincipalId
| project TimeGenerated = LastAttempt, ApplicationId, ServicePrincipalName, StraTenantId,
FindingCount, RuleIds, Repos, FailedAttempts, DistinctIPs
entityMappings:
- entityType: CloudApplication
fieldMappings:
- identifier: AppId
columnName: ApplicationId
version: 1.0.0
kind: Scheduled
Stages and Predicates
Parameters
let lookback = 1d;
let SecretFindings is inlined into the numbered stages below.
Let Binding: AnomalousSignins
let AnomalousSignins = AADServicePrincipalSignInLogs
| where TimeGenerated >= ago(lookback)
| where ResultType != "0" or ConditionalAccessStatus =~ "failure"
| summarize FailedAttempts = count(), DistinctIPs = dcount(IPAddress),
FirstAttempt = min(TimeGenerated), LastAttempt = max(TimeGenerated)
by ServicePrincipalId, ServicePrincipalName
| where FailedAttempts > 5 or DistinctIPs > 3;
Stages 1 to 6 define let SecretFindings as the rule's main pipeline source. Stages 7 to 8 use it.
Stage 1: source
StratoSecure_Findings_CL
Stage 2: where
| where TimeGenerated >= ago(lookback)
Stage 3: where
| where FixStatus =~ "open"
Stage 4: where
| where CweId in ("CWE-798", "CWE-259", "CWE-321", "CWE-522")
Stage 5: where
| where Severity in ("Critical", "High")
Stage 6: summarize
| summarize FindingCount = count(), RuleIds = make_set(RuleId), Repos = make_set(Repository)
by ApplicationId, StraTenantId
Stage 7: join
SecretFindings
| join kind=inner AnomalousSignins on $left.ApplicationId == $right.ServicePrincipalId
Stage 8: project
project ApplicationId, DistinctIPs, FailedAttempts, FindingCount, Repos, RuleIds, ServicePrincipalName, StraTenantId, TimeGenerated
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ConditionalAccessStatus | eq |
| field:"ConditionalAccessStatus" kind:eq value:"failure" |
CweId | in |
| field:"CweId" kind:in |
DistinctIPs | gt |
| field:"DistinctIPs" kind:gt value:"3" |
FailedAttempts | gt |
| field:"FailedAttempts" kind:gt value:"5" |
FixStatus | eq |
| field:"FixStatus" kind:eq value:"open" |
ResultType | ne |
| field:"ResultType" kind:ne value:"0" |
Severity | in |
| field:"Severity" kind:in |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ApplicationId | project |
DistinctIPs | project |
FailedAttempts | project |
FindingCount | project |
Repos | project |
RuleIds | project |
ServicePrincipalName | project |
StraTenantId | project |
TimeGenerated | project |
Tailscale Premium: DERP relay traffic surge
#Identifies when a source node has more than 75 percent of its recent flows falling back to a DERP relay (Tailscale IsRelayed flag, traffic via 127.3.3.40). Operational signal useful for spotting policy drift.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Command & Control |
Rule Body
id: 0a1c8d12-e7d3-4890-8b89-8d6dbc1be2f0
name: "Tailscale Premium: DERP relay traffic surge"
description: Identifies when a source node has more than 75 percent of its recent flows falling back to a DERP relay (Tailscale IsRelayed flag, traffic via 127.3.3.40). Operational signal useful for spotting policy drift.
description-detailed: |
Identifies when a source node has more than 75 percent of its recent flows falling back to a DERP relay (Tailscale's IsRelayed flag, traffic via 127.3.3.40). Sustained high relay rate indicates direct WireGuard peer-to-peer is failing - causes include NAT/firewall changes, a network blocking UDP 41641, or potential evasion attempts. Operational signal but useful for spotting policy drift. Requires Tailscale Premium or Enterprise.
severity: Low
status: Available
requiredDataConnectors:
- connectorId: TailscalePremiumCCF
dataTypes:
- Tailscale_Network_CL
queryFrequency: 15m
queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandAndControl
relevantTechniques:
- T1572
query: |
let minFlows = 20;
let relayedPctThreshold = 75.0;
Tailscale_Network_CL
| where TimeGenerated > ago(15m)
| summarize
TotalFlows = count(),
RelayedFlows = countif(IsRelayed)
by SrcNodeName, SrcUser, SrcOs, SrcTags=tostring(SrcTags)
| where TotalFlows >= minFlows
| extend RelayedPct = round(100.0 * RelayedFlows / TotalFlows, 1)
| where RelayedPct > relayedPctThreshold
| project SrcNodeName, SrcUser, SrcOs, SrcTags, TotalFlows, RelayedFlows, RelayedPct
| order by RelayedPct desc
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: SrcNodeName
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: SrcUser
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: PT6H
matchingMethod: AllEntities
kind: Scheduled
version: 1.0.0
Stages and Predicates
Parameters
let minFlows = 20;
let relayedPctThreshold = 75.0;
Stage 1: source
Tailscale_Network_CL
Stage 2: where
| where TimeGenerated > ago(15m)
Stage 3: summarize
| summarize
TotalFlows = count(),
RelayedFlows = countif(IsRelayed)
by SrcNodeName, SrcUser, SrcOs, SrcTags=tostring(SrcTags)
Stage 4: where
| where TotalFlows >= minFlows
Stage 5: extend
| extend RelayedPct = round(100.0 * RelayedFlows / TotalFlows, 1)
Stage 6: where
| where RelayedPct > relayedPctThreshold
Stage 7: project
| project SrcNodeName, SrcUser, SrcOs, SrcTags, TotalFlows, RelayedFlows, RelayedPct
Stage 8: sort
| order by RelayedPct desc
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
RelayedPct | gt |
| field:"RelayedPct" kind:gt value:"75.0" |
TotalFlows | ge |
| field:"TotalFlows" kind:ge value:"20" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
RelayedFlows | project |
RelayedPct | project |
SrcNodeName | project |
SrcOs | project |
SrcTags | project |
SrcUser | project |
TotalFlows | project |
TI Map URL Entity to PaloAlto Data
#'This query identifies any URL indicators of compromise (IOCs) from threat intelligence (TI) by searching for matches in PaloAlto Data.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Command & Control |
Rule Body
id: 106813db-679e-4382-a51b-1bfc463befc3
name: TI Map URL Entity to PaloAlto Data
description: |
'This query identifies any URL indicators of compromise (IOCs) from threat intelligence (TI) by searching for matches in PaloAlto Data.'
severity: Medium
requiredDataConnectors:
- connectorId: PaloAltoNetworks
dataTypes:
- CommonSecurityLog
- 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;
ThreatIntelligenceIndicator
// Picking up only IOC's that contain the entities we want
| where isnotempty(Url)
| where TimeGenerated >= ago(ioc_lookBack)
| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
| where Active == true and ExpirationDateTime > now()
// 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
| join kind=innerunique (
CommonSecurityLog
| extend IngestionTime = ingestion_time()
| where IngestionTime > ago(dt_lookBack)
// Select on Palo Alto logs
| where DeviceVendor =~ "Palo Alto Networks"
| where DeviceEventClassID =~ 'url'
//Uncomment the line below to only alert on allowed connections
//| where DeviceAction !~ "block-url"
//Select logs where URL data is populated
| extend PA_Url = column_ifexists("RequestURL", "None")
| extend PA_Url = iif(isempty(PA_Url), extract("([^\"]+)", 1, tolower(AdditionalExtensions)), trim('"', PA_Url))
| extend PA_Url = iif(PA_Url !startswith "http://" and ApplicationProtocol !~ "ssl", strcat('http://', PA_Url), iif(PA_Url !startswith "https://" and ApplicationProtocol =~ "ssl", strcat('https://', PA_Url), PA_Url))
| where isnotempty(PA_Url)
| extend CommonSecurityLog_TimeGenerated = TimeGenerated
) on $left.Url == $right.PA_Url
| where CommonSecurityLog_TimeGenerated < ExpirationDateTime
| summarize CommonSecurityLog_TimeGenerated = arg_max(CommonSecurityLog_TimeGenerated, *) by IndicatorId, PA_Url
| project timestamp = CommonSecurityLog_TimeGenerated, Description, ActivityGroupNames, IndicatorId, ThreatType, ExpirationDateTime, ConfidenceScore, DeviceAction, SourceIP, PA_Url, DeviceName
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: DeviceName
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SourceIP
- entityType: URL
fieldMappings:
- identifier: Url
columnName: PA_Url
version: 1.2.5
kind: Scheduled
Stages and Predicates
Parameters
let dt_lookBack = 1h;
let ioc_lookBack = 14d;
Stage 1: source
ThreatIntelligenceIndicator
Stage 2: where
| where isnotempty(Url)
Stage 3: where
| where TimeGenerated >= ago(ioc_lookBack)
Stage 4: summarize
| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
Stage 5: where
| where Active == true and ExpirationDateTime > now()
Stage 6: join
| join kind=innerunique (
CommonSecurityLog
| extend IngestionTime = ingestion_time()
| where IngestionTime > ago(dt_lookBack)
| where DeviceVendor =~ "Palo Alto Networks"
| where DeviceEventClassID =~ 'url'
| extend PA_Url = column_ifexists("RequestURL", "None")
| extend PA_Url = iif(isempty(PA_Url), extract("([^\"]+)", 1, tolower(AdditionalExtensions)), trim('"', PA_Url))
| extend PA_Url = iif(PA_Url !startswith "http://" and ApplicationProtocol !~ "ssl", strcat('http://', PA_Url), iif(PA_Url !startswith "https://" and ApplicationProtocol =~ "ssl", strcat('https://', PA_Url), PA_Url))
| where isnotempty(PA_Url)
| extend CommonSecurityLog_TimeGenerated = TimeGenerated
) on $left.Url == $right.PA_Url
Stage 7: where
where CommonSecurityLog_TimeGenerated < ExpirationDateTime
Stage 8: summarize
summarize CommonSecurityLog_TimeGenerated by IndicatorId, PA_Url
Stage 9: project
project ActivityGroupNames, ConfidenceScore, Description, DeviceAction, DeviceName, ExpirationDateTime, IndicatorId, PA_Url, SourceIP, ThreatType, timestamp
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Active | eq |
| field:"Active" kind:eq value:"true" |
DeviceEventClassID | eq |
| field:"DeviceEventClassID" kind:eq value:"url" |
DeviceVendor | eq |
| field:"DeviceVendor" kind:eq value:"Palo Alto Networks" |
PA_Url | is_not_null | field:"PA_Url" kind:is_not_null | |
Url | is_not_null | field:"Url" kind:is_not_null |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ActivityGroupNames | project |
ConfidenceScore | project |
Description | project |
DeviceAction | project |
DeviceName | project |
ExpirationDateTime | project |
IndicatorId | project |
PA_Url | project |
SourceIP | project |
ThreatType | project |
timestamp | project |
Vectra AI Detect - Suspected Compromised Host
#'Create an incident when a Host is suspected to be compromised. The higher the severity level is, the more immediate attention it requires as Vectra AI engine is more confident that this is a real threat. Level of severity are: Low, Medium, High, Critical). Recommended configuration is to trigger an alert for at least High and Critical.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Credential Access | |
| Discovery | |
| Lateral Movement | |
| Collection | |
| Command & Control | |
| Exfiltration | |
| Impact |
Rule Body
id: 60eb6cf0-3fa1-44c1-b1fe-220fbee23d63
name: Vectra AI Detect - Suspected Compromised Host
description: |
'Create an incident when a Host is suspected to be compromised.
The higher the severity level is, the more immediate attention it requires as Vectra AI engine is more confident that this is a real threat.
Level of severity are: Low, Medium, High, Critical). Recommended configuration is to trigger an alert for at least High and Critical.'
severity: Informational
status: Available
requiredDataConnectors:
- connectorId: CefAma
dataTypes:
- CommonSecurityLog
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
eventGroupingSettings:
aggregationKind: AlertPerResult
tactics:
- CredentialAccess
- Discovery
- LateralMovement
- Collection
- CommandAndControl
- Exfiltration
- Impact
relevantTechniques:
- T1003
- T1087
- T1021
- T1119
- T1071
- T1041
- T1499
query: |
// Edit this variable to only keep the Severity level where an incident needs to be created (Defaults are: "High", "Critical" ). Possible values are: "Low", "Medium", "High", "Critical"
let configured_level = dynamic(["High", "Critical"]);
CommonSecurityLog
| where DeviceVendor == "Vectra Networks"
| where DeviceProduct == "X Series"
| where DeviceEventClassID == "hsc"
| project-rename threat_score = FlexNumber1
| project-rename certainty_score = FlexNumber2
| project-rename vectra_URL = DeviceCustomString4
| project-rename detection_name = DeviceEventClassID
| project-rename score_decreases = DeviceCustomString3
| extend level = case( threat_score < 50 and certainty_score < 50, "Low",
threat_score < 50 and certainty_score >= 50 , "Medium",
threat_score >= 50 and certainty_score <= 50, "High",
threat_score >= 50 and certainty_score >= 50, "Critical",
"UNKNOWN")
| extend Severity = case(level == "Info", "Informational",level == "Critical", "High", level)
| where level in (configured_level)
//keep only the event with the highest threat score per Host
| summarize arg_max(TimeGenerated, *) by SourceHostName
| sort by TimeGenerated
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: SourceHostName
alertDetailsOverride:
alertDisplayNameFormat: Vectra AI Detect - Host {{SourceHostName}} reaches {{level}} severity
alertDescriptionFormat: |
The host {{SourceHostName}} has a Threat score of {{threat_score}} and a
certainty of {{certainty_score}}
alertSeverityColumnName: Severity
alertDynamicProperties:
- alertProperty: AlertLink
value: vectra_URL
- alertProperty: ProductName
value: DeviceProduct
- alertProperty: ProviderName
value: DeviceVendor
- alertProperty: ConfidenceScore
value: certainty_score
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: true
lookbackDuration: 7d
matchingMethod: AllEntities
customDetails:
ScoreDecrease: score_decreases
version: 1.0.9
kind: Scheduled
Stages and Predicates
Parameters
let configured_level = dynamic(["High", "Critical"]);
Stage 1: source
CommonSecurityLog
Stage 2: where
| where DeviceVendor == "Vectra Networks"
Stage 3: where
| where DeviceProduct == "X Series"
Stage 4: where
| where DeviceEventClassID == "hsc"
Stage 5: project-rename
| project-rename threat_score = FlexNumber1
Stage 6: project-rename
| project-rename certainty_score = FlexNumber2
Stage 7: project-rename
| project-rename vectra_URL = DeviceCustomString4
Stage 8: project-rename
| project-rename detection_name = DeviceEventClassID
Stage 9: project-rename
| project-rename score_decreases = DeviceCustomString3
Stage 10: extend
| extend level = case( threat_score < 50 and certainty_score < 50, "Low",
threat_score < 50 and certainty_score >= 50 , "Medium",
threat_score >= 50 and certainty_score <= 50, "High",
threat_score >= 50 and certainty_score >= 50, "Critical",
"UNKNOWN")
level =threat_score < 50 and certainty_score < 50"Low"threat_score < 50 and certainty_score >= 50"Medium"threat_score >= 50 and certainty_score <= 50"High"threat_score >= 50 and certainty_score >= 50"Critical""UNKNOWN"Stage 11: extend
| extend Severity = case(level == "Info", "Informational",level == "Critical", "High", level)
Severity =level == "Info""Informational"level == "Critical""High"levelStage 12: where
| where level in (configured_level)
Stage 13: summarize
| summarize arg_max(TimeGenerated, *) by SourceHostName
Stage 14: sort
| sort by TimeGenerated
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
DeviceEventClassID | eq |
| field:"DeviceEventClassID" kind:eq value:"hsc" |
DeviceProduct | eq |
| field:"DeviceProduct" kind:eq value:"X Series" |
DeviceVendor | eq |
| field:"DeviceVendor" kind:eq value:"Vectra Networks" |
level | in |
| field:"level" kind:in |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
SourceHostName | summarize |
Veeam ONE VM with No Replica (Hyper-V)
#This is a third-party alert feed, not a detection over modeled telemetry. The vendor product raised the finding; this rule forwards it into the SIEM. It is searchable for reference but is excluded from the detection-rule browse and the ATT&CK coverage matrix.
Detects Hyper-V VMs with no replica configured.
Rule Body
id: 6117e317-4b90-4bcc-a71f-0c1f29d82ce3
name: Veeam ONE VM with No Replica (Hyper-V)
description: Detects Hyper-V VMs with no replica configured.
severity: High
status: Available
requiredDataConnectors:
- connectorId: VeeamCustomTablesDataConnector
dataTypes:
- VeeamOneTriggeredAlarms_CL
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
eventGroupingSettings:
aggregationKind: AlertPerResult
tactics: []
relevantTechniques: []
query: VeeamOneTriggeredAlarms_CL | where PredefinedAlarmId == 332
version: 1.0.1
kind: Scheduled
customDetails:
PredefinedAlarmId: PredefinedAlarmId
TriggeredAlarmId: TriggeredAlarmId
Description: Description
Name: Name
VoneHostName: VoneHostName
TriggeredTime: TriggeredTime
Status: Status
Comment: Comment
ObjectId: ObjectId
ObjectName: ObjectName
ObjectType: ObjectType
Stages and Predicates
Stage 1: source
VeeamOneTriggeredAlarms_CL
Stage 2: where
| where PredefinedAlarmId == 332
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
PredefinedAlarmId | eq |
| field:"PredefinedAlarmId" kind:eq value:"332" |
Web sites blocked by Eset
#'Create alert on web sites blocked by Eset.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Command & Control | |
| Exfiltration |
Rule Body
id: 84ad2f8a-b64c-49bc-b669-bdb4fd3071e9
name: Web sites blocked by Eset
description: |
'Create alert on web sites blocked by Eset.'
severity: Low
status: Available
requiredDataConnectors:
- connectorId: EsetSMC
dataTypes:
- eset_CL
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
tactics:
- Exfiltration
- CommandAndControl
- InitialAccess
relevantTechniques:
- T1189
- T1567
- T1071.001
query: |
eset_CL
| where event_type_s == 'FilteredWebsites_Event'
| extend AccountCustomEntity = username_s, URLCustomEntity = object_uri_s, HostCustomEntity = hostname_s, IPCustomEntity = ipv4_s
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: HostCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
- entityType: URL
fieldMappings:
- identifier: Url
columnName: URLCustomEntity
version: 1.0.1
kind: Scheduled
Stages and Predicates
Stage 1: source
eset_CL
Stage 2: where
| where event_type_s == 'FilteredWebsites_Event'
Stage 3: extend
| extend AccountCustomEntity = username_s, URLCustomEntity = object_uri_s, HostCustomEntity = hostname_s, IPCustomEntity = ipv4_s
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
event_type_s | eq |
| field:"event_type_s" kind:eq value:"FilteredWebsites_Event" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AccountCustomEntity | extend |
HostCustomEntity | extend |
IPCustomEntity | extend |
URLCustomEntity | extend |