Detection rules › Kusto
Kusto rules: 2o
1Password - Log Ingestion Failure
#This will alert when the log ingestion for the OnePasswordEventLogs_CL logs is failing. The alert is based on the healthevents that are created every 5 minutes and will trigger if no logs have been received for 1 hour. Log ingestion troubleshooting: <insert URL> Ref: https://1password.com/ Ref: https://github.com/securehats/
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Defense Impairment |
Rule Body
id: bf9132c7-9d4d-4244-98c7-7d994703c208
name: 1Password - Log Ingestion Failure
version: 1.0.0
kind: Scheduled
description: |-
This will alert when the log ingestion for the OnePasswordEventLogs_CL logs is failing. The alert is based on the healthevents that are created every 5 minutes and will trigger if no logs have been received for 1 hour.
Log ingestion troubleshooting:
<insert URL>
Ref: https://1password.com/
Ref: https://github.com/securehats/
severity: Medium
requiredDataConnectors:
- connectorId: 1Password
dataTypes:
- OnePasswordEventLogs_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: Equal
triggerThreshold: 0
tactics:
- DefenseEvasion
relevantTechniques:
- T1562
query: |-
OnePasswordEventLogs_CL
| where log_source == "healthevents"
subTechniques:
- T1562.008
suppressionEnabled: false
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: false
reopenClosedIncident: false
lookbackDuration: 5h
matchingMethod: AllEntities
suppressionDuration: 5h
eventGroupingSettings:
aggregationKind: SingleAlert
Stages and Predicates
Stage 1: source
OnePasswordEventLogs_CL
Stage 2: where
| where log_source == "healthevents"
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
log_source | eq |
| field:"log_source" kind:eq value:"healthevents" |
AIShield - Image classification AI Model Evasion high suspicious vulnerability detection
#'This alert creates an incident when Image classification AI Model Evasion high suspicious, high severity vulnerability detected from the AIShield.'
Rule Body
id: 76c9e83d-c6f9-4270-ad21-761410f9cc6c
name: AIShield - Image classification AI Model Evasion high suspicious vulnerability detection
description: |
'This alert creates an incident when Image classification AI Model Evasion high suspicious, high severity vulnerability detected from the AIShield.'
severity: High
status: Available
requiredDataConnectors:
- connectorId: BoschAIShield
dataTypes:
- AIShield
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics: []
relevantTechniques: []
query: |
AIShield
| where Message has 'Image Classification AI Model Evasion Attack Identified'
| where Severity =~ 'High'
| where SuspiciousLevel =~ 'high suspicious attack'
| extend NTDomain = tostring(split(Computer, '\\')[0]), HostName = tostring(split(Computer, '.')[0])
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: HostName
- identifier: NTDomain
columnName: NTDomain
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SourceName
eventGroupingSettings:
aggregationKind: SingleAlert
alertDetailsOverride:
alertDisplayNameFormat: AIShield - Image Classification AI Model Evasion high suspicious vulnerability detected.
alertDescriptionFormat: |
This query detects Image Classification AI Model Evasion high suspicious, high severity alert from AIShield generated at {{TimeGenerated}}.\n\nPlease check the source for more information and investigate further.
alertTacticsColumnName: null
alertSeverityColumnName: Severity
version: 1.0.4
kind: Scheduled
Stages and Predicates
Stage 1: source
AIShield
Stage 2: where
| where Message has 'Image Classification AI Model Evasion Attack Identified'
Stage 3: where
| where Severity =~ 'High'
Stage 4: where
| where SuspiciousLevel =~ 'high suspicious attack'
Stage 5: extend
| extend NTDomain = tostring(split(Computer, '\\')[0]), HostName = tostring(split(Computer, '.')[0])
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Message | match |
| field:"Message" kind:match value:"Image Classification AI Model Evasion Attack Identified" |
Severity | eq |
| field:"Severity" kind:eq value:"High" |
SuspiciousLevel | eq |
| field:"SuspiciousLevel" kind:eq value:"high suspicious attack" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
HostName | extend |
NTDomain | extend |
AWS Security Hub - Detect SSM documents public sharing enabled
#This query detects AWS accounts where public sharing is enabled, using AWS Security Hub control SSM.7 findings. Allowing public sharing of SSM documents can expose automation content and enable unauthorized execution or tampering.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Execution |
Rule Body
id: 0aa20f8c-b8e4-4a34-a5b8-8b2d9dd7d1c2
name: AWS Security Hub - Detect SSM documents public sharing enabled
description: |
This query detects AWS accounts where public sharing is enabled, using AWS Security Hub control SSM.7 findings.
Allowing public sharing of SSM documents can expose automation content and enable unauthorized execution or tampering.
severity: High
status: Available
requiredDataConnectors:
- connectorId: AWSSecurityHub
dataTypes:
- AWSSecurityHubFindings
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Execution
relevantTechniques:
- T1059
tags:
- AWS Foundational Security Best Practices v1.0.0
query: |
AWSSecurityHubFindings
| where RecordState == "ACTIVE" and ComplianceStatus == "FAILED"
| where tostring(AwsSecurityFindingGeneratorId) == "security-control/SSM.7"
or tostring(ComplianceSecurityControlId) == "SSM.7"
| summarize TimeGenerated = max(TimeGenerated)
by AwsAccountId, AwsRegion, AwsSecurityFindingTitle, AwsSecurityFindingDescription,
AwsSecurityFindingId, ComplianceSecurityControlId
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AwsAccountId
- identifier: CloudAppAccountId
columnName: AwsAccountId
customDetails:
ComplianceControlId: ComplianceSecurityControlId
Region: AwsRegion
FindingId: AwsSecurityFindingId
alertDetailsOverride:
alertDisplayNameFormat: "AWS Account {{AwsAccountId}} SSM documents public sharing enabled"
alertDescriptionFormat: |-
AWS Account {{AwsAccountId}} has SSM documents with public sharing enabled. Disable public sharing setting to prevent unintended exposure of automation documents.
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
AWSSecurityHubFindings
Stage 2: where
| where RecordState == "ACTIVE" and ComplianceStatus == "FAILED"
Stage 3: where
| where tostring(AwsSecurityFindingGeneratorId) == "security-control/SSM.7"
or tostring(ComplianceSecurityControlId) == "SSM.7"
Stage 4: summarize
| summarize TimeGenerated = max(TimeGenerated)
by AwsAccountId, AwsRegion, AwsSecurityFindingTitle, AwsSecurityFindingDescription,
AwsSecurityFindingId, ComplianceSecurityControlId
Indicators
These rows show field, operator, and value matches.
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AwsAccountId | summarize |
AwsRegion | summarize |
AwsSecurityFindingDescription | summarize |
AwsSecurityFindingId | summarize |
AwsSecurityFindingTitle | summarize |
ComplianceSecurityControlId | summarize |
TimeGenerated | summarize |
AWSCloudTrail - Privilege escalation via CRUD KMS policy
#Detects inline IAM policy updates that grant broad KMS create, read, update, enable/disable, and delete permissions. This pattern can support key management abuse and indicates possible privilege escalation through expanded cloud role capabilities.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Privilege Escalation |
Telemetry Coverage
Rules Detecting the Same Action
These rules filter on the same operation.
- AWS IAM Access Key Compromise Detection (Panther)
- AWS Lateral Movement from Kubernetes SA via AssumeRoleWithWebIdentity (Elastic)
- AWSCloudTrail - Privilege escalation via CloudFormation policy (Kusto)
- AWSCloudTrail - Privilege escalation via CRUD DynamoDB policy (Kusto)
- AWSCloudTrail - Privilege escalation via CRUD IAM policy (Kusto)
- AWSCloudTrail - Privilege escalation via CRUD Lambda policy (Kusto)
- AWSCloudTrail - Privilege escalation via CRUD S3 policy (Kusto)
- AWSCloudTrail - Privilege escalation via DataPipeline policy (Kusto)
Rule Body
id: d7c39e15-997f-49e5-a782-73bf07db8aa5
name: AWSCloudTrail - Privilege escalation via CRUD KMS policy
description: |
Detects inline IAM policy updates that grant broad KMS create, read, update, enable/disable, and delete
permissions. This pattern can support key management abuse and indicates possible privilege escalation through
expanded cloud role capabilities.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: AWS
dataTypes:
- AWSCloudTrail
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- PrivilegeEscalation
relevantTechniques:
- T1098.003
query: |
AWSCloudTrail
| where EventName in ("PutUserPolicy","PutRolePolicy","PutGroupPolicy") and isempty(ErrorCode) and isempty(ErrorMessage)
| 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 contains "kms:Create" and (Action contains "kms:Get" or Action contains "kms:Describe") and (Action contains "kms:Disable" or Action contains "kms:Enable") and Action contains "kms:Delete") and Resource == "*" and Condition == ""
| 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]), "")
| distinct TimeGenerated, EventName, PolicyName, SourceIpAddress, RecipientAccountId, AccountName, AccountUPNSuffix, UserIdentityArn, UserIdentityUserName
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
UserIdentityArn: UserIdentityArn
RecipientAccountId: RecipientAccountId
alertDetailsOverride:
alertDisplayNameFormat: 'AWS KMS privilege escalation policy update by {{AccountName}}'
alertDescriptionFormat: 'Detected {{EventName}} Event, updating inline KMS escalation policy {{PolicyName}} in account {{RecipientAccountId}}.'
version: 1.0.2
kind: Scheduled
Stages and Predicates
Stage 1: source
AWSCloudTrail
Stage 2: where
| where EventName in ("PutUserPolicy","PutRolePolicy","PutGroupPolicy") and isempty(ErrorCode) and isempty(ErrorMessage)
Stage 3: extend
| extend PolicyName = tostring(parse_json(RequestParameters).policyName)
Stage 4: extend
| extend Statement = parse_json(tostring((parse_json(RequestParameters).policyDocument))).Statement
Stage 5: mv-expand
| mvexpand Statement
Stage 6: 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 7: extend
| extend Action = tostring(Action)
Stage 8: where
| where Effect =~ "Allow" and (Action contains "kms:Create" and (Action contains "kms:Get" or Action contains "kms:Describe") and (Action contains "kms:Disable" or Action contains "kms:Enable") and Action contains "kms:Delete") and Resource == "*" and Condition == ""
Stage 9: 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 10: distinct
| distinct TimeGenerated, EventName, PolicyName, SourceIpAddress, RecipientAccountId, AccountName, AccountUPNSuffix, UserIdentityArn, UserIdentityUserName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Action | contains |
| field:"Action" kind:contains |
Effect | eq |
| field:"Effect" kind:eq value:"Allow" |
ErrorCode | is_null | field:"aws::errorCode" kind:is_null | |
ErrorMessage | is_null | field:"aws::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 |
|---|---|
PolicyName | extend |
Statement | extend |
Action | extend |
Condition | extend |
Effect | extend |
Resource | extend |
UserIdentityArn | extend |
UserName | extend |
AccountName | extend |
AccountUPNSuffix | extend |
CiscoISE - Attempt to delete local store logs
#'Detects when attempt to delete local store logs failed.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Stealth |
Rule Body
id: b6549a28-d61c-476e-b350-4404352ee427
name: CiscoISE - Attempt to delete local store logs
description: |
'Detects when attempt to delete local store logs failed.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: SyslogAma
datatypes:
- Syslog
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
relevantTechniques:
- T1070
query: |
let lbtime = 5m;
CiscoISEEvent
| where TimeGenerated > ago(lbtime)
| where EventId == '59103'
| project TimeGenerated, DvcHostname, DvcIpAddr, DstUserName
| extend HostCustomEntity = DvcHostname
| extend IPCustomEntity = DvcIpAddr
| extend AccountCustomEntity = DstUserName
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: HostCustomEntity
version: 1.0.3
kind: Scheduled
Stages and Predicates
Parameters
let lbtime = 5m;
Stage 1: source
CiscoISEEvent
Stage 2: where
| where TimeGenerated > ago(lbtime)
Stage 3: where
| where EventId == '59103'
Stage 4: project
| project TimeGenerated, DvcHostname, DvcIpAddr, DstUserName
Stage 5: extend (3 consecutive steps)
| extend HostCustomEntity = DvcHostname
| extend IPCustomEntity = DvcIpAddr
| extend AccountCustomEntity = DstUserName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventId | eq |
| field:"EventId" kind:eq value:"59103" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DstUserName | project |
DvcHostname | project |
DvcIpAddr | project |
TimeGenerated | project |
HostCustomEntity | extend |
IPCustomEntity | extend |
AccountCustomEntity | extend |
Cyble Vision Alerts IP Risk Score
#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.
'Triggers when the risk score for a monitored IP increases significantly. This may indicate new malicious behavior or updated threat intelligence classification.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Reconnaissance |
Rule Body
id: 1e7c8d9f-1d42-42b3-b6ce-12a637e05f16
name: Cyble Vision Alerts IP Risk Score
description: |
'Triggers when the risk score for a monitored IP increases significantly. This may indicate new malicious behavior or updated threat intelligence classification.'
severity: Low
status: Available
requiredDataConnectors:
- connectorId: CybleVisionAlerts
dataTypes:
- CybleVisionAlerts_CL
enabled: true
queryfrequency: 30m
queryPeriod: 30m
triggerOperator: GreaterThan
triggerThreshold: 0
eventGroupingSettings:
aggregationKind: AlertPerResult
tactics:
- Reconnaissance
relevantTechniques:
- T1595
query: |
Alerts_ip_risk_score
| where Service == "ip_risk_score"
| extend MappedSeverity = Severity
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: false
reopenClosedIncident: false
lookbackDuration: PT5H
matchingMethod: AllEntities
alertDetailsOverride:
alertDisplayNameFormat: Risk Score Increased for IP {{IPRS_IP}}
alertDescriptionFormat: |
The risk score for IP {{IPRS_IP}} has increased. Previous score {{IPRS_OldScore}}. New score {{IPRS_NewScore}}. This may represent newly observed malicious activity or updated threat intelligence.
customDetails:
MappedSeverity: Severity
Status: Status
AlertID: AlertID
Service: Service
IPRS_IP: IPRS_IP
IPRS_OldScore: IPRS_OldScore
IPRS_NewScore: IPRS_NewScore
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPRS_IP
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
Alerts_ip_risk_score
Stage 2: where
| where Service == "ip_risk_score"
Stage 3: extend
| extend MappedSeverity = Severity
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Service | eq |
| field:"Service" kind:eq value:"ip_risk_score" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
MappedSeverity | extend |
Cyble Vision Alerts Physical Threat Alert
#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.
'Creates an incident for physical threats identified by Cyble Intelligence such as explosions, safety incidents, riots, or violence. Each alert generates a single incident for SOC evaluation.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Impact |
Rule Body
id: 88db8505-1889-46aa-a4e2-4e866262dcb9
name: Cyble Vision Alerts Physical Threat Alert
description: |
'Creates an incident for physical threats identified by Cyble Intelligence such as explosions, safety incidents, riots, or violence. Each alert generates a single incident for SOC evaluation.'
severity: Low
status: Available
requiredDataConnectors:
- connectorId: CybleVisionAlerts
dataTypes:
- CybleVisionAlerts_CL
enabled: true
queryFrequency: 30m
queryPeriod: 30m
triggerOperator: GreaterThan
triggerThreshold: 0
suppressionDuration: PT5M
eventGroupingSettings:
aggregationKind: AlertPerResult
tactics:
- Impact
relevantTechniques:
- T1486
query: |
Alerts_physical_threats
| where Service == "physical_threats"
| extend MappedSeverity = Severity
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: false
reopenClosedIncident: false
lookbackDuration: PT5H
matchingMethod: AllEntities
alertDetailsOverride:
alertDisplayNameFormat: Physical Threat Detected {{PT_Title_Nested}}
alertDescriptionFormat: |
A physical threat incident was identified by Cyble Intelligence.
Title {{PT_Title_Nested}}
Threat Type {{PT_ThreatType}}
Published At {{PT_PublishedAt}}
customDetails:
MappedSeverity: Severity
Status: Status
AlertID: AlertID
Service: Service
ThreatTitle: PT_Title_Nested
ThreatType: PT_ThreatType
Location: PT_LocationName
LocationType: PT_LocationType
Latitude: PT_Latitude
Longitude: PT_Longitude
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: PT_BaseSourceURL
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
Alerts_physical_threats
Stage 2: where
| where Service == "physical_threats"
Stage 3: extend
| extend MappedSeverity = Severity
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Service | eq |
| field:"Service" kind:eq value:"physical_threats" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
MappedSeverity | extend |
CYFIRMA - Medium severity File Hash Indicators with Monitor Action and Malware
#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 KQL query retrieves file hash indicators (MD5, SHA1, SHA256) from the CyfirmaIndicators_CL table within the last 5 minutes. It filters records with a confidence score of 80 or higher, containing file hash patterns, a recommended action of 'Monitor', and roles marked as 'Malware'. Extracted hashes and key threat intelligence details are projected for monitoring and investigation."
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Execution | |
| Stealth | |
| Impact |
Rule Body
id: ca16daff-28dd-499d-93fe-0bb232d76d4f
name: CYFIRMA - Medium severity File Hash Indicators with Monitor Action and Malware
description: |
"This KQL query retrieves file hash indicators (MD5, SHA1, SHA256) from the CyfirmaIndicators_CL table within the last 5 minutes.
It filters records with a confidence score of 80 or higher, containing file hash patterns, a recommended action of 'Monitor', and roles marked as 'Malware'.
Extracted hashes and key threat intelligence details are projected for monitoring and investigation."
version: 1.0.1
kind: Scheduled
severity: Medium
enabled: false
requiredDataConnectors:
- connectorId: CyfirmaCyberIntelligenceDC
dataTypes:
- CyfirmaIndicators_CL
query: |
// File Hash Indicators with Monitor Action and Malware
let timeFrame = 5m;
CyfirmaIndicators_CL
| where (ConfidenceScore < 80 and ConfidenceScore >= 50)
and TimeGenerated between (ago(timeFrame) .. now())
and pattern contains 'file:hashes' and RecommendedActions has 'Monitor' and (Roles contains 'Malware')
| extend MD5 = extract(@"file:hashes\.md5\s*=\s*'([a-fA-F0-9]{32})'", 1, pattern)
| extend SHA1 = extract(@"file:hashes\.'SHA-1'\s*=\s*'([a-fA-F0-9]{40})'", 1, pattern)
| extend SHA256 = extract(@"file:hashes\.'SHA-256'\s*=\s*'([a-fA-F0-9]{64})'", 1, pattern)
| extend
Algo_MD5='md5',
Algo_SHA1= 'SHA1',
Algo_SHA256='SHA256',
ProviderName = 'CYFIRMA',
ProductName = 'DeCYFIR/DeTCT'
| project
MD5,
Algo_MD5,
SHA1,
Algo_SHA1,
SHA256,
Algo_SHA256,
ThreatActors,
Sources,
RecommendedActions,
Roles,
Country,
name,
Description,
ConfidenceScore,
SecurityVendors,
IndicatorID,
created,
modified,
valid_from,
Tags,
ThreatType,
TimeGenerated,
ProductName,
ProviderName
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: GreaterThan
triggerThreshold: 0
suppressionDuration: 5m
suppressionEnabled: true
tactics:
- DefenseEvasion
- InitialAccess
- Impact
- Execution
relevantTechniques:
- T1027
- T1486
- T1204
- T1485
- T1218
- T1566.001
alertDetailsOverride:
alertDisplayNameFormat: "High-Confidence File Hash Indicators with Monitor Action and Malware - {{name}} "
alertDescriptionFormat: "{{Description}} - {{name}} "
alertDynamicProperties:
- alertProperty: ProviderName
value: ProviderName
- alertProperty: ProductName
value: ProductName
customDetails:
ThreatActors: ThreatActors
Sources: Sources
RecommendedActions: RecommendedActions
Roles: Roles
Country: Country
Description: Description
ConfidenceScore: ConfidenceScore
SecurityVendors: SecurityVendors
IndicatorID: IndicatorID
created: created
modified: modified
valid_from: valid_from
Tags: Tags
ThreatType: ThreatType
TimeGenerated: TimeGenerated
entityMappings:
- entityType: FileHash
fieldMappings:
- identifier: Algorithm
columnName: Algo_MD5
- identifier: Value
columnName: MD5
- entityType: FileHash
fieldMappings:
- identifier: Algorithm
columnName: Algo_SHA1
- identifier: Value
columnName: SHA1
- entityType: FileHash
fieldMappings:
- identifier: Algorithm
columnName: Algo_SHA256
- identifier: Value
columnName: SHA256
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: false
reopenClosedIncident: false
lookbackDuration: PT5H
matchingMethod: AllEntities
eventGroupingSettings:
aggregationKind: AlertPerResult
Stages and Predicates
Parameters
let timeFrame = 5m;
Stage 1: source
CyfirmaIndicators_CL
Stage 2: where
| where (ConfidenceScore < 80 and ConfidenceScore >= 50)
and TimeGenerated between (ago(timeFrame) .. now())
and pattern contains 'file:hashes' and RecommendedActions has 'Monitor' and (Roles contains 'Malware')
Stage 3: extend (4 consecutive steps)
| extend MD5 = extract(@"file:hashes\.md5\s*=\s*'([a-fA-F0-9]{32})'", 1, pattern)
| extend SHA1 = extract(@"file:hashes\.'SHA-1'\s*=\s*'([a-fA-F0-9]{40})'", 1, pattern)
| extend SHA256 = extract(@"file:hashes\.'SHA-256'\s*=\s*'([a-fA-F0-9]{64})'", 1, pattern)
| extend
Algo_MD5='md5',
Algo_SHA1= 'SHA1',
Algo_SHA256='SHA256',
ProviderName = 'CYFIRMA',
ProductName = 'DeCYFIR/DeTCT'
Stage 4: project
| project
MD5,
Algo_MD5,
SHA1,
Algo_SHA1,
SHA256,
Algo_SHA256,
ThreatActors,
Sources,
RecommendedActions,
Roles,
Country,
name,
Description,
ConfidenceScore,
SecurityVendors,
IndicatorID,
created,
modified,
valid_from,
Tags,
ThreatType,
TimeGenerated,
ProductName,
ProviderName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ConfidenceScore | ge |
| field:"ConfidenceScore" kind:ge value:"50" |
ConfidenceScore | lt |
| field:"ConfidenceScore" kind:lt value:"80" |
RecommendedActions | match |
| field:"RecommendedActions" kind:match value:"Monitor" |
Roles | contains |
| field:"Roles" kind:contains value:"Malware" |
pattern | contains |
| field:"pattern" kind:contains value:"file:hashes" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Algo_MD5 | project |
Algo_SHA1 | project |
Algo_SHA256 | project |
ConfidenceScore | project |
Country | project |
Description | project |
IndicatorID | project |
MD5 | project |
ProductName | project |
ProviderName | project |
RecommendedActions | project |
Roles | project |
SHA1 | project |
SHA256 | project |
SecurityVendors | project |
Sources | project |
Tags | project |
ThreatActors | project |
ThreatType | project |
TimeGenerated | project |
created | project |
modified | project |
name | project |
valid_from | project |
New executable via Office FileUploaded Operation
#Identifies when executable file types are uploaded to Office services such as SharePoint and OneDrive. List currently includes 'exe', 'inf', 'gzip', 'cmd', 'bat' file extensions. Additionally, identifies when a given user is uploading these files to another users workspace. This may be indication of a staging location for malware or other malicious activity.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Lateral Movement | |
| Command & Control |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Microsoft 365 | FileUploaded |
Rules Detecting the Same Action
These rules filter on the same operation.
Rule Body
id: d722831e-88f5-4e25-b106-4ef6e29f8c13
name: New executable via Office FileUploaded Operation
description: |
'Identifies when executable file types are uploaded to Office services such as SharePoint and OneDrive.
List currently includes 'exe', 'inf', 'gzip', 'cmd', 'bat' file extensions.
Additionally, identifies when a given user is uploading these files to another users workspace.
This may be indication of a staging location for malware or other malicious activity.'
severity: Low
status: Available
requiredDataConnectors:
- connectorId: Office365
dataTypes:
- OfficeActivity (SharePoint)
queryFrequency: 1d
queryPeriod: 8d
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandAndControl
- LateralMovement
relevantTechniques:
- T1105
- T1570
query: |
// a threshold can be enabled, see commented line below for PrevSeenCount
let threshold = 2;
let uploadOp = 'FileUploaded';
// Extensions that are interesting. Add/Remove to this list as you see fit
let execExt = dynamic(['exe', 'inf', 'gzip', 'cmd', 'bat']);
let starttime = 8d;
let endtime = 1d;
OfficeActivity | where TimeGenerated >= ago(endtime)
// Limited to File Uploads due to potential noise, comment out the Operation statement below to include any operation type
// Additional, but potentially noisy operation types that include Uploads and Downloads can be included by adding the following - Operation contains "upload" or Operation contains "download"
| where Operation =~ uploadOp
| where SourceFileExtension has_any (execExt)
| project TimeGenerated, OfficeId, OfficeWorkload, RecordType, Operation, UserType, UserKey, UserId, ClientIP, UserAgent, Site_Url, SourceRelativeUrl, SourceFileName
| join kind= leftanti (
OfficeActivity | where TimeGenerated between (ago(starttime) .. ago(endtime))
| where Operation =~ uploadOp
| where SourceFileExtension has_any (execExt)
| summarize SourceRelativeUrl = make_set(SourceRelativeUrl, 100000), UserId = make_set(UserId, 100000) , PrevSeenCount = count() by SourceFileName
// To exclude previous matches when only above a specific count, change threshold above and uncomment the line below
//| where PrevSeenCount > threshold
| mvexpand SourceRelativeUrl, UserId
| extend SourceRelativeUrl = tostring(SourceRelativeUrl), UserId = tostring(UserId)
) on SourceFileName, SourceRelativeUrl, UserId
| extend SiteUrlUserFolder = tolower(split(Site_Url, '/')[-2])
| extend UserIdUserFolderFormat = tolower(replace_regex(UserId, '@|\\.', '_'))
// identify when UserId is not a match to the specific site url personal folder reference
| extend UserIdDiffThanUserFolder = iff(Site_Url has '/personal/' and SiteUrlUserFolder != UserIdUserFolderFormat, true , false )
| summarize TimeGenerated = make_list(TimeGenerated, 100000), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated),
UserAgents = make_list(UserAgent, 100000), OfficeIds = make_list(OfficeId, 100000), SourceRelativeUrls = make_list(SourceRelativeUrl, 100000), FileNames = make_list(SourceFileName, 100000)
by OfficeWorkload, RecordType, Operation, UserType, UserKey, UserId, ClientIP, Site_Url, SiteUrlUserFolder, UserIdUserFolderFormat, UserIdDiffThanUserFolder
| extend AccountName = tostring(split(UserId, "@")[0]), AccountUPNSuffix = tostring(split(UserId, "@")[1])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: UserId
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: AccountUPNSuffix
- entityType: IP
fieldMappings:
- identifier: Address
columnName: ClientIP
- entityType: URL
fieldMappings:
- identifier: Url
columnName: Site_Url
- entityType: File
fieldMappings:
- identifier: Name
columnName: FileNames
version: 2.0.5
kind: Scheduled
Stages and Predicates
Parameters
let threshold = 2;
let uploadOp = 'FileUploaded';
let execExt = dynamic(['exe', 'inf', 'gzip', 'cmd', 'bat']);
let starttime = 8d;
let endtime = 1d;
Stage 1: source
OfficeActivity
Stage 2: where
| where TimeGenerated >= ago(endtime)
Stage 3: where
| where Operation =~ uploadOp
Stage 4: where
| where SourceFileExtension has_any (execExt)
Stage 5: project
| project TimeGenerated, OfficeId, OfficeWorkload, RecordType, Operation, UserType, UserKey, UserId, ClientIP, UserAgent, Site_Url, SourceRelativeUrl, SourceFileName
Stage 6: join (negated)
join kind=leftanti (OfficeActivity) on SourceFileName, SourceRelativeUrl, UserId
Stage 7: extend (3 consecutive steps)
extend SiteUrlUserFolder, UserIdDiffThanUserFolder, UserIdUserFolderFormat
Stage 8: summarize
summarize EndTime, FileNames, OfficeIds, SourceRelativeUrls, StartTime, TimeGenerated, UserAgents by OfficeWorkload, RecordType, Operation, UserType, UserKey, UserId, ClientIP, Site_Url, SiteUrlUserFolder, UserIdUserFolderFormat, UserIdDiffThanUserFolder
Stage 9: extend
extend AccountName, AccountUPNSuffix
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Operation | eq |
| field:"Operation" kind:eq value:"FileUploaded" |
SourceFileExtension | match |
| field:"SourceFileExtension" kind:match |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
Operation | eq | FileUploaded | excludes:Operation field:"Operation" value:"FileUploaded" |
SourceFileExtension | match | exe, inf, gzip, cmd, bat | excludes:SourceFileExtension |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ClientIP | summarize |
EndTime | summarize |
FileNames | summarize |
OfficeIds | summarize |
OfficeWorkload | summarize |
Operation | summarize |
RecordType | summarize |
SiteUrlUserFolder | summarize |
Site_Url | summarize |
SourceRelativeUrls | summarize |
StartTime | summarize |
TimeGenerated | summarize |
UserAgents | summarize |
UserId | summarize |
UserIdDiffThanUserFolder | summarize |
UserIdUserFolderFormat | summarize |
UserKey | summarize |
UserType | summarize |
AccountName | extend |
AccountUPNSuffix | extend |
Palo Alto Prisma Cloud - Network ACL allow all outbound traffic
#'Detects network ACLs with outbound rule to allow all traffic.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: 4264e133-eec2-438f-af85-05e869308f94
name: Palo Alto Prisma Cloud - Network ACL allow all outbound traffic
description: |
'Detects network ACLs with outbound rule to allow all traffic.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: PaloAltoPrismaCloud
dataTypes:
- PaloAltoPrismaCloud
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1133
query: |
PaloAltoPrismaCloud
| where Reason =~ 'NEW_ALERT'
| where Status =~ 'open'
| where AlertMessage has 'Network ACLs with Outbound rule to allow All Traffic'
| extend AccountCustomEntity = UserName
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountCustomEntity
version: 1.0.1
kind: Scheduled
Stages and Predicates
Stage 1: source
PaloAltoPrismaCloud
Stage 2: where
| where Reason =~ 'NEW_ALERT'
Stage 3: where
| where Status =~ 'open'
Stage 4: where
| where AlertMessage has 'Network ACLs with Outbound rule to allow All Traffic'
Stage 5: extend
| extend AccountCustomEntity = UserName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
AlertMessage | match |
| field:"AlertMessage" kind:match value:"Network ACLs with Outbound rule to allow All Traffic" |
Reason | eq |
| field:"Reason" kind:eq value:"NEW_ALERT" |
Status | eq |
| field:"Status" kind:eq value:"open" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AccountCustomEntity | extend |
SAP LogServ - HANA DB - Assign Admin Authorizations
#Identifies admin privileges/roles assignment. Source Action: Assign a user with any Admin role / privileges. Data Sources: SAP LogServ - HANA DB (Syslog)
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Privilege Escalation | No specific technique |
Rule Body
id: 4981469b-8618-43a7-b44c-5744594fa494
kind: Scheduled
name: SAP LogServ - HANA DB - Assign Admin Authorizations
description: |
Identifies admin privileges/roles assignment.
Source Action: Assign a user with any Admin role / privileges.
*Data Sources: SAP LogServ - HANA DB (Syslog)*
severity: High
status: Available
requiredDataConnectors:
- connectorId: SAPLogServ
dataTypes:
- Syslog
queryFrequency: 10m
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- PrivilegeEscalation
relevantTechniques: []
query: |
let AuditTimeAgo = 60m;
Syslog
| where TimeGenerated >= ago(AuditTimeAgo)
| where SourceSystem == "HANADB" and CollectorHostName == "SAPLogServ"
| extend raw_split = split(SyslogMessage, ";")
| extend
event_timestamp__col_0 = tostring(raw_split[0]),
service_name__col_1 = tostring(raw_split[1]),
hostname__col_2 = tostring(raw_split[2]),
sid__col_3 = tostring(raw_split[3]),
instance_number__col_4 = tostring(raw_split[4]),
port_number__col_5 = tostring(raw_split[5]),
database_name__col_6 = tostring(raw_split[6]),
client_ip_address__col_7 = tostring(raw_split[7]),
client_name__col_8 = tostring(raw_split[8]),
client_process_id__col_9 = tostring(raw_split[9]),
client_port_number__col_10 = tostring(raw_split[10]),
policy_name__col_11 = tostring(raw_split[11]),
audit_level__col_12 = tostring(raw_split[12]),
audit_action__col_13 = tostring(raw_split[13]),
session_user__col_14 = tostring(raw_split[14]),
target_schema__col_15 = tostring(raw_split[15]),
target_object__col_16 = tostring(raw_split[16]),
privilege_name__col_17 = tostring(raw_split[17]),
grantable__col_18 = tostring(raw_split[18]),
role_name__col_19 = tostring(raw_split[19]),
target_principal__col_20 = tostring(raw_split[20]),
action_status__col_21 = tostring(raw_split[21]),
component__col_22 = tostring(raw_split[22]),
section__col_23 = tostring(raw_split[23]),
parameter__col_24 = tostring(raw_split[24]),
old_value__col_25 = tostring(raw_split[25]),
new_value__col_26 = tostring(raw_split[26]),
comment__col_27 = tostring(raw_split[27]),
executed_statement__col_28 = tostring(raw_split[28]),
session_id__col_29 = tostring(raw_split[29]),
application_user_name__col_30 = tostring(raw_split[30]),
role_schema_name__col_31 = tostring(raw_split[31]),
grantee_schema_name__col_32 = tostring(raw_split[32]),
origin_database_name__col_33 = tostring(raw_split[33]),
origin_user_name__col_34 = tostring(raw_split[34]),
xs_application_user_name__col_35 = tostring(raw_split[35]),
application_name__col_36 = tostring(raw_split[36]),
statement_user_name__col_37 = tostring(raw_split[37]),
create_time__col_38 = tostring(raw_split[38]),
xsa_message_ip__col_39 = tostring(raw_split[39]),
xsa_tenant__col_40 = tostring(raw_split[40]),
xsa_uuid__col_41 = tostring(raw_split[41]),
xsa_channel__col_42 = tostring(raw_split[42]),
xsa_attachment_id__col_43 = tostring(raw_split[43]),
xsa_attachment_name__col_44 = tostring(raw_split[44]),
xsa_organization_id__col_45 = tostring(raw_split[45]),
xsa_space_id__col_46 = tostring(raw_split[46]),
xsa_instance_id__col_47 = tostring(raw_split[47]),
xsa_binding_id__col_48 = tostring(raw_split[48]),
xsa_object__col_49 = tostring(raw_split[49]),
xsa_data_subject__col_50 = tostring(raw_split[50])
| where
audit_action__col_13 =~ "GRANT PRIVILEGE"
and privilege_name__col_17 contains "ADMIN"
| extend AlertRuleUniqueName = 'hanadb-assignadminauthorizations-logserv'
eventGroupingSettings:
aggregationKind: SingleAlert
entityMappings:
- entityType: CloudApplication
fieldMappings:
- identifier: AppId
columnName: sid__col_3
- identifier: InstanceName
columnName: database_name__col_6
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: hostname__col_2
- entityType: IP
fieldMappings:
- identifier: Address
columnName: client_ip_address__col_7
alertDetailsOverride:
alertDisplayNameFormat: 'SAP LogServ - HANA DB - Assign Admin Authorizations'
alertDescriptionFormat: |
{{comment__col_27}}
customDetails:
SAP_User: session_user__col_14
version: 1.0.1
Stages and Predicates
Parameters
let AuditTimeAgo = 60m;
Stage 1: source
Syslog
Stage 2: where
| where TimeGenerated >= ago(AuditTimeAgo)
Stage 3: where
| where SourceSystem == "HANADB" and CollectorHostName == "SAPLogServ"
Stage 4: extend
| extend raw_split = split(SyslogMessage, ";")
Stage 5: extend
| extend
event_timestamp__col_0 = tostring(raw_split[0]),
service_name__col_1 = tostring(raw_split[1]),
hostname__col_2 = tostring(raw_split[2]),
sid__col_3 = tostring(raw_split[3]),
instance_number__col_4 = tostring(raw_split[4]),
port_number__col_5 = tostring(raw_split[5]),
database_name__col_6 = tostring(raw_split[6]),
client_ip_address__col_7 = tostring(raw_split[7]),
client_name__col_8 = tostring(raw_split[8]),
client_process_id__col_9 = tostring(raw_split[9]),
client_port_number__col_10 = tostring(raw_split[10]),
policy_name__col_11 = tostring(raw_split[11]),
audit_level__col_12 = tostring(raw_split[12]),
audit_action__col_13 = tostring(raw_split[13]),
session_user__col_14 = tostring(raw_split[14]),
target_schema__col_15 = tostring(raw_split[15]),
target_object__col_16 = tostring(raw_split[16]),
privilege_name__col_17 = tostring(raw_split[17]),
grantable__col_18 = tostring(raw_split[18]),
role_name__col_19 = tostring(raw_split[19]),
target_principal__col_20 = tostring(raw_split[20]),
action_status__col_21 = tostring(raw_split[21]),
component__col_22 = tostring(raw_split[22]),
section__col_23 = tostring(raw_split[23]),
parameter__col_24 = tostring(raw_split[24]),
old_value__col_25 = tostring(raw_split[25]),
new_value__col_26 = tostring(raw_split[26]),
comment__col_27 = tostring(raw_split[27]),
executed_statement__col_28 = tostring(raw_split[28]),
session_id__col_29 = tostring(raw_split[29]),
application_user_name__col_30 = tostring(raw_split[30]),
role_schema_name__col_31 = tostring(raw_split[31]),
grantee_schema_name__col_32 = tostring(raw_split[32]),
origin_database_name__col_33 = tostring(raw_split[33]),
origin_user_name__col_34 = tostring(raw_split[34]),
xs_application_user_name__col_35 = tostring(raw_split[35]),
application_name__col_36 = tostring(raw_split[36]),
statement_user_name__col_37 = tostring(raw_split[37]),
create_time__col_38 = tostring(raw_split[38]),
xsa_message_ip__col_39 = tostring(raw_split[39]),
xsa_tenant__col_40 = tostring(raw_split[40]),
xsa_uuid__col_41 = tostring(raw_split[41]),
xsa_channel__col_42 = tostring(raw_split[42]),
xsa_attachment_id__col_43 = tostring(raw_split[43]),
xsa_attachment_name__col_44 = tostring(raw_split[44]),
xsa_organization_id__col_45 = tostring(raw_split[45]),
xsa_space_id__col_46 = tostring(raw_split[46]),
xsa_instance_id__col_47 = tostring(raw_split[47]),
xsa_binding_id__col_48 = tostring(raw_split[48]),
xsa_object__col_49 = tostring(raw_split[49]),
xsa_data_subject__col_50 = tostring(raw_split[50])
Stage 6: where
| where
audit_action__col_13 =~ "GRANT PRIVILEGE"
and privilege_name__col_17 contains "ADMIN"
Stage 7: extend
| extend AlertRuleUniqueName = 'hanadb-assignadminauthorizations-logserv'
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
CollectorHostName | eq |
| field:"CollectorHostName" kind:eq value:"SAPLogServ" |
SourceSystem | eq |
| field:"SourceSystem" kind:eq value:"HANADB" |
audit_action__col_13 | eq |
| field:"audit_action__col_13" kind:eq value:"GRANT PRIVILEGE" |
privilege_name__col_17 | contains |
| field:"privilege_name__col_17" kind:contains value:"ADMIN" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
raw_split | extend |
action_status__col_21 | extend |
application_name__col_36 | extend |
application_user_name__col_30 | extend |
audit_action__col_13 | extend |
audit_level__col_12 | extend |
client_ip_address__col_7 | extend |
client_name__col_8 | extend |
client_port_number__col_10 | extend |
client_process_id__col_9 | extend |
comment__col_27 | extend |
component__col_22 | extend |
create_time__col_38 | extend |
database_name__col_6 | extend |
event_timestamp__col_0 | extend |
executed_statement__col_28 | extend |
grantable__col_18 | extend |
grantee_schema_name__col_32 | extend |
hostname__col_2 | extend |
instance_number__col_4 | extend |
new_value__col_26 | extend |
old_value__col_25 | extend |
origin_database_name__col_33 | extend |
origin_user_name__col_34 | extend |
parameter__col_24 | extend |
policy_name__col_11 | extend |
port_number__col_5 | extend |
privilege_name__col_17 | extend |
role_name__col_19 | extend |
role_schema_name__col_31 | extend |
section__col_23 | extend |
service_name__col_1 | extend |
session_id__col_29 | extend |
session_user__col_14 | extend |
sid__col_3 | extend |
statement_user_name__col_37 | extend |
target_object__col_16 | extend |
target_principal__col_20 | extend |
target_schema__col_15 | extend |
xs_application_user_name__col_35 | extend |
xsa_attachment_id__col_43 | extend |
xsa_attachment_name__col_44 | extend |
xsa_binding_id__col_48 | extend |
xsa_channel__col_42 | extend |
xsa_data_subject__col_50 | extend |
xsa_instance_id__col_47 | extend |
xsa_message_ip__col_39 | extend |
xsa_object__col_49 | extend |
xsa_organization_id__col_45 | extend |
xsa_space_id__col_46 | extend |
xsa_tenant__col_40 | extend |
xsa_uuid__col_41 | extend |
AlertRuleUniqueName | extend |
Semperis DSP Mimikatz's DCShadow Alert
#'Mimikatz's DCShadow switch allows a user who has compromised an AD domain, to inject arbitrary changes into AD using a "fake" domain controller. These changes bypass the security event log and can't be spotted using normal AD tools. This rule looks for evidence that a machine has been used in this capacity.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Defense Impairment |
Rule Body
id: 1a6d0a49-64b3-4ca1-96c3-f154c16c218c
name: Semperis DSP Mimikatz's DCShadow Alert
description: |
'Mimikatz's DCShadow switch allows a user who has compromised an AD domain, to inject arbitrary changes into AD using a "fake" domain controller. These changes bypass the security event log and can't be spotted using normal AD tools. This rule looks for evidence that a machine has been used in this capacity.'
severity: High
status: Available
requiredDataConnectors:
- connectorId: SemperisDSP
dataTypes:
- dsp_parser
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
relevantTechniques:
- T1207
query: |
dsp_parser
| where EventID == 9212
| where SecurityIndicatorName == "Evidence of Mimikatz DCShadow attack"
| extend HostName = tostring(split(Computer, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Computer, '.'), 1, -1), '.'))
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: HostName
- identifier: DnsDomain
columnName: DnsDomain
version: 2.0.7
kind: Scheduled
Stages and Predicates
Stage 1: source
dsp_parser
Stage 2: where
| where EventID == 9212
Stage 3: where
| where SecurityIndicatorName == "Evidence of Mimikatz DCShadow attack"
Stage 4: extend
| extend HostName = tostring(split(Computer, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Computer, '.'), 1, -1), '.'))
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventID | eq |
| field:"EventID" kind:eq value:"9212" |
SecurityIndicatorName | eq |
| field:"SecurityIndicatorName" kind:eq value:"Evidence of Mimikatz DCShadow attack" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DnsDomain | extend |
HostName | extend |
T1566.002 Spearphishing Link - Rare URL Clicks
#Below query analyzes URLs that are opened from applications like Outlook, Word, Excel, Powerpoint, and Adobe PDF apps. It finds rare URLs that might be a phishing attempt.
It is strongly recommended to enrich results with prevalence information using firewall or proxy logs. You can reduce the noise by filtering specific parent processes according to your needs.
You can further improve the results using logic apps or scripting to get extra information about the URL(age, certificate, VT score etc.) Keep in mind that there ways to bypass controls by hosting the phishing links inside a document stored in the cloud. You don't have any visibility with Sysmon in this scenario.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Telemetry Coverage
| Provider | Record / event type |
|---|---|
| Sysmon | Event ID 1: Process creation |
Rule Body
// Author: Cyb3rMonk(https://twitter.com/Cyb3rMonk, https://mergene.medium.com)
// Link to original post:
// https://posts.bluraven.io/hunting-for-phishing-links-using-sysmon-and-kql-e87d1118ce5e
//
//
// Query parameters:
// Define how manys days of data you want to analyze.
// Consider covering weekends
let lookback = 3d;
// Define how many user might receive the same phishing URL(based on URL or URLHost).
let PhishingTargetMax = 5;
// Get all URLs that were clicked
let PotentialPhishingLinks = materialize (
Event
| where TimeGenerated > ago(lookback)
| where Source == "Microsoft-Windows-Sysmon" and EventID == 1
// Get only the relevant events to improve the query performance during parsing
| where RenderedDescription has_any ("http://", "https://") and RenderedDescription has_any ("msedge.exe", "chrome.exe", "firefox.exe","brave.exe")
| extend RenderedDescription = tostring(split(RenderedDescription, ":")[0])
| extend EventData = parse_xml(EventData).DataItem.EventData.Data
| mv-expand bagexpansion=array EventData
| evaluate bag_unpack(EventData)
| extend Key=tostring(['@Name']), Value=['#text']
| evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, RenderedDescription, MG, ManagementGroupName, Type)
| extend RuleName = column_ifexists("RuleName", ""), TechniqueId = column_ifexists("TechniqueId", ""),
TechniqueName = column_ifexists("TechniqueName", ""),
ParentImage = tostring(ParentImage),
OriginalFileName = tostring(OriginalFileName),
CommandLine = tostring(CommandLine),
Computer = tostring(Computer)
| parse RuleName with * 'technique_id=' TechniqueId ',' * 'technique_name=' TechniqueName
// Extract URL and URLHost
| extend URL = extract("((http|https):\\/\\/.*)\\s?",1,tostring(CommandLine))
| extend URLHost = tostring(parse_url(URL).Host)
)
;
// Perform frequency analysis.
// WARNING!!: Phishing URLs can be customized per target user or not.
// Perform 2 different analysis (one for URL, one for URLHost)
//// Frequency analysis by URLHost ////
PotentialPhishingLinks
| summarize Prevalence = dcount(Computer) by URLHost, ParentImage
| where Prevalence <= PhishingTargetMax
//// Get event details back. ////
| join kind=inner PotentialPhishingLinks on URLHost
// Filter only the last 1 day of events (if you perform analysis everyday)
| where TimeGenerated > ago(1d)
| project-reorder TimeGenerated, Prevalence, Computer, ParentImage, OriginalFileName , URLHost, URL, CommandLine
//// Frequency analysis by URL (comment out the above 8 lines, uncomment the below 8 lines) ////
// PotentialPhishingLinks
// | summarize Prevalence = dcount(Computer) by URL, ParentImage
// | where Prevalence <= PhishingTargetMax
// //// Get event details back. ////
// | join kind=inner PotentialPhishingLinks on URL
// // Filter only the last 1 day of events (if you perform analysis everyday)
// | where TimeGenerated > ago(1d)
// | project-reorder TimeGenerated, Prevalence, Computer, ParentImage, OriginalFileName, URLHost , URL, CommandLine
Stages and Predicates
Parameters
let lookback = 3d;
let PhishingTargetMax = 5;
let PotentialPhishingLinks is inlined into the numbered stages below.
Stages 1 to 15 define let PotentialPhishingLinks as the rule's main pipeline source. Stages 16 to 20 use it.
Stage 1: source
let PotentialPhishingLinks
Stage 2: source
Event
Stage 3: where
| where TimeGenerated > ago(lookback)
Stage 4: where
| where Source == "Microsoft-Windows-Sysmon" and EventID == 1
Stage 5: where
| where RenderedDescription has_any ("http://", "https://") and RenderedDescription has_any ("msedge.exe", "chrome.exe", "firefox.exe","brave.exe")
Stage 6: extend
| extend RenderedDescription = tostring(split(RenderedDescription, ":")[0])
Stage 7: extend
| extend EventData = parse_xml(EventData).DataItem.EventData.Data
Stage 8: mv-expand
| mv-expand bagexpansion=array EventData
Stage 9: evaluate
| evaluate bag_unpack(EventData)
Stage 10: extend
| extend Key=tostring(['@Name']), Value=['#text']
Stage 11: evaluate
| evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, RenderedDescription, MG, ManagementGroupName, Type)
Stage 12: extend
| extend RuleName = column_ifexists("RuleName", ""), TechniqueId = column_ifexists("TechniqueId", ""),
TechniqueName = column_ifexists("TechniqueName", ""),
ParentImage = tostring(ParentImage),
OriginalFileName = tostring(OriginalFileName),
CommandLine = tostring(CommandLine),
Computer = tostring(Computer)
Stage 13: parse
| parse RuleName with * 'technique_id=' TechniqueId ',' * 'technique_name=' TechniqueName
Stage 14: extend
| extend URL = extract("((http|https):\\/\\/.*)\\s?",1,tostring(CommandLine))
Stage 15: extend
| extend URLHost = tostring(parse_url(URL).Host)
Stage 16: summarize
PotentialPhishingLinks
| summarize Prevalence = dcount(Computer) by URLHost, ParentImage
Stage 17: where
| where Prevalence <= PhishingTargetMax
Stage 18: join
| join kind=inner PotentialPhishingLinks on URLHost
Stage 19: where
where TimeGenerated > ago(86400s)
Stage 20: project-reorder
project-reorder
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventID | eq |
| field:"EventID" kind:eq value:"1" |
Prevalence | le |
| field:"Prevalence" kind:le value:"5" |
RenderedDescription | match |
| field:"RenderedDescription" kind:match |
Source | eq |
| field:"Source" kind:eq value:"Microsoft-Windows-Sysmon" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ParentImage | summarize |
Prevalence | summarize |
URLHost | summarize |
UniFi Site Manager: New WAN issue index recorded
#Identifies a newly-recorded UniFi WAN issue index. May indicate ISP problems, hardware fault, or active denial-of-service pressure on the gateway.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Impact |
Rule Body
id: 17d09e1b-8a3f-776b-6981-dbe2cc74d097
name: "UniFi Site Manager: New WAN issue index recorded"
description: |
Identifies a newly-recorded UniFi WAN issue index. May indicate ISP problems, hardware fault, or active denial-of-service pressure on the gateway.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: UniFiSiteManagerConnectorDefinition
dataTypes:
- Unifi_SiteManager_Sites_CL
queryFrequency: 15m
queryPeriod: 45m
triggerOperator: gt
triggerThreshold: 0
tactics:
- Impact
relevantTechniques:
- T1498
subTechniques:
- T1498.001
query: |
// UniFi reports a monotonically-rising wanIssues.count rather than discrete events.
// Detect a NEW occurrence by checking whether the per-site max(count) has grown
// in the most recent 15-min window vs the prior 15-min window.
Unifi_SiteManager_Sites_CL
| where TimeGenerated > ago(45m)
| extend siteId_s = tostring(SiteId)
| where isnotempty(tostring(SiteStatistics.wans.WAN))
| mv-expand issue = todynamic(tostring(SiteStatistics.wans.WAN.wanIssues))
| extend issueCount = tolong(issue.count), idx = tolong(issue.index)
| summarize
PrevMaxCount = maxif(issueCount, TimeGenerated < ago(15m)),
CurrentMaxCount = maxif(issueCount, TimeGenerated >= ago(15m)),
LatestIndex = maxif(idx, TimeGenerated >= ago(15m))
by siteId_s, SiteName
| extend PrevMaxCount = coalesce(PrevMaxCount, tolong(0))
| where CurrentMaxCount > PrevMaxCount
| extend
TimeGenerated = now(),
Delta = CurrentMaxCount - PrevMaxCount,
Activity = strcat('New WAN issue: count rose from ', PrevMaxCount, ' to ', CurrentMaxCount)
| project TimeGenerated, SiteId = siteId_s, SiteName, Activity, IssueIndex = LatestIndex, PrevMaxCount, CurrentMaxCount, Delta
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: SiteId
- identifier: DnsDomain
columnName: SiteName
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: PT5H
matchingMethod: AllEntities
kind: Scheduled
version: 1.0.1
Stages and Predicates
Stage 1: source
Unifi_SiteManager_Sites_CL
Stage 2: where
| where TimeGenerated > ago(45m)
Stage 3: extend
| extend siteId_s = tostring(SiteId)
Stage 4: where
| where isnotempty(tostring(SiteStatistics.wans.WAN))
Stage 5: mv-expand
| mv-expand issue = todynamic(tostring(SiteStatistics.wans.WAN.wanIssues))
Stage 6: extend
| extend issueCount = tolong(issue.count), idx = tolong(issue.index)
Stage 7: summarize
| summarize
PrevMaxCount = maxif(issueCount, TimeGenerated < ago(15m)),
CurrentMaxCount = maxif(issueCount, TimeGenerated >= ago(15m)),
LatestIndex = maxif(idx, TimeGenerated >= ago(15m))
by siteId_s, SiteName
Stage 8: extend
| extend PrevMaxCount = coalesce(PrevMaxCount, tolong(0))
Stage 9: where
| where CurrentMaxCount > PrevMaxCount
Stage 10: extend
| extend
TimeGenerated = now(),
Delta = CurrentMaxCount - PrevMaxCount,
Activity = strcat('New WAN issue: count rose from ', PrevMaxCount, ' to ', CurrentMaxCount)
Stage 11: project
| project TimeGenerated, SiteId = siteId_s, SiteName, Activity, IssueIndex = LatestIndex, PrevMaxCount, CurrentMaxCount, Delta
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
SiteStatistics.wans.WAN | is_not_null | field:"SiteStatistics.wans.WAN" kind:is_not_null |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Activity | project |
CurrentMaxCount | project |
Delta | project |
IssueIndex | project |
PrevMaxCount | project |
SiteId | project |
SiteName | project |
TimeGenerated | project |
User agent search for log4j exploitation attempt
#This query uses various log sources having user agent data to look for log4j CVE-2021-44228 exploitation attempt based on user agent pattern. Log4j is an open-source Apache logging library that is used in many Java-based applications. The regex and the string matching look for the most common attacks. This might not be comprehensive to detect every possible user agent variation. Reference: https://msrc-blog.microsoft.com/2021/12/11/microsofts-response-to-cve-2021-44228-apache-log4j2/
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Telemetry Coverage
Rules Detecting the Same Action
These rules filter on the same operation.
Rule Body
id: 29283b22-a1c0-4d16-b0a9-3460b655a46a
name: User agent search for log4j exploitation attempt
description: |
'This query uses various log sources having user agent data to look for log4j CVE-2021-44228 exploitation attempt based on user agent pattern.
Log4j is an open-source Apache logging library that is used in many Java-based applications. The regex and the string matching look for the most common attacks. This might not be comprehensive to detect every possible user agent variation.
Reference: https://msrc-blog.microsoft.com/2021/12/11/microsofts-response-to-cve-2021-44228-apache-log4j2/'
severity: High
status: Available
requiredDataConnectors:
- connectorId: SquidProxy
dataTypes:
- SquidProxy_CL
- connectorId: Zscaler
dataTypes:
- CommonSecurityLog
- connectorId: WAF
dataTypes:
- AzureDiagnostics
- connectorId: Office365
dataTypes:
- OfficeActivity
- connectorId: AzureActiveDirectory
dataTypes:
- SigninLogs
- connectorId: AzureActiveDirectory
dataTypes:
- AADNonInteractiveUserSignInLogs
- connectorId: AWS
dataTypes:
- AWSCloudTrail
- connectorId: AzureMonitor(IIS)
dataTypes:
- W3CIISLog
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1190
tags:
- log4j
- log4shell
- CVE2021-44228
- Schema: ASimWebSession
- SchemaVersion: 0.2.1
- Schema: ASimNetworkSessions
- SchemaVersion: 0.2.1
query: |
let UserAgentString = dynamic (["${jndi:ldap:/", "${jndi:rmi:/", "${jndi:ldaps:/", "${jndi:dns:/", "${jndi:iiop:/","${jndi:","${jndi:nds:/","${jndi:corba/"]);
let UARegexMinimalString=dynamic(['{','%7b', '%7B']);
let UARegex = @'(\\$|%24)(\\{|%7B)([^jJ]*[jJ])([^nN]*[nN])([^dD]*[dD])([^iI]*[iI])(:|%3A|\\$|%24|}|%7D)';
(union isfuzzy=true
(OfficeActivity
| where UserAgent has_any (UserAgentString) or UserAgent matches regex UARegex
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = ClientIP, Account = UserId, Type, Operation
),
(AzureDiagnostics
| where Category in ("FrontdoorWebApplicationFirewallLog", "FrontdoorAccessLog", "ApplicationGatewayFirewallLog", "ApplicationGatewayAccessLog")
| where userAgent_s has_any (UserAgentString) or userAgent_s matches regex UARegex
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent = userAgent_s, SourceIP = column_ifexists("clientIp_s",clientIP_s), Type, column_ifexists("originalHost_s",host_s), Url = requestUri_s, HttpStatus = column_ifexists("httpStatusDetails_s",httpStatus_d), column_ifexists("trackingReference_s",transactionId_g), ruleName_s, ResourceType, ResourceId
),
(
W3CIISLog
| where csUserAgent has_any (UserAgentString) or csUserAgent matches regex UARegex
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent = csUserAgent, SourceIP = cIP, Account = csUserName, Type, sSiteName, csMethod, Url = csUriStem
),
(
AWSCloudTrail
| where UserAgent has_any (UserAgentString) or UserAgent matches regex UARegex
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = SourceIpAddress, Account = UserIdentityUserName, Type, EventName
),
(SigninLogs
| where UserAgent has_any (UserAgentString) or UserAgent matches regex UARegex
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = IPAddress, Account = UserPrincipalName, Type, Operation = OperationName, tostring(LocationDetails), tostring(DeviceDetail), AppDisplayName, ClientAppUsed
),
(AADNonInteractiveUserSignInLogs
| where UserAgent has_any (UserAgentString) or UserAgent matches regex UARegex
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = IPAddress, Account = UserPrincipalName, Type, Operation = OperationName, tostring(LocationDetails), tostring(DeviceDetail), AppDisplayName, ClientAppUsed
),
(_Im_WebSession (httpuseragent_has_any=array_concat(UserAgentString,UARegexMinimalString))
| where HttpUserAgent has_any (UserAgentString) or HttpUserAgent matches regex UARegex
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by HttpUserAgent, SourceIP = SrcIpAddr, DstIpAddr, Account = SrcUsername, Url, Type
)
)
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: Url
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SourceIP
- entityType: Account
fieldMappings:
- identifier: Name
columnName: Account
version: 1.0.9
kind: Scheduled
Stages and Predicates
Parameters
let UserAgentString = dynamic (["${jndi:ldap:/", "${jndi:rmi:/", "${jndi:ldaps:/", "${jndi:dns:/", "${jndi:iiop:/","${jndi:","${jndi:nds:/","${jndi:corba/"]);
let UARegexMinimalString = dynamic(['{','%7b', '%7B']);
Let Binding: UARegex
let UARegex = @'(\\$|%24)(\\{|%7B)([^jJ]*[jJ])([^nN]*[nN])([^dD]*[dD])([^iI]*[iI])(:|%3A|\\$|%24|}|%7D)';
Union isfuzzy=true (7 Sources)
Each leg below queries one source; the rule matches if any leg does. Sources: OfficeActivity, AzureDiagnostics, W3CIISLog, AWSCloudTrail, SigninLogs, AADNonInteractiveUserSignInLogs, _Im_WebSession
Leg 1: OfficeActivity
OfficeActivity
| where UserAgent has_any (UserAgentString) or UserAgent matches regex UARegex
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = ClientIP, Account = UserId, Type, Operation
Leg 2: AzureDiagnostics
AzureDiagnostics
| where Category in ("FrontdoorWebApplicationFirewallLog", "FrontdoorAccessLog", "ApplicationGatewayFirewallLog", "ApplicationGatewayAccessLog")
| where userAgent_s has_any (UserAgentString) or userAgent_s matches regex UARegex
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent = userAgent_s, SourceIP = column_ifexists("clientIp_s",clientIP_s), Type, column_ifexists("originalHost_s",host_s), Url = requestUri_s, HttpStatus = column_ifexists("httpStatusDetails_s",httpStatus_d), column_ifexists("trackingReference_s",transactionId_g), ruleName_s, ResourceType, ResourceId
Leg 3: W3CIISLog
W3CIISLog
| where csUserAgent has_any (UserAgentString) or csUserAgent matches regex UARegex
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent = csUserAgent, SourceIP = cIP, Account = csUserName, Type, sSiteName, csMethod, Url = csUriStem
Leg 4: AWSCloudTrail
AWSCloudTrail
| where UserAgent has_any (UserAgentString) or UserAgent matches regex UARegex
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = SourceIpAddress, Account = UserIdentityUserName, Type, EventName
Leg 5: SigninLogs
SigninLogs
| where UserAgent has_any (UserAgentString) or UserAgent matches regex UARegex
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = IPAddress, Account = UserPrincipalName, Type, Operation = OperationName, tostring(LocationDetails), tostring(DeviceDetail), AppDisplayName, ClientAppUsed
Leg 6: AADNonInteractiveUserSignInLogs
AADNonInteractiveUserSignInLogs
| where UserAgent has_any (UserAgentString) or UserAgent matches regex UARegex
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = IPAddress, Account = UserPrincipalName, Type, Operation = OperationName, tostring(LocationDetails), tostring(DeviceDetail), AppDisplayName, ClientAppUsed
Leg 7: _Im_WebSession
_Im_WebSession (httpuseragent_has_any=array_concat(UserAgentString,UARegexMinimalString))
| where HttpUserAgent has_any (UserAgentString) or HttpUserAgent matches regex UARegex
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by HttpUserAgent, SourceIP = SrcIpAddr, DstIpAddr, Account = SrcUsername, Url, Type
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Category | in |
| field:"Category" kind:in |
HttpUserAgent | match |
| field:"HttpUserAgent" kind:match |
HttpUserAgent | regex_match |
| field:"HttpUserAgent" kind:regex_match value:"(\$|%24)(\{|%7B)([^jJ]*[jJ])([^nN]*[nN])([^dD]*[dD])([^iI]*[iI])(:|%3A|\$|%24|}|%7D)" |
UserAgent | match |
| field:"aws::userAgent" kind:match |
UserAgent | regex_match |
| field:"aws::userAgent" kind:regex_match |
csUserAgent | match |
| field:"csUserAgent" kind:match |
csUserAgent | regex_match |
| field:"csUserAgent" kind:regex_match value:"(\$|%24)(\{|%7B)([^jJ]*[jJ])([^nN]*[nN])([^dD]*[dD])([^iI]*[iI])(:|%3A|\$|%24|}|%7D)" |
userAgent_s | match |
| field:"userAgent_s" kind:match |
userAgent_s | regex_match |
| field:"userAgent_s" kind:regex_match value:"(\$|%24)(\{|%7B)([^jJ]*[jJ])([^nN]*[nN])([^dD]*[dD])([^iI]*[iI])(:|%3A|\$|%24|}|%7D)" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Account | summarize |
DstIpAddr | summarize |
EndTime | summarize |
HttpUserAgent | summarize |
SourceIP | summarize |
StartTime | summarize |
Type | summarize |
Url | summarize |
Vectra AI Detect - New Campaign Detected
#'Identifies when a new Campaign has been detected. This occurs when multiple Detections accross different Hosts are suspected to be part of the same Attack Campaign.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Lateral Movement | |
| Command & Control |
Rule Body
id: a34d0338-eda0-42b5-8b93-32aae0d7a501
name: Vectra AI Detect - New Campaign Detected
description: |
'Identifies when a new Campaign has been detected. This occurs when multiple Detections accross different Hosts are suspected to be part of the same Attack Campaign.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: CefAma
dataTypes:
- CommonSecurityLog
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
tactics:
- LateralMovement
- CommandAndControl
relevantTechniques:
- T1021
- T1071
query: |
CommonSecurityLog
| where DeviceVendor == "Vectra Networks"
| where DeviceProduct == "X Series"
| where DeviceEventClassID contains "campaign"
| where DeviceAction == "START"
| extend reason = coalesce(
column_ifexists("Reason", ""),
extract("reason=(.+?)($|;)", 1, AdditionalExtensions),
""
)
| project-rename vectra_URL = DeviceCustomString4
| sort by TimeGenerated
entityMappings:
- entityType: DNS
fieldMappings:
- identifier: DomainName
columnName: Activity
alertDetailsOverride:
alertDisplayNameFormat: Vectra AI - New Campaign Detected
alertDescriptionFormat: |
A new campaign named {{Activity}} has been detected (reason is {{reason}})
alertDynamicProperties:
- alertProperty: AlertLink
value: vectra_URL
- alertProperty: ProductName
value: DeviceProduct
- alertProperty: ProviderName
value: DeviceVendor
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: true
lookbackDuration: 7d
matchingMethod: AllEntities
customDetails:
CampaignName: Activity
CampaignReason: reason
CampaignSourceHost: SourceHostName
version: 1.2.3
kind: Scheduled
Stages and Predicates
Stage 1: source
CommonSecurityLog
Stage 2: where
| where DeviceVendor == "Vectra Networks"
Stage 3: where
| where DeviceProduct == "X Series"
Stage 4: where
| where DeviceEventClassID contains "campaign"
Stage 5: where
| where DeviceAction == "START"
Stage 6: extend
| extend reason = coalesce(
column_ifexists("Reason", ""),
extract("reason=(.+?)($|;)", 1, AdditionalExtensions),
""
)
Stage 7: project-rename
| project-rename vectra_URL = DeviceCustomString4
Stage 8: sort
| sort by TimeGenerated
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
DeviceAction | eq |
| field:"DeviceAction" kind:eq value:"START" |
DeviceEventClassID | contains |
| field:"DeviceEventClassID" kind:contains value:"campaign" |
DeviceProduct | eq |
| field:"DeviceProduct" kind:eq value:"X Series" |
DeviceVendor | eq |
| field:"DeviceVendor" kind:eq value:"Vectra Networks" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
reason | extend |
vectra_URL | project-rename |
VMware Cloud Web Security - Data Loss Prevention Violation
#This Analytics rule receives VMware CWS DLP alerts and combines them with their respective Web Log events. Each Data Loss Prevention event is an alert of policy violations and should be investigated.
Rule Body
id: d811ef72-66b9-43a3-ba29-cd9e4bf75b74
name: VMware Cloud Web Security - Data Loss Prevention Violation
version: 1.0.0
kind: Scheduled
description: This Analytics rule receives VMware CWS DLP alerts and combines them with their respective Web Log events. Each Data Loss Prevention event is an alert of policy violations and should be investigated.
severity: Medium
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
requiredDataConnectors:
- connectorId: VMwareSDWAN
dataTypes:
- CWS
query: |-
VMware_CWS_DLPLogs_CL
| join kind=innerunique VMware_CWS_Weblogs_CL on TimeGenerated
suppressionEnabled: false
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: 5h
matchingMethod: AllEntities
groupByEntities: []
groupByAlertDetails: []
groupByCustomDetails: []
eventGroupingSettings:
aggregationKind: AlertPerResult
customDetails:
CWS_Policy_Name: policyName
CWS_Rule_Name: ruleMatched
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: userId
- entityType: IP
fieldMappings:
- identifier: Address
columnName: sourceIp
- entityType: CloudApplication
fieldMappings:
- identifier: Name
columnName: casbAppName
- entityType: URL
fieldMappings:
- identifier: Url
columnName: dstUrl
suppressionDuration: 5h
Stages and Predicates
Stage 1: source
VMware_CWS_DLPLogs_CL
Stage 2: join
| join kind=innerunique VMware_CWS_Weblogs_CL on TimeGenerated