Detection rules › Kusto
Kusto rules: 2u
Apache - Request from private IP
#'Detects requests from private IP'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Impact |
Rule Body
id: a0077556-3aff-11ec-8d3d-0242ac130003
name: Apache - Request from private IP
description: |
'Detects requests from private IP'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: CustomLogsAma
datatypes:
- ApacheHTTPServer_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Impact
- InitialAccess
relevantTechniques:
- T1498
- T1190
- T1133
query: |
ApacheHTTPServer
| where ipv4_is_private(SrcIpAddr)
| extend IPCustomEntity = SrcIpAddr
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.2
kind: Scheduled
Stages and Predicates
Stage 1: source
ApacheHTTPServer
Stage 2: where
| where ipv4_is_private(SrcIpAddr)
Stage 3: extend
| extend IPCustomEntity = SrcIpAddr
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
SrcIpAddr | cidr_match |
| field:"src_ip" kind:cidr_match |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
IPCustomEntity | extend |
ApexOne - Suspicious connections
#'Detects suspicious connections.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Command & Control |
Rule Body
id: 9e3dc038-67b7-11ec-90d6-0242ac120003
name: ApexOne - Suspicious connections
description: |
'Detects suspicious connections.'
severity: High
status: Available
requiredDataConnectors:
- connectorId: CefAma
dataTypes:
- CommonSecurityLog
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandAndControl
relevantTechniques:
- T1102
query: |
TMApexOneEvent
| where EventMessage has "Suspicious Connection"
| where NetworkDirection == 1
| where DvcAction in ('1', '3')
| extend IPCustomEntity = SrcIpAddr, AccountCustomEntity = DstUserName
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountCustomEntity
version: 1.0.3
kind: Scheduled
Stages and Predicates
Stage 1: source
TMApexOneEvent
Stage 2: where
| where EventMessage has "Suspicious Connection"
Stage 3: where
| where NetworkDirection == 1
Stage 4: where
| where DvcAction in ('1', '3')
Stage 5: extend
| extend IPCustomEntity = SrcIpAddr, AccountCustomEntity = DstUserName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
DvcAction | in |
| field:"DvcAction" kind:in |
EventMessage | match |
| field:"EventMessage" kind:match value:"Suspicious Connection" |
NetworkDirection | eq |
| field:"NetworkDirection" kind:eq value:"1" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AccountCustomEntity | extend |
IPCustomEntity | extend |
AWS Security Hub - Detect SQS Queue lacking encryption at rest
#This query detects Amazon SQS queues without server-side encryption at rest enabled, using AWS Security Hub control SQS.1 findings. Lack of encryption for SQS queues can expose sensitive message contents if underlying storage or backups are accessed by unauthorized parties.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Impact |
Rule Body
id: 7b8c5e2d-6f1c-4a1f-9e2a-3c5f7a8b9c10
name: AWS Security Hub - Detect SQS Queue lacking encryption at rest
description: |
This query detects Amazon SQS queues without server-side encryption at rest enabled, using AWS Security Hub control SQS.1 findings.
Lack of encryption for SQS queues can expose sensitive message contents if underlying storage or backups are accessed by unauthorized parties.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: AWSSecurityHub
dataTypes:
- AWSSecurityHubFindings
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Impact
relevantTechniques:
- T1565.001
tags:
- AWS Foundational Security Best Practices v1.0.0
- NIST 800-53 r5
query: |
AWSSecurityHubFindings
| where RecordState == "ACTIVE" and ComplianceStatus == "FAILED"
| where tostring(AwsSecurityFindingGeneratorId) == "security-control/SQS.1"
or tostring(ComplianceSecurityControlId) == "SQS.1"
| mv-expand Resource = Resources
| where tostring(Resource.Type) == "AwsSqsQueue"
| extend QueueArn = tostring(Resource.Id)
| summarize TimeGenerated = max(TimeGenerated)
by AwsAccountId, AwsRegion, AwsSecurityFindingTitle, AwsSecurityFindingDescription,
AwsSecurityFindingId, ComplianceSecurityControlId, QueueArn
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AwsAccountId
- identifier: CloudAppAccountId
columnName: AwsAccountId
- entityType: CloudApplication
fieldMappings:
- identifier: Name
columnName: QueueArn
customDetails:
ComplianceControlId: ComplianceSecurityControlId
Region: AwsRegion
FindingId: AwsSecurityFindingId
alertDetailsOverride:
alertDisplayNameFormat: "SQS queue {{QueueArn}} not encrypted at rest"
alertDescriptionFormat: |-
AWS Account {{AwsAccountId}} has an SQS queue ({{QueueArn}}) without server-side encryption enabled. Enable KMS encryption to protect message data at rest.
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
AWSSecurityHubFindings
Stage 2: where
| where RecordState == "ACTIVE" and ComplianceStatus == "FAILED"
Stage 3: where
| where tostring(AwsSecurityFindingGeneratorId) == "security-control/SQS.1"
or tostring(ComplianceSecurityControlId) == "SQS.1"
Stage 4: mv-expand
| mv-expand Resource = Resources
Stage 5: where
| where tostring(Resource.Type) == "AwsSqsQueue"
Stage 6: extend
| extend QueueArn = tostring(Resource.Id)
Stage 7: summarize
| summarize TimeGenerated = max(TimeGenerated)
by AwsAccountId, AwsRegion, AwsSecurityFindingTitle, AwsSecurityFindingDescription,
AwsSecurityFindingId, ComplianceSecurityControlId, QueueArn
Indicators
These rows show field, operator, and value matches.
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AwsAccountId | summarize |
AwsRegion | summarize |
AwsSecurityFindingDescription | summarize |
AwsSecurityFindingId | summarize |
AwsSecurityFindingTitle | summarize |
ComplianceSecurityControlId | summarize |
QueueArn | summarize |
TimeGenerated | summarize |
AWSCloudTrail - S3 bucket suspicious ransomware activity
#Detects a ransomware-like sequence where objects are read from an S3 bucket and then overwritten using an external KMS key. This pattern can indicate malicious encryption and potential data denial in the bucket.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Impact |
Telemetry Coverage
Rules Detecting the Same Action
These rules filter on the same operation.
- AWS Exfiltration via Anomalous GetObject API Activity (Splunk)
- AWSCloudTrail - S3 Object Exfiltration from Anonymous User (Kusto)
- AWSCloudTrail - Successful brute force attack on S3 Bucket (Kusto)
- AWSCloudTrail - Suspicious command sent to EC2 (Kusto)
- S3 Access Via VPC Endpoint From External IP (Panther)
- Suspicious access of BEC related documents in AWS S3 buckets (Kusto)
Rule Body
id: b442b9e2-5cc4-4129-a85b-a5ef38a9e5f0
name: AWSCloudTrail - S3 bucket suspicious ransomware activity
description: |
Detects a ransomware-like sequence where objects are read from an S3 bucket and then overwritten using an
external KMS key. This pattern can indicate malicious encryption and potential data denial in the bucket.
severity: High
status: Available
requiredDataConnectors:
- connectorId: AWS
dataTypes:
- AWSCloudTrail
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Impact
relevantTechniques:
- T1486
query: |
let timeframe = 1h;
let lookback = 2h;
// The attacker downloads the object(s) from the compromised bucket
let GetObject = AWSCloudTrail
| where TimeGenerated >= ago(lookback)
| where EventName == "GetObject" and isempty(ErrorCode) and isempty(ErrorMessage)
| extend bucketName = tostring(parse_json(RequestParameters).bucketName), keyName = tostring(parse_json(RequestParameters).key)
| project-rename StartTime = TimeGenerated;
// Then, the attacker overwrites the same object(s) but encrypted with his own key
let PutObject = AWSCloudTrail
| where TimeGenerated >= ago(timeframe)
| where EventName == "PutObject" and isempty(ErrorCode) and isempty(ErrorMessage)
| extend bucketName = tostring(parse_json(RequestParameters).bucketName), keyName = tostring(parse_json(RequestParameters).key)
| extend kmsId = tostring(parse_json(RequestParameters).["x-amz-server-side-encryption-aws-kms-key-id"])
| where tostring(kmsId) !has tostring(RecipientAccountId) and kmsId <> "";
PutObject
| join kind=inner
(
GetObject
)
on $left.bucketName == $right.bucketName, $left.keyName == $right.keyName
| where TimeGenerated > StartTime
| 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]), "")
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: AccountUPNSuffix
- identifier: CloudAppAccountId
columnName: RecipientAccountId
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SourceIpAddress
customDetails:
bucketName: bucketName
keyName: keyName
kmsId: kmsId
RecipientAccountId: RecipientAccountId
alertDetailsOverride:
alertDisplayNameFormat: 'AWS S3 ransomware-like overwrite activity by {{AccountName}}'
alertDescriptionFormat: 'Detected GetObject followed by encrypted PutObject activity in bucket {{bucketName}} from {{SourceIpAddress}} for account {{RecipientAccountId}}.'
version: 1.0.2
kind: Scheduled
Stages and Predicates
Parameters
let timeframe = 1h;
let lookback = 2h;
let PutObject is inlined into the numbered stages below.
Let Binding: GetObject
let GetObject = AWSCloudTrail
| where TimeGenerated >= ago(lookback)
| where EventName == "GetObject" and isempty(ErrorCode) and isempty(ErrorMessage)
| extend bucketName = tostring(parse_json(RequestParameters).bucketName), keyName = tostring(parse_json(RequestParameters).key)
| project-rename StartTime = TimeGenerated;
Stages 1 to 6 define let PutObject as the rule's main pipeline source. Stages 7 to 9 use it.
Stage 1: source
AWSCloudTrail
Stage 2: where
| where TimeGenerated >= ago(timeframe)
Stage 3: where
| where EventName == "PutObject" and isempty(ErrorCode) and isempty(ErrorMessage)
Stage 4: extend
| extend bucketName = tostring(parse_json(RequestParameters).bucketName), keyName = tostring(parse_json(RequestParameters).key)
Stage 5: extend
| extend kmsId = tostring(parse_json(RequestParameters).["x-amz-server-side-encryption-aws-kms-key-id"])
Stage 6: where
| where tostring(kmsId) !has tostring(RecipientAccountId) and kmsId <> ""
Stage 7: join
PutObject
| join kind=inner
(
GetObject
)
on $left.bucketName == $right.bucketName, $left.keyName == $right.keyName
Stage 8: where
where TimeGenerated > StartTime
Stage 9: extend (4 consecutive steps)
extend AccountName, AccountUPNSuffix, UserIdentityArn, UserName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ErrorCode | is_null | field:"ErrorCode" kind:is_null | |
ErrorMessage | is_null | field:"ErrorMessage" kind:is_null | |
EventName | eq |
| field:"EventName" kind:eq |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
bucketName | extend |
keyName | extend |
kmsId | extend |
UserIdentityArn | extend |
UserName | extend |
AccountName | extend |
AccountUPNSuffix | extend |
Azure secure score sign in risk policy
#'This query searches for an active Azure Premium P2 license is required to use and edit this policy. You will be required to have setup the MFA Policy before activating this policy'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Impact |
Rule Body
id: 5231D757-A5B5-4CA7-A91B-AA3702970E02
name: Azure secure score sign in risk policy
description: |
'This query searches for an active Azure Premium P2 license is required to use and edit this policy.
You will be required to have setup the MFA Policy before activating this policy'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: SenservaPro
dataTypes:
- SenservaPro_CL
queryFrequency: 6h
queryPeriod: 6h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Impact
relevantTechniques:
- T1529
query: |
SenservaPro_CL
| where ControlName_s == 'AzureSecureScoreSignInRiskPolicy'
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: ControlName_s
- identifier: AadTenantId
columnName: TenantId
- identifier: DisplayName
columnName: TenantDisplayName_s
- entityType: SecurityGroup
fieldMappings:
- identifier: DistinguishedName
columnName: Group_s
- entityType: AzureResource
fieldMappings:
- identifier: ResourceId
columnName: SourceSystem
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
SenservaPro_CL
Stage 2: where
| where ControlName_s == 'AzureSecureScoreSignInRiskPolicy'
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ControlName_s | eq |
| field:"ControlName_s" kind:eq value:"AzureSecureScoreSignInRiskPolicy" |
Backup Repository Deleted
#Detects when a backup repository is deleted from Veeam Backup & Replication. This might indicate unauthorized removal of critical components.
Rule Body
id: 73b4d1d5-c357-4350-bb58-924684a4792a
name: Backup Repository Deleted
description: Detects when a backup repository is deleted from Veeam Backup & Replication.
This might indicate unauthorized removal of critical components.
severity: High
status: Available
requiredDataConnectors:
- connectorId: Syslog
dataTypes:
- Syslog
- connectorId: SyslogAma
dataTypes:
- Syslog
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
eventGroupingSettings:
aggregationKind: AlertPerResult
tactics: []
relevantTechniques: []
query: "Veeam_GetSecurityEvents\n| where instanceId == 28200\n| extend Name = extract(\"\
Name=\\\"(?<Name>[^\\\"]*)\\\"\", 1, SyslogMessage)\n| project\n Date = format_datetime(TimeGenerated,\
\ 'dd.MM.yyyy HH:mm'),\n DataSource = original_host,\n EventId = instanceId,\n\
\ UserName = user,\n [\"Object Name\"] = Name,\n MessageDetails = Description,\n\
\ Severity = SeverityDescription"
version: 1.0.1
kind: Scheduled
customDetails:
Date: Date
VbrHostName: DataSource
EventId: EventId
MessageDetails: MessageDetails
Severity: Severity
Stages and Predicates
Stage 1: source
Veeam_GetSecurityEvents
Stage 2: where
| where instanceId == 28200
Stage 3: extend
| extend Name = extract("Name=\"(?<Name>[^\"]*)\"", 1, SyslogMessage)
Stage 4: project
| project
Date = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),
DataSource = original_host,
EventId = instanceId,
UserName = user,
["Object Name"] = Name,
MessageDetails = Description,
Severity = SeverityDescription
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
instanceId | eq |
| field:"instanceId" kind:eq value:"28200" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DataSource | project |
Date | project |
EventId | project |
MessageDetails | project |
Object Name | project |
Severity | project |
UserName | project |
Bitglass - New admin user
#'Detects new admin user.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Privilege Escalation |
Rule Body
id: 8c8602e6-315d-400f-9d1e-23bbdee1dbfe
name: Bitglass - New admin user
description: |
'Detects new admin user.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: Bitglass
dataTypes:
- Bitglass
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- PrivilegeEscalation
relevantTechniques:
- T1078
query: |
Bitglass
| where EventType =~ 'admin'
| where EventResultDetails has_all ('User', 'Promoted to administrator')
| extend AccountCustomEntity = User
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountCustomEntity
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
Bitglass
Stage 2: where
| where EventType =~ 'admin'
Stage 3: where
| where EventResultDetails has_all ('User', 'Promoted to administrator')
Stage 4: extend
| extend AccountCustomEntity = User
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventResultDetails | match |
| field:"EventResultDetails" kind:match |
EventType | eq |
| field:"EventType" kind:eq value:"admin" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AccountCustomEntity | extend |
Checkpoint - Pending Phishing emails
#This query searches for phishing emails that are pending action
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: a97e2333-b7de-4c14-9700-e652a1dbef26
name: Checkpoint - Pending Phishing emails
apiVersion: 2021-09-01-preview
description: This query searches for phishing emails that are pending action
displayName: Checkpoint - Pending Phishing emails
severity: High
enabled: true
query: CheckpointHEC_CL | where EventCurrentState == "new" and EventCategory == "phishing"
queryFrequency: 5m
queryPeriod: 15m
requiredDataConnectors:
- connectorId: CheckpointHECConnection
dataTypes:
- CheckpointHEC_CL
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1566
suppressionDuration: 5h
suppressionEnabled: false
alertRuleTemplateName:
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: 1d
matchingMethod: AllEntities
eventGroupingSettings:
aggregationKind: SingleAlert
alertDetailsOverride:
customDetails:
EmailID: EmailEmailId
entityMappings:
- entityType: MailMessage
fieldMappings:
- identifier: Sender
columnName: EmailFromEmail
- identifier: NetworkMessageId
columnName: EmailMessageId
- identifier: Subject
columnName: EmailSubject
- entityType: Mailbox
fieldMappings:
- identifier: MailboxPrimaryAddress
columnName: EmailTo
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
CheckpointHEC_CL
Stage 2: where
| where EventCurrentState == "new" and EventCategory == "phishing"
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventCategory | eq |
| field:"EventCategory" kind:eq value:"phishing" |
EventCurrentState | eq |
| field:"EventCurrentState" kind:eq value:"new" |
Cisco Cloud Security - Windows PowerShell User-Agent Detected
#'Rule helps to detect Powershell user-agent activity by an unusual process other than a web browser.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Execution | |
| Stealth | |
| Command & Control |
Rule Body
id: b12b3dab-d973-45af-b07e-e29bb34d8db9
name: Cisco Cloud Security - Windows PowerShell User-Agent Detected
description: |
'Rule helps to detect Powershell user-agent activity by an unusual process other than a web browser.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: CiscoUmbrellaDataConnector
dataTypes:
- Cisco_Umbrella_proxy_CL
queryFrequency: 15m
queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandAndControl
- DefenseEvasion
- Execution
relevantTechniques:
- T1132
- T1027
- T1059.001
query: |
Cisco_Umbrella
| where EventType == "proxylogs"
| where HttpUserAgentOriginal contains "WindowsPowerShell"
| extend Message = "Windows PowerShell User Agent"
| project TimeGenerated, Message, SrcIpAddr, DstIpAddr, UrlOriginal, HttpUserAgentOriginal
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: UrlOriginal
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SrcIpAddr
version: 1.1.3
kind: Scheduled
Stages and Predicates
Stage 1: source
Cisco_Umbrella
Stage 2: where
| where EventType == "proxylogs"
Stage 3: where
| where HttpUserAgentOriginal contains "WindowsPowerShell"
Stage 4: extend
| extend Message = "Windows PowerShell User Agent"
Stage 5: project
| project TimeGenerated, Message, SrcIpAddr, DstIpAddr, UrlOriginal, HttpUserAgentOriginal
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventType | eq |
| field:"EventType" kind:eq value:"proxylogs" |
HttpUserAgentOriginal | contains |
| field:"HttpUserAgentOriginal" kind:contains value:"WindowsPowerShell" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DstIpAddr | project |
HttpUserAgentOriginal | project |
Message | project |
SrcIpAddr | project |
TimeGenerated | project |
UrlOriginal | project |
Cisco SEG - Suspicious link
#'Detects mails with suspicious links.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: 506291dd-8050-4c98-a92f-58e376080a0a
name: Cisco SEG - Suspicious link
description: |
'Detects mails with suspicious links.'
severity: High
status: Available
requiredDataConnectors:
- connectorId: CefAma
dataTypes:
- CommonSecurityLog
queryFrequency: 15m
queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1566
query: |
let bl_cat = dynamic(['Adult', 'Hacking', 'Cheating and Plagiarism', 'Child Abuse Content', 'Dating', 'Illegal Activities', 'Pornography']);
CiscoSEGEvent
| where NetworkDirection =~ 'Incoming'
| where tostring(AdditionalFields) has 'ESAURLDetails'
| extend link_cat = extract(@"'Category': '(.*?)'", 1, tostring(AdditionalFields))
| where link_cat in~ (bl_cat)
| extend AccountCustomEntity = DstUserName
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountCustomEntity
version: 1.0.3
kind: Scheduled
Stages and Predicates
Parameters
let bl_cat = dynamic(['Adult', 'Hacking', 'Cheating and Plagiarism', 'Child Abuse Content', 'Dating', 'Illegal Activities', 'Pornography']);
Stage 1: source
CiscoSEGEvent
Stage 2: where
| where NetworkDirection =~ 'Incoming'
Stage 3: where
| where tostring(AdditionalFields) has 'ESAURLDetails'
Stage 4: extend
| extend link_cat = extract(@"'Category': '(.*?)'", 1, tostring(AdditionalFields))
Stage 5: where
| where link_cat in~ (bl_cat)
Stage 6: extend
| extend AccountCustomEntity = DstUserName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
AdditionalFields | match |
| field:"AdditionalFields" kind:match value:"ESAURLDetails" |
NetworkDirection | eq |
| field:"NetworkDirection" kind:eq value:"Incoming" |
link_cat | in |
| field:"link_cat" kind:in |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
link_cat | extend |
AccountCustomEntity | extend |
Cisco SEG - Unscannable attacment
#'Detects unscannable attachments in mails.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: c66b8ced-8c76-415b-a0f3-08c7030a857d
name: Cisco SEG - Unscannable attacment
description: |
'Detects unscannable attachments in mails.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: CefAma
dataTypes:
- CommonSecurityLog
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1566
query: |
CiscoSEGEvent
| where NetworkDirection =~ 'Incoming'
| where tostring(AdditionalFields) has 'ESAAMPVerdict'
| extend amp_verdict = extract(@'ESAAMPVerdict":"(NOT_EVALUATED|CLEAN|FA_PENDING|UNKNOWN|SKIPPED|UNSCANNABLE|LOW_RISK|MALICIOUS)"', 1, tostring(AdditionalFields))
| where amp_verdict =~ 'UNSCANNABLE'
| extend AccountCustomEntity = DstUserName
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountCustomEntity
version: 1.0.3
kind: Scheduled
Stages and Predicates
Stage 1: source
CiscoSEGEvent
Stage 2: where
| where NetworkDirection =~ 'Incoming'
Stage 3: where
| where tostring(AdditionalFields) has 'ESAAMPVerdict'
Stage 4: extend
| extend amp_verdict = extract(@'ESAAMPVerdict":"(NOT_EVALUATED|CLEAN|FA_PENDING|UNKNOWN|SKIPPED|UNSCANNABLE|LOW_RISK|MALICIOUS)"', 1, tostring(AdditionalFields))
Stage 5: where
| where amp_verdict =~ 'UNSCANNABLE'
Stage 6: extend
| extend AccountCustomEntity = DstUserName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
AdditionalFields | match |
| field:"AdditionalFields" kind:match value:"ESAAMPVerdict" |
NetworkDirection | eq |
| field:"NetworkDirection" kind:eq value:"Incoming" |
amp_verdict | eq |
| field:"amp_verdict" kind:eq value:"UNSCANNABLE" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
amp_verdict | extend |
AccountCustomEntity | extend |
Claroty - Login to uncommon location
#Detects user login to uncommon location.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: e7dbcbc3-b18f-4635-b27c-718195c369f1
name: Claroty - Login to uncommon location
description: 'Detects user login to uncommon location.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: CefAma
dataTypes:
- CommonSecurityLog
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1190
- T1133
query: |
let usr_sites = ClarotyEvent
| where TimeGenerated > ago(14d)
| where EventType has 'Login to SRA succeeded'
| extend Site = column_ifexists("site_name","")
| where isnotempty(Site)
| extend SrcUsername = extract(@'User\s(.*?)\slogged', 1, EventMessage)
| where isnotempty(SrcUsername)
| summarize all_loc = make_set(tostring(Site)) by SrcUsername;
ClarotyEvent
| where TimeGenerated > ago(14d)
| where EventType has 'Login to SRA succeeded'
| extend Site = column_ifexists("site_name","")
| where isnotempty(Site)
| extend SrcUsername = extract(@'User\s(.*?)\slogged', 1, EventMessage)
| where isnotempty(SrcUsername)
| join kind=leftouter (usr_sites) on SrcUsername
| where isempty(all_loc) or not(set_has_element(all_loc, tostring(Site)))
| extend SrcIpAddr
| summarize StartTime=min(TimeGenerated), EndTime=max(TimeGenerated), EventCount=count(), Sites=make_set(Site, 100), KnownSites=any(all_loc) by SrcUsername, SrcIpAddr, Site, EventType, EventMessage
| extend UncommonSiteCount = array_length(Sites)
| project StartTime, EndTime, SrcUsername, SrcIpAddr, Site, EventType, EventMessage, EventCount, UncommonSiteCount, KnownSites
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SrcIpAddr
version: 1.0.4
kind: Scheduled
Stages and Predicates
Let Binding: usr_sites
let usr_sites = ClarotyEvent
| where TimeGenerated > ago(14d)
| where EventType has 'Login to SRA succeeded'
| extend Site = column_ifexists("site_name","")
| where isnotempty(Site)
| extend SrcUsername = extract(@'User\s(.*?)\slogged', 1, EventMessage)
| where isnotempty(SrcUsername)
| summarize all_loc = make_set(tostring(Site)) by SrcUsername;
Stage 1: source
ClarotyEvent
Stage 2: where
| where TimeGenerated > ago(14d)
Stage 3: where
| where EventType has 'Login to SRA succeeded'
Stage 4: extend
| extend Site = column_ifexists("site_name","")
Stage 5: where
| where isnotempty(Site)
Stage 6: extend
| extend SrcUsername = extract(@'User\s(.*?)\slogged', 1, EventMessage)
Stage 7: where
| where isnotempty(SrcUsername)
Stage 8: join
| join kind=leftouter (usr_sites) on SrcUsername
Stage 9: where
where (not (all_loc =~ "Site") or isempty(all_loc))
Stage 10: extend
extend SrcIpAddr
Stage 11: summarize
summarize EndTime, EventCount, KnownSites, Sites, StartTime by SrcUsername, SrcIpAddr, Site, EventType, EventMessage
Stage 12: extend
extend UncommonSiteCount
Stage 13: project
project EndTime, EventCount, EventMessage, EventType, KnownSites, Site, SrcIpAddr, SrcUsername, StartTime, UncommonSiteCount
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventType | match |
| field:"EventType" kind:match value:"Login to SRA succeeded" |
Site | is_not_null | field:"Site" kind:is_not_null | |
SrcUsername | is_not_null | field:"SrcUsername" kind:is_not_null | |
all_loc | is_null | field:"all_loc" kind:is_null |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
EndTime | project |
EventCount | project |
EventMessage | project |
EventType | project |
KnownSites | project |
Site | project |
SrcIpAddr | project |
SrcUsername | project |
StartTime | project |
UncommonSiteCount | project |
Cloud Gateway Pool Settings Updated
#Detects when cloud gateway pool settings are updated in Veeam Backup & Replication. This might indicate configuration changes that require review.
Rule Body
id: 2b3b59eb-ea7c-45f6-9df8-8dbaed632317
name: Cloud Gateway Pool Settings Updated
description: Detects when cloud gateway pool settings are updated in Veeam Backup
& Replication. This might indicate configuration changes that require review.
severity: Informational
status: Available
requiredDataConnectors:
- connectorId: Syslog
dataTypes:
- Syslog
- connectorId: SyslogAma
dataTypes:
- Syslog
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
eventGroupingSettings:
aggregationKind: AlertPerResult
tactics: []
relevantTechniques: []
query: "Veeam_GetSecurityEvents\n| where instanceId == 24142\n| project\n Date\
\ = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),\n DataSource = original_host,\n\
\ EventId = instanceId,\n [\"User Name\"] = user,\n MessageDetails = Description,\n\
\ Severity = SeverityDescription"
version: 1.0.1
kind: Scheduled
customDetails:
Date: Date
VbrHostName: DataSource
EventId: EventId
MessageDetails: MessageDetails
Severity: Severity
Stages and Predicates
Stage 1: source
Veeam_GetSecurityEvents
Stage 2: where
| where instanceId == 24142
Stage 3: project
| project
Date = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),
DataSource = original_host,
EventId = instanceId,
["User Name"] = user,
MessageDetails = Description,
Severity = SeverityDescription
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
instanceId | eq |
| field:"instanceId" kind:eq value:"24142" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DataSource | project |
Date | project |
EventId | project |
MessageDetails | project |
Severity | project |
User Name | project |
Cognni Incidents for Highly Sensitive Financial Information
#This is a third-party alert feed, not a detection over modeled telemetry. The vendor product raised the finding; this rule forwards it into the SIEM. It is searchable for reference but is excluded from the detection-rule browse and the ATT&CK coverage matrix.
'Display incidents in which highly sensitive financial information was placed at risk by user sharing.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Collection |
Rule Body
id: 7ebb7386-6c99-4331-aab1-a185a603eb47
name: Cognni Incidents for Highly Sensitive Financial Information
description: |
'Display incidents in which highly sensitive financial information was placed at risk by user sharing.'
severity: High
requiredDataConnectors:
- connectorId: CognniSentinelDataConnector
dataTypes:
- CognniIncidents_CL
queryFrequency: 5h
queryPeriod: 5h
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
- Collection
relevantTechniques:
- T1530
query: |
let highRisk = 3;
let financial = 'Financial Information';
CognniIncidents_CL
| where Severity == highRisk
| where informationType_s == financial
| where TimeGenerated >= ago(5h)
| extend AccountCustomEntity = userId_s
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
version: 1.0.0
kind: Scheduled
Stages and Predicates
Parameters
let highRisk = 3;
let financial = 'Financial Information';
Stage 1: source
CognniIncidents_CL
Stage 2: where
| where Severity == highRisk
Stage 3: where
| where informationType_s == financial
Stage 4: where
| where TimeGenerated >= ago(5h)
Stage 5: extend
| extend AccountCustomEntity = userId_s
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Severity | eq |
| field:"Severity" kind:eq value:"3" |
informationType_s | eq |
| field:"informationType_s" kind:eq value:"Financial Information" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AccountCustomEntity | extend |
Detecting Impossible travel with mailbox permission tampering & Privilege Escalation attempt
#This hunting query will alert on any Impossible travel activity in correlation with mailbox permission tampering followed by account being added to a PIM managed privileged group. Ensure this impossible travel incident with increase of privileges is legitimate in your environment.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Privilege Escalation |
Telemetry Coverage
Rules Detecting the Same Action
These rules filter on the same operation.
- Conditional Access - Dynamic Group Exclusion Changes (Kusto)
- Detect suspicious conditional access policy modifications (Kusto)
- Entra ID Successful Group Deletion (YARA-L)
- Guest accounts added in Entra ID Groups other than the ones specified (Kusto)
- High risk Office operation conducted by IP Address that recently attempted to log into a disabled account (Kusto)
- Rare and potentially high-risk Office operations (Kusto)
- User Removed From Group With CA Policy Modification Access (Sigma)
Rule Body
id: 1399664f-9434-497c-9cde-42e4d74ae20e
name: Detecting Impossible travel with mailbox permission tampering & Privilege Escalation attempt
description: |
'This hunting query will alert on any Impossible travel activity in correlation with mailbox permission tampering followed by account being added to a PIM managed privileged group.
Ensure this impossible travel incident with increase of privileges is legitimate in your environment.'
severity: Medium
requiredDataConnectors:
- connectorId: AzureSecurityCenter
dataTypes:
- SecurityAlert (ASC)
- connectorId: Office365
dataTypes:
- OfficeActivity
- connectorId: AzureActivity
dataTypes:
- AzureActivity
- connectorId: AzureActiveDirectory
dataTypes:
- AuditLogs
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
- PrivilegeEscalation
relevantTechniques:
- T1078
- T1548
query: |
SecurityAlert
| where AlertName == "Impossible travel activity"
| extend Extprop = parsejson(Entities)
| mv-expand Extprop
| extend Extprop = parsejson(Extprop)
| extend CmdLine = iff(Extprop['Type']=="process", Extprop['CommandLine'], '')
| extend File = iff(Extprop['Type']=="file", Extprop['Name'], '')
| extend Account = Extprop['Name']
| extend Domain = Extprop['UPNSuffix']
| extend Account = iif(isnotempty(Domain) and Extprop['Type']=="account", tolower(strcat(Account, "@", Domain)), iif(Extprop['Type']=="account", tolower(Account), ""))
| extend IpAddress = iff(Extprop["Type"] == "ip",Extprop['Address'], '')
| extend Process = iff(isnotempty(CmdLine), CmdLine, File)
| project TimeGenerated,Account,IpAddress,CompromisedEntity,Description,ProviderName,ResourceId
| join kind=inner
(
OfficeActivity
| where Operation =~ "Add-MailboxPermission"
| extend value = tostring(parse_json(Parameters)[3].Value)
| where value contains "FullAccess"
| where ResultStatus == "True"
| project Parameters,TimeGenerated,value,RecordType,Operation,OrganizationId,UserType,UserKey,OfficeWorkload,ResultStatus,OfficeObjectId,UserId,ClientIP,ExternalAccess,OriginatingServer,OrganizationName,TenantId,ElevationTime,SourceSystem,OfficeId,OfficeTenantId,Type,SourceRecordId
) on $left.Account == $right.UserId
| join kind=inner
(
AuditLogs
| where ActivityDisplayName =~ "Add eligible member to role in PIM requested (timebound)"
| where AADOperationType =~ "CreateRequestEligibleRole"
| where TargetResources has_any ("-PRIV", "Administrator", "Security")
| extend BuiltinRole = tostring(parse_json(TargetResources[0].displayName))
| extend CustomGroup = tostring(parse_json(TargetResources[3].displayName))
| extend TargetAccount = tostring(parse_json(TargetResources[2].displayName))
| extend Initiatedby = Identity
| project TimeGenerated, ActivityDisplayName, AADOperationType, Initiatedby, TargetAccount, BuiltinRole, CustomGroup, LoggedByService, Result, ResourceId, Id
| sort by TimeGenerated desc
) on $left.UserId == $right.Initiatedby
| extend AccountName = tostring(split(Initiatedby, "@")[0]), AccountUPNSuffix = tostring(split(Initiatedby, "@")[1])
| project AADOperationType, ActivityDisplayName,AccountName, AccountUPNSuffix, Id,ResourceId,IpAddress
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: AccountUPNSuffix
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IpAddress
version: 1.0.3
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Microsoft Security Research
support:
tier: Community
categories:
domains: [ "Security - Others", "Identity" ]
Stages and Predicates
Stage 1: source
SecurityAlert
Stage 2: where
| where AlertName == "Impossible travel activity"
Stage 3: extend
| extend Extprop = parsejson(Entities)
Stage 4: mv-expand
| mv-expand Extprop
Stage 5: extend (8 consecutive steps)
| extend Extprop = parsejson(Extprop)
| extend CmdLine = iff(Extprop['Type']=="process", Extprop['CommandLine'], '')
| extend File = iff(Extprop['Type']=="file", Extprop['Name'], '')
| extend Account = Extprop['Name']
| extend Domain = Extprop['UPNSuffix']
| extend Account = iif(isnotempty(Domain) and Extprop['Type']=="account", tolower(strcat(Account, "@", Domain)), iif(Extprop['Type']=="account", tolower(Account), ""))
| extend IpAddress = iff(Extprop["Type"] == "ip",Extprop['Address'], '')
| extend Process = iff(isnotempty(CmdLine), CmdLine, File)
Stage 6: project
| project TimeGenerated,Account,IpAddress,CompromisedEntity,Description,ProviderName,ResourceId
Stage 7: join
| join kind=inner
(
OfficeActivity
| where Operation =~ "Add-MailboxPermission"
| extend value = tostring(parse_json(Parameters)[3].Value)
| where value contains "FullAccess"
| where ResultStatus == "True"
| project Parameters,TimeGenerated,value,RecordType,Operation,OrganizationId,UserType,UserKey,OfficeWorkload,ResultStatus,OfficeObjectId,UserId,ClientIP,ExternalAccess,OriginatingServer,OrganizationName,TenantId,ElevationTime,SourceSystem,OfficeId,OfficeTenantId,Type,SourceRecordId
) on $left.Account == $right.UserId
Stage 8: join
| join kind=inner
(
AuditLogs
| where ActivityDisplayName =~ "Add eligible member to role in PIM requested (timebound)"
| where AADOperationType =~ "CreateRequestEligibleRole"
| where TargetResources has_any ("-PRIV", "Administrator", "Security")
| extend BuiltinRole = tostring(parse_json(TargetResources[0].displayName))
| extend CustomGroup = tostring(parse_json(TargetResources[3].displayName))
| extend TargetAccount = tostring(parse_json(TargetResources[2].displayName))
| extend Initiatedby = Identity
| project TimeGenerated, ActivityDisplayName, AADOperationType, Initiatedby, TargetAccount, BuiltinRole, CustomGroup, LoggedByService, Result, ResourceId, Id
| sort by TimeGenerated desc
) on $left.UserId == $right.Initiatedby
Stage 9: extend
extend AccountName, AccountUPNSuffix
Stage 10: project
project AADOperationType, AccountName, AccountUPNSuffix, ActivityDisplayName, Id, IpAddress, ResourceId
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
AADOperationType | eq |
| field:"AADOperationType" kind:eq value:"CreateRequestEligibleRole" |
ActivityDisplayName | eq |
| field:"ActivityDisplayName" kind:eq value:"Add eligible member to role in PIM requested (timebound)" |
AlertName | eq |
| field:"AlertName" kind:eq value:"Impossible travel activity" |
Operation | eq |
| field:"Operation" kind:eq value:"Add-MailboxPermission" |
ResultStatus | eq |
| field:"ResultStatus" kind:eq value:"True" |
TargetResources | match |
| field:"TargetResources" kind:match |
value | contains |
| field:"value" kind:contains value:"FullAccess" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AADOperationType | project |
AccountName | project |
AccountUPNSuffix | project |
ActivityDisplayName | project |
Id | project |
IpAddress | project |
ResourceId | project |
Object Storage Deleted
#Detects when an object storage is deleted from Veeam Backup & Replication. This might indicate unauthorized removal of critical components.
Rule Body
id: 6e4d1832-2cf9-410d-a5e2-c12b33c7d9f7
name: Object Storage Deleted
description: Detects when an object storage is deleted from Veeam Backup & Replication.
This might indicate unauthorized removal of critical components.
severity: High
status: Available
requiredDataConnectors:
- connectorId: Syslog
dataTypes:
- Syslog
- connectorId: SyslogAma
dataTypes:
- Syslog
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
eventGroupingSettings:
aggregationKind: AlertPerResult
tactics: []
relevantTechniques: []
query: "Veeam_GetSecurityEvents\n| where instanceId == 28980\n| extend Name = extract(\"\
Name=\\\"(?<Name>[^\\\"]*)\\\"\", 1, SyslogMessage)\n| project\n Date = format_datetime(TimeGenerated,\
\ 'dd.MM.yyyy HH:mm'),\n DataSource = original_host,\n EventId = instanceId,\n\
\ UserName = user,\n [\"Data SourceName\"] = Name,\n MessageDetails = Description,\n\
\ Severity = SeverityDescription"
version: 1.0.1
kind: Scheduled
customDetails:
Date: Date
VbrHostName: DataSource
EventId: EventId
MessageDetails: MessageDetails
Severity: Severity
Stages and Predicates
Stage 1: source
Veeam_GetSecurityEvents
Stage 2: where
| where instanceId == 28980
Stage 3: extend
| extend Name = extract("Name=\"(?<Name>[^\"]*)\"", 1, SyslogMessage)
Stage 4: project
| project
Date = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),
DataSource = original_host,
EventId = instanceId,
UserName = user,
["Data SourceName"] = Name,
MessageDetails = Description,
Severity = SeverityDescription
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
instanceId | eq |
| field:"instanceId" kind:eq value:"28980" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Data SourceName | project |
DataSource | project |
Date | project |
EventId | project |
MessageDetails | project |
Severity | project |
UserName | project |
PaloAlto - Possible attack without response
#'Detects possible attack without response.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: b6d54840-51d3-11ec-bf63-0242ac130002
name: PaloAlto - Possible attack without response
description: |
'Detects possible attack without response.'
severity: High
status: Available
requiredDataConnectors:
- connectorId: CefAma
dataTypes:
- CommonSecurityLog
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1190
- T1133
query: |
PaloAltoCDLEvent
| where EventResourceId =~ 'THREAT'
| where DvcAction !has "block" or DvcAction !has "override" or DvcAction !has "deny"
| extend AccountCustomEntity = DstUsername, IPCustomEntity = SrcIpAddr, UrlCustomEntity = Url
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
- entityType: URL
fieldMappings:
- identifier: Url
columnName: UrlCustomEntity
version: 1.0.4
kind: Scheduled
Stages and Predicates
Stage 1: source
PaloAltoCDLEvent
Stage 2: where
| where EventResourceId =~ 'THREAT'
Stage 3: where
| where DvcAction !has "block" or DvcAction !has "override" or DvcAction !has "deny"
Stage 4: extend
| extend AccountCustomEntity = DstUsername, IPCustomEntity = SrcIpAddr, UrlCustomEntity = Url
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventResourceId | eq |
| field:"EventResourceId" kind:eq value:"THREAT" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AccountCustomEntity | extend |
IPCustomEntity | extend |
UrlCustomEntity | extend |
Recorded Future Sandbox - Malicious Email Attachment
#'Creates incidents when Recorded Future Sandbox detects malicious files from Outlook email attachments'
Rule Body
id: a1b2c3d4-5678-90ab-cdef-222222222222
name: Recorded Future Sandbox - Malicious Email Attachment
description: |
'Creates incidents when Recorded Future Sandbox detects malicious files from Outlook email attachments'
severity: High
status: Available
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics: []
relevantTechniques: []
query: |
RecordedFutureSandboxResults_CL
| where TimeGenerated >= now(-1h)
| where Source_s == "OutlookAttachment"
| where toint(SandboxScore_s) >= 50
eventGroupingSettings:
aggregationKind: AlertPerResult
alertDetailsOverride:
alertDisplayNameFormat: 'Malicious Email Attachment: {{FileName_s}} from {{EmailFrom_s}}'
alertDescriptionFormat: |
_Recorded Future Sandbox - Malicious Email Attachment Detected_
**Sandbox Score:** {{SandboxScore_s}}/100
**Verdict:** {{SandboxVerdict_s}}
**Sample ID:** {{SampleId_s}}
A malicious file was detected in an email attachment. Review the full sandbox report and investigate the sender.
customDetails:
RFLabel: SourceSystem
Source: Source_s
SandboxScore: SandboxScore_s
SandboxVerdict: SandboxVerdict_s
FileName: FileName_s
SampleId: SampleId_s
EmailFrom: EmailFrom_s
EmailTo: EmailTo_s
entityMappings:
- entityType: File
fieldMappings:
- identifier: Name
columnName: FileName_s
- entityType: Mailbox
fieldMappings:
- identifier: MailboxPrimaryAddress
columnName: EmailFrom_s
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: 1h
matchingMethod: Selected
groupByCustomDetails:
- EmailFrom
version: 1.0.0
kind: NRT
Stages and Predicates
Stage 1: source
RecordedFutureSandboxResults_CL
Stage 2: where
| where TimeGenerated >= now(-1h)
Stage 3: where
| where Source_s == "OutlookAttachment"
Stage 4: where
| where toint(SandboxScore_s) >= 50
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
SandboxScore_s | ge |
| field:"SandboxScore_s" kind:ge value:"50" |
Source_s | eq |
| field:"Source_s" kind:eq value:"OutlookAttachment" |
Scale-Out Backup Repository Settings Updated
#Detects when scale-out backup repository settings are updated in Veeam Backup & Replication. This might indicate configuration changes that require review.
Rule Body
id: 12006091-95a7-4f21-b474-f74b0480a138
name: Scale-Out Backup Repository Settings Updated
description: Detects when scale-out backup repository settings are updated in Veeam
Backup & Replication. This might indicate configuration changes that require review.
severity: Low
status: Available
requiredDataConnectors:
- connectorId: Syslog
dataTypes:
- Syslog
- connectorId: SyslogAma
dataTypes:
- Syslog
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
eventGroupingSettings:
aggregationKind: AlertPerResult
tactics: []
relevantTechniques: []
query: "Veeam_GetSecurityEvents\n| where instanceId == 30100\n| extend Name = extract(\"\
Name=\\\"([^\\\"]*)\\\"\", 1, SyslogMessage)\n| project\n Date = format_datetime(TimeGenerated,\
\ 'dd.MM.yyyy HH:mm'),\n DataSource = original_host,\n EventId = instanceId,\n\
\ UserName = user,\n [\"Object Name\"] = Name,\n MessageDetails = Description,\n\
\ Severity = SeverityDescription"
version: 1.0.1
kind: Scheduled
customDetails:
Date: Date
VbrHostName: DataSource
EventId: EventId
MessageDetails: MessageDetails
Severity: Severity
Stages and Predicates
Stage 1: source
Veeam_GetSecurityEvents
Stage 2: where
| where instanceId == 30100
Stage 3: extend
| extend Name = extract("Name=\"([^\"]*)\"", 1, SyslogMessage)
Stage 4: project
| project
Date = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),
DataSource = original_host,
EventId = instanceId,
UserName = user,
["Object Name"] = Name,
MessageDetails = Description,
Severity = SeverityDescription
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
instanceId | eq |
| field:"instanceId" kind:eq value:"30100" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DataSource | project |
Date | project |
EventId | project |
MessageDetails | project |
Object Name | project |
Severity | project |
UserName | project |
SlackAudit - Suspicious file downloaded.
#'Detects potentialy suspicious downloads.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: 132b98a5-07e9-401a-9b6f-453e52a53979
name: SlackAudit - Suspicious file downloaded.
description: |
'Detects potentialy suspicious downloads.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: SlackAuditAPI
dataTypes:
- SlackAudit_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1189
query: |
SlackAudit
| where DvcAction =~ 'file_downloaded'
| extend FileName = tostring(EntityFileName)
| extend fe = split(FileName, '.')
| extend FileExtension = iff(array_length(fe) > 1, tostring(fe[-1]), '')
| where FileName contains '.'
| where FileExtension matches regex @"^[A-Za-z]{1,4}$"
| project EntityFileName = FileName, SrcUserName
| extend AccountCustomEntity = SrcUserName
| extend FileCustomEntity = EntityFileName
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: File
fieldMappings:
- identifier: Name
columnName: FileCustomEntity
alertDetailsOverride:
alertDisplayNameFormat: 'Suspicious Slack file downloaded by {{SrcUserName}}: {{EntityFileName}}'
alertDescriptionFormat: A Slack audit file_downloaded event matched the suspicious extension heuristic for {{EntityFileName}}
by {{SrcUserName}}.
customDetails:
FileName: EntityFileName
UserName: SrcUserName
version: 1.0.1
kind: Scheduled
Stages and Predicates
Stage 1: source
SlackAudit
Stage 2: where
| where DvcAction =~ 'file_downloaded'
Stage 3: extend (3 consecutive steps)
| extend FileName = tostring(EntityFileName)
| extend fe = split(FileName, '.')
| extend FileExtension = iff(array_length(fe) > 1, tostring(fe[-1]), '')
Stage 4: where
| where FileName contains '.'
Stage 5: where
| where FileExtension matches regex @"^[A-Za-z]{1,4}$"
Stage 6: project
| project EntityFileName = FileName, SrcUserName
Stage 7: extend
| extend AccountCustomEntity = SrcUserName
Stage 8: extend
| extend FileCustomEntity = EntityFileName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
DvcAction | eq |
| field:"DvcAction" kind:eq value:"file_downloaded" |
FileExtension | regex_match |
| field:"FileExtension" kind:regex_match value:"^[A-Za-z]{1,4}$" |
FileName | contains |
| field:"FileName" kind:contains value:"." |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
EntityFileName | project |
SrcUserName | project |
AccountCustomEntity | extend |
FileCustomEntity | extend |
TacitRed - High Confidence Compromise
#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 compromised credentials with high confidence scores. High confidence findings indicate verified credential compromises that require immediate attention. Ref: https://data443.com/tacitred-attack-surface-intelligence/
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Reconnaissance | |
| Initial Access |
Rule Body
id: b2c3d4e5-f6a7-8901-bcde-f23456789012
name: TacitRed - High Confidence Compromise
version: 1.0.1
kind: Scheduled
description: |-
Detects compromised credentials with high confidence scores.
High confidence findings indicate verified credential compromises that require immediate attention.
Ref: https://data443.com/tacitred-attack-surface-intelligence/
severity: High
requiredDataConnectors:
- connectorId: TacitRedThreatIntel
dataTypes:
- TacitRed_Findings_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: GreaterThan
triggerThreshold: 0
tactics:
- CredentialAccess
- InitialAccess
- Reconnaissance
relevantTechniques:
- T1078
- T1589
query: |-
TacitRed_Findings_CL
| where TimeGenerated >= ago(1h)
| where confidence_d >= 80
| extend
Email = tostring(email_s),
Username = tostring(username_s),
Domain = tostring(domain_s),
FindingType = tostring(findingType_s),
Confidence = todouble(confidence_d),
Source = tostring(source_s),
Severity = tostring(severity_s)
| project
TimeGenerated,
Email,
Username,
Domain,
FindingType,
Confidence,
Source,
Severity
suppressionEnabled: false
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: 5h
matchingMethod: Selected
groupByEntities:
- Account
suppressionDuration: 5h
eventGroupingSettings:
aggregationKind: AlertPerResult
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: Username
- identifier: UPNSuffix
columnName: Email
- entityType: DNS
fieldMappings:
- identifier: DomainName
columnName: Domain
Stages and Predicates
Stage 1: source
TacitRed_Findings_CL
Stage 2: where
| where TimeGenerated >= ago(1h)
Stage 3: where
| where confidence_d >= 80
Stage 4: extend
| extend
Email = tostring(email_s),
Username = tostring(username_s),
Domain = tostring(domain_s),
FindingType = tostring(findingType_s),
Confidence = todouble(confidence_d),
Source = tostring(source_s),
Severity = tostring(severity_s)
Stage 5: project
| project
TimeGenerated,
Email,
Username,
Domain,
FindingType,
Confidence,
Source,
Severity
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
confidence_d | ge |
| field:"confidence_d" kind:ge value:"80" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Confidence | project |
Domain | project |
Email | project |
FindingType | project |
Severity | project |
Source | project |
TimeGenerated | project |
Username | project |
TI map IP entity to LastPass data
#'Identifies a match in LastPass table from any IP IOC from TI'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Impact |
Rule Body
id: 2a723664-22c2-4d3e-bbec-5843b90166f3
name: TI map IP entity to LastPass data
description: |
'Identifies a match in LastPass table from any IP IOC from TI'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: LastPass
dataTypes:
- LastPassNativePoller_CL
- connectorId: ThreatIntelligence
dataTypes:
- ThreatIntelligenceIndicator
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
eventGroupingSettings:
aggregationKind: AlertPerResult
tactics:
- Impact
relevantTechniques:
- T1485
query: |
let dt_lookBack = 1h;
let ioc_lookBack = 14d;
ThreatIntelligenceIndicator
| where TimeGenerated >= ago(ioc_lookBack) and ExpirationDateTime > now()
| where Active == true
// Picking up only IOC's that contain the entities we want
| where isnotempty(NetworkIP) or isnotempty(EmailSourceIpAddress) or isnotempty(NetworkDestinationIP) or isnotempty(NetworkSourceIP)
// As there is potentially more than 1 indicator type for matching IP, taking Network IP first, then others if that is empty.
// Taking the first non-empty value based on potential IOC match availability
| extend TI_ipEntity = iff(isnotempty(NetworkIP), NetworkIP, NetworkDestinationIP)
| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(NetworkSourceIP), NetworkSourceIP, TI_ipEntity)
| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(EmailSourceIpAddress), EmailSourceIpAddress, TI_ipEntity)
| join (
LastPassNativePoller_CL | where todatetime(Time_s) >= ago(dt_lookBack)
| where Action_s != "Reporting"
// renaming time column so it is clear the log this came from
| extend LastPass_TimeGenerated = todatetime(Time_s)
)
on $left.TI_ipEntity == $right.IP_Address_s
| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
| project LatestIndicatorTime, Description, ActivityGroupNames, IndicatorId, ThreatType, Url, ExpirationDateTime, ConfidenceScore, LastPass_TimeGenerated,
TI_ipEntity, IP_Address_s, Username_s, Action_s, Data_s, NetworkIP, NetworkDestinationIP, NetworkSourceIP, EmailSourceIpAddress
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: Username_s
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IP_Address_s
- entityType: URL
fieldMappings:
- identifier: Url
columnName: Url
version: 1.0.1
kind: Scheduled
Stages and Predicates
Parameters
let dt_lookBack = 1h;
let ioc_lookBack = 14d;
Stage 1: source
ThreatIntelligenceIndicator
Stage 2: where
| where TimeGenerated >= ago(ioc_lookBack) and ExpirationDateTime > now()
Stage 3: where
| where Active == true
Stage 4: where
| where isnotempty(NetworkIP) or isnotempty(EmailSourceIpAddress) or isnotempty(NetworkDestinationIP) or isnotempty(NetworkSourceIP)
Stage 5: extend (3 consecutive steps)
| extend TI_ipEntity = iff(isnotempty(NetworkIP), NetworkIP, NetworkDestinationIP)
| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(NetworkSourceIP), NetworkSourceIP, TI_ipEntity)
| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(EmailSourceIpAddress), EmailSourceIpAddress, TI_ipEntity)
TI_ipEntity =isnotempty(NetworkIP)NetworkIPNetworkDestinationIPStage 6: join
| join (
LastPassNativePoller_CL | where todatetime(Time_s) >= ago(dt_lookBack)
| where Action_s != "Reporting"
| extend LastPass_TimeGenerated = todatetime(Time_s)
)
on $left.TI_ipEntity == $right.IP_Address_s
Stage 7: summarize
summarize LatestIndicatorTime by IndicatorId
Stage 8: project
project Action_s, ActivityGroupNames, ConfidenceScore, Data_s, Description, EmailSourceIpAddress, ExpirationDateTime, IP_Address_s, IndicatorId, LastPass_TimeGenerated, LatestIndicatorTime, NetworkDestinationIP, NetworkIP, NetworkSourceIP, TI_ipEntity, ThreatType, Url, Username_s
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Action_s | ne |
| field:"Action_s" kind:ne value:"Reporting" |
Active | eq |
| field:"Active" kind:eq value:"true" |
EmailSourceIpAddress | is_not_null | field:"EmailSourceIpAddress" kind:is_not_null | |
NetworkDestinationIP | is_not_null | field:"NetworkDestinationIP" kind:is_not_null | |
NetworkIP | is_not_null | field:"NetworkIP" kind:is_not_null | |
NetworkSourceIP | is_not_null | field:"NetworkSourceIP" kind:is_not_null |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Action_s | project |
ActivityGroupNames | project |
ConfidenceScore | project |
Data_s | project |
Description | project |
EmailSourceIpAddress | project |
ExpirationDateTime | project |
IP_Address_s | project |
IndicatorId | project |
LastPass_TimeGenerated | project |
LatestIndicatorTime | project |
NetworkDestinationIP | project |
NetworkIP | project |
NetworkSourceIP | project |
TI_ipEntity | project |
ThreatType | project |
Url | project |
Username_s | project |
User login from different countries within 3 hours (Uses Authentication Normalization)
#This query searches for successful user logins from different countries within 3 hours. To use this analytics rule, make sure you have deployed the ASIM normalization parsers
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Telemetry Coverage
Rule Body
id: 09ec8fa2-b25f-4696-bfae-05a7b85d7b9e
name: User login from different countries within 3 hours (Uses Authentication Normalization)
description: |
'This query searches for successful user logins from different countries within 3 hours.
To use this analytics rule, make sure you have deployed the [ASIM normalization parsers](https://aka.ms/ASimAuthentication)'
severity: High
requiredDataConnectors: []
queryFrequency: 3h
queryPeriod: 3h
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1078
tags:
- Id: 2954d424-f786-4677-9ffc-c24c44c6e7d5
version: 1.0.0
- Schema: ASIMAuthentication
SchemaVersion: 0.1.0
query: |
let timeframe = ago(3h);
let threshold = 2;
imAuthentication
| where TimeGenerated > timeframe
| where EventType == 'Logon'
and EventResult == 'Success'
| where isnotempty(SrcGeoCountry)
| summarize
StartTime = min(TimeGenerated)
, EndTime = max(TimeGenerated)
, Vendors = make_set(EventVendor, 128)
, Products = make_set(EventProduct, 128)
, NumOfCountries = dcount(SrcGeoCountry)
, Countries = make_set(SrcGeoCountry, 128)
by TargetUserId, TargetUsername, TargetUserType
| where NumOfCountries >= threshold
| where TargetUserType !in ("Application", "Service", "System", "Other", "Machine", "ServicePrincipal")
| extend
Name = iif(
TargetUsername contains "@"
, tostring(split(TargetUsername, '@', 0)[0])
, TargetUsername
),
UPNSuffix = iif(
TargetUsername contains "@"
, tostring(split(TargetUsername, '@', 1)[0])
, ""
)
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: TargetUserName
- identifier: Name
columnName: Name
- identifier: UPNSuffix
columnName: UPNSuffix
version: 1.2.5
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Ofer Shezaf
support:
tier: Community
categories:
domains: [ "Security - Network" ]
Stages and Predicates
Parameters
let timeframe = ago(3h);
let threshold = 2;
Stage 1: source
imAuthentication
Stage 2: where
| where TimeGenerated > timeframe
Stage 3: where
| where EventType == 'Logon'
and EventResult == 'Success'
Stage 4: where
| where isnotempty(SrcGeoCountry)
Stage 5: summarize
| summarize
StartTime = min(TimeGenerated)
, EndTime = max(TimeGenerated)
, Vendors = make_set(EventVendor, 128)
, Products = make_set(EventProduct, 128)
, NumOfCountries = dcount(SrcGeoCountry)
, Countries = make_set(SrcGeoCountry, 128)
by TargetUserId, TargetUsername, TargetUserType
Stage 6: where
| where NumOfCountries >= threshold
Stage 7: where
| where TargetUserType !in ("Application", "Service", "System", "Other", "Machine", "ServicePrincipal")
Stage 8: extend
| extend
Name = iif(
TargetUsername contains "@"
, tostring(split(TargetUsername, '@', 0)[0])
, TargetUsername
),
UPNSuffix = iif(
TargetUsername contains "@"
, tostring(split(TargetUsername, '@', 1)[0])
, ""
)
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventResult | eq |
| field:"EventResult" kind:eq value:"Success" |
EventType | eq |
| field:"ElevatedToken" kind:eq value:"Logon" |
NumOfCountries | ge |
| field:"NumOfCountries" kind:ge value:"2" |
SrcGeoCountry | is_not_null | field:"SrcGeoCountry" kind:is_not_null |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
TargetUserType | in | Application, Machine, Other, Service, ServicePrincipal, System | excludes:TargetUserType |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Countries | summarize |
EndTime | summarize |
NumOfCountries | summarize |
Products | summarize |
StartTime | summarize |
TargetUserId | summarize |
TargetUserType | summarize |
TargetUsername | summarize |
Vendors | summarize |
Name | extend |
UPNSuffix | extend |
Veeam ONE Possible Ransomware Activity (vSphere)
#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 Veeam ONE possible ransomware activity alerts for VMware vSphere.
Rule Body
id: 37d97c4d-a42f-495b-a523-376416b278b5
name: Veeam ONE Possible Ransomware Activity (vSphere)
description: Detects Veeam ONE possible ransomware activity alerts for VMware vSphere.
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 == 342
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 == 342
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
PredefinedAlarmId | eq |
| field:"PredefinedAlarmId" kind:eq value:"342" |
Wazuh - Large Number of Web errors from an IP
#'Identifies instances where Wazuh logged over 400 '403' Web Errors from one IP Address. To onboard Wazuh data into Sentinel please view: https://documentation.wazuh.com/current/cloud-security/azure/index.html'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Credential Access |
Rule Body
id: 2790795b-7dba-483e-853f-44aa0bc9c985
name: Wazuh - Large Number of Web errors from an IP
description: |
'Identifies instances where Wazuh logged over 400 '403' Web Errors from one IP Address. To onboard Wazuh data into Sentinel please view: https://documentation.wazuh.com/current/cloud-security/azure/index.html'
severity: Low
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- CredentialAccess
relevantTechniques:
- T1110
query: |
CommonSecurityLog
| where DeviceProduct =~ "Wazuh"
| where Activity has "Web server 400 error code."
| where Message has "403"
| extend HostName=substring(split(DeviceCustomString1,")")[0],1)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), NumberOfErrors = dcount(SourceIP) by HostName, SourceIP
| where NumberOfErrors > 400
| sort by NumberOfErrors desc
| extend timestamp = StartTime
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: HostName
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SourceIP
version: 1.0.5
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Jordan Ross
support:
tier: Community
categories:
domains: [ "Security - Others", "Networking" ]
Stages and Predicates
Stage 1: source
CommonSecurityLog
Stage 2: where
| where DeviceProduct =~ "Wazuh"
Stage 3: where
| where Activity has "Web server 400 error code."
Stage 4: where
| where Message has "403"
Stage 5: extend
| extend HostName=substring(split(DeviceCustomString1,")")[0],1)
Stage 6: summarize
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), NumberOfErrors = dcount(SourceIP) by HostName, SourceIP
Stage 7: where
| where NumberOfErrors > 400
Stage 8: sort
| sort by NumberOfErrors desc
Stage 9: extend
| extend timestamp = StartTime
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Activity | match |
| field:"Activity" kind:match value:"Web server 400 error code." |
DeviceProduct | eq |
| field:"DeviceProduct" kind:eq value:"Wazuh" |
Message | match |
| field:"Message" kind:match value:"403" |
NumberOfErrors | gt |
| field:"NumberOfErrors" kind:gt value:"400" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
EndTime | summarize |
HostName | summarize |
NumberOfErrors | summarize |
SourceIP | summarize |
StartTime | summarize |
timestamp | extend |
Zscaler - ZPA connections from new IP
#'Detects ZPA connections from new IP.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: 24f0779d-3927-403a-aac1-cc8791653606
name: Zscaler - ZPA connections from new IP
description: |
'Detects ZPA connections from new IP.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: CustomLogsAma
datatypes:
- ZPA_CL
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1078
- T1133
query: |
let listIPs =
ZPAEvent
| where TimeGenerated > ago(14d)
| where DvcAction == 'open'
| summarize ListofIPs = make_set(SrcIpAddr) by DstUserName
| project ListofIPs;
ZPAEvent
| where isnotempty(SrcIpAddr)
| where SrcIpAddr !in (listIPs)
| summarize EventCount = count() by DstUserName, SrcIpAddr
| project-away EventCount
| extend IPCustomEntity = SrcIpAddr, AccountCustomEntity = DstUserName
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.2
kind: Scheduled
Stages and Predicates
Let Binding: listIPs
let listIPs = ZPAEvent
| where TimeGenerated > ago(14d)
| where DvcAction == 'open'
| summarize ListofIPs = make_set(SrcIpAddr) by DstUserName
| project ListofIPs;
Stage 1: source
ZPAEvent
Stage 2: where
| where isnotempty(SrcIpAddr)
Stage 3: where
| where SrcIpAddr !in (listIPs)
Stage 4: summarize
| summarize EventCount = count() by DstUserName, SrcIpAddr
Stage 5: project-away
| project-away EventCount
Stage 6: extend
| extend IPCustomEntity = SrcIpAddr, AccountCustomEntity = DstUserName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
SrcIpAddr | is_not_null | field:"src_ip" kind:is_not_null |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
SrcIpAddr | eq | listIPs | excludes:SrcIpAddr field:"SrcIpAddr" value:"listIPs" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DstUserName | summarize |
SrcIpAddr | summarize |
AccountCustomEntity | extend |
IPCustomEntity | extend |