Detection rules › Kusto
Kusto rules: 2x
AV detections related to Hive Ransomware
#This query looks for Microsoft Defender AV detections related to Hive Ransomware. In Microsoft Sentinel the SecurityAlerts table includes only the Device Name of the affected device, this query joins the DeviceInfo table to clearly connect other information such as Device group, ip, logged on users etc. This would allow the Microsoft Sentinel analyst to have more context related to the alert, if available.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Impact |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Microsoft Defender for Endpoint | DeviceInfo action any: Device information |
Rule Body
id: 4e5914a4-2ccd-429d-a845-fa597f0bd8c5
name: AV detections related to Hive Ransomware
description: |
'This query looks for Microsoft Defender AV detections related to Hive Ransomware.
In Microsoft Sentinel the SecurityAlerts table includes only the Device Name of the affected device, this query joins the DeviceInfo table to clearly connect other information such as Device group, ip, logged on users etc. This would allow the Microsoft Sentinel analyst to have more context related to the alert, if available.'
severity: High
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- SecurityAlert
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Impact
relevantTechniques:
- T1486
tags:
- HiveRansomware
query: |
let Hive_threats = dynamic(["Ransom:Win64/Hive", "Ransom:Win32/Hive"]);
DeviceInfo
| extend DeviceName = tolower(DeviceName)
| join kind=inner ( SecurityAlert
| where ProviderName == "MDATP"
| extend ThreatName = tostring(parse_json(ExtendedProperties).ThreatName)
| extend ThreatFamilyName = tostring(parse_json(ExtendedProperties).ThreatFamilyName)
| where ThreatName in~ (Hive_threats) or ThreatFamilyName in~ (Hive_threats)
| extend CompromisedEntity = tolower(CompromisedEntity)
) on $left.DeviceName == $right.CompromisedEntity
| summarize by bin(TimeGenerated, 1d), DisplayName, ThreatName, ThreatFamilyName, PublicIP, AlertSeverity, Description, tostring(LoggedOnUsers), DeviceId, TenantId , CompromisedEntity, tostring(LoggedOnUsers), ProductName, Entities
| extend HostName = tostring(split(CompromisedEntity, ".")[0]), DomainIndex = toint(indexof(CompromisedEntity, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(CompromisedEntity, DomainIndex + 1), CompromisedEntity)
| project-away DomainIndex
entityMappings:
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: CompromisedEntity
- identifier: HostName
columnName: HostName
- identifier: DnsDomain
columnName: HostNameDomain
- entityType: IP
fieldMappings:
- identifier: Address
columnName: PublicIP
version: 1.0.5
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Microsoft Security Research
support:
tier: Community
categories:
domains: [ "Security - Others" ]
Stages and Predicates
Parameters
let Hive_threats = dynamic(["Ransom:Win64/Hive", "Ransom:Win32/Hive"]);
Stage 1: source
DeviceInfo
Stage 2: extend
| extend DeviceName = tolower(DeviceName)
Stage 3: join
| join kind=inner ( SecurityAlert
| where ProviderName == "MDATP"
| extend ThreatName = tostring(parse_json(ExtendedProperties).ThreatName)
| extend ThreatFamilyName = tostring(parse_json(ExtendedProperties).ThreatFamilyName)
| where ThreatName in~ (Hive_threats) or ThreatFamilyName in~ (Hive_threats)
| extend CompromisedEntity = tolower(CompromisedEntity)
) on $left.DeviceName == $right.CompromisedEntity
Stage 4: summarize
summarize by DisplayName, ThreatName, ThreatFamilyName, PublicIP, AlertSeverity, Description, DeviceId, TenantId, CompromisedEntity, ProductName, Entities
Stage 5: extend
extend DomainIndex, HostName
Stage 6: extend
extend HostNameDomain
HostNameDomain =DomainIndex != -1substring(CompromisedEntity, (DomainIndex + 1))CompromisedEntityStage 7: project-away
project-away DomainIndex
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ProviderName | eq |
| field:"ProviderName" kind:eq value:"MDATP" |
ThreatFamilyName | in |
| field:"ThreatFamilyName" kind:in |
ThreatName | in |
| field:"ThreatName" kind:in |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AlertSeverity | summarize |
CompromisedEntity | summarize |
Description | summarize |
DeviceId | summarize |
DisplayName | summarize |
Entities | summarize |
ProductName | summarize |
PublicIP | summarize |
TenantId | summarize |
ThreatFamilyName | summarize |
ThreatName | summarize |
HostName | extend |
HostNameDomain | extend |
Cognni Incidents for Highly Sensitive Business 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 business information was placed at risk by user sharing.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Collection |
Rule Body
id: 44e80f00-b4f5-486b-a57d-4073746276df
name: Cognni Incidents for Highly Sensitive Business Information
description: |
'Display incidents in which highly sensitive business 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 business = 'Business Information';
CognniIncidents_CL
| where Severity == highRisk
| where informationType_s == business
| 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 business = 'Business Information';
Stage 1: source
CognniIncidents_CL
Stage 2: where
| where Severity == highRisk
Stage 3: where
| where informationType_s == business
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:"Business Information" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AccountCustomEntity | extend |
Corelight - Possible Typo Squatting or Punycode Phishing HTTP Request
#'Detects when an HTTP request was made to a domain that was using unicode/punycode.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: 6b579e98-abc9-4e7a-9efc-2f3408ba16c9
name: Corelight - Possible Typo Squatting or Punycode Phishing HTTP Request
description: |
'Detects when an HTTP request was made to a domain that was using unicode/punycode.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: Corelight
dataTypes:
- corelight_http
- corelight_http_red
- corelight_http2
- corelight_http_agg
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1566
query: |
union isfuzzy=true corelight_http, corelight_http_agg
| where method =~ 'GET'
| where isempty(referrer)
| where host has 'xn--'
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: id_orig_h
version: 2.2.0
kind: Scheduled
Stages and Predicates
Union isfuzzy=true (2 Sources)
Each leg below queries one source; the rule matches if any leg does. Sources: corelight_http, corelight_http_agg
Leg 1: corelight_http
Leg 2: corelight_http_agg
Applied to the Combined Result
| where method =~ 'GET' | where isempty(referrer) | where host has 'xn--'
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
host | match |
| field:"host" kind:match value:"xn--" |
method | eq |
| field:"method" kind:eq value:"GET" |
referrer | is_null | field:"referrer" kind:is_null |
CreepyDrive request URL sequence
#'CreepyDrive uses OneDrive for command and control, however, it makes regular requests to predicatable paths. This detecton will alert when over 20 sequences are observed in a single day.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Command & Control | |
| Exfiltration |
Rule Body
id: eda260eb-f4a1-4379-ad98-452604da9b3e
name: CreepyDrive request URL sequence
description: |
'CreepyDrive uses OneDrive for command and control, however, it makes regular requests to predicatable paths.
This detecton will alert when over 20 sequences are observed in a single day.'
severity: High
requiredDataConnectors:
- connectorId: Zscaler
dataTypes:
- CommonSecurityLog
- connectorId: Fortinet
dataTypes:
- CommonSecurityLog
- connectorId: CheckPoint
dataTypes:
- CommonSecurityLog
- connectorId: PaloAltoNetworks
dataTypes:
- CommonSecurityLog
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Exfiltration
- CommandAndControl
relevantTechniques:
- T1567.002
- T1102.002
tags:
- POLONIUM
query: |
let eventsThreshold = 20;
CommonSecurityLog
| where isnotempty(RequestURL)
| project TimeGenerated, RequestURL, RequestMethod, SourceIP, SourceHostName
| evaluate sequence_detect(TimeGenerated, 5s, 8s, login=(RequestURL has "login.microsoftonline.com/consumers/oauth2/v2.0/token"), graph=(RequestURL has "graph.microsoft.com/v1.0/me/drive/"), SourceIP, SourceHostName)
| summarize Events=count() by SourceIP, SourceHostName
| where Events >= eventsThreshold
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SourceIP
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: SourceHostName
version: 1.0.1
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Thomas McElroy
support:
tier: Community
categories:
domains: [ "Security - Others" ]
Stages and Predicates
Parameters
let eventsThreshold = 20;
Stage 1: source
CommonSecurityLog
Stage 2: where
| where isnotempty(RequestURL)
Stage 3: project
| project TimeGenerated, RequestURL, RequestMethod, SourceIP, SourceHostName
Stage 4: evaluate
| evaluate sequence_detect(TimeGenerated, 5s, 8s, login=(RequestURL has "login.microsoftonline.com/consumers/oauth2/v2.0/token"), graph=(RequestURL has "graph.microsoft.com/v1.0/me/drive/"), SourceIP, SourceHostName)
Stage 5: summarize
| summarize Events=count() by SourceIP, SourceHostName
Stage 6: where
| where Events >= eventsThreshold
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Events | ge |
| field:"Events" kind:ge value:"20" |
RequestURL | is_not_null | field:"RequestURL" kind:is_not_null |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Events | summarize |
SourceHostName | summarize |
SourceIP | summarize |
Detect device code login with user risk
#Threat actors regularly use Device Code authentication to login into compromised accounts. Popular attacks for this are using device code phishing attacks for example. Even though every organization should block device code authentication in conditional access, you can create a fall-back detection rule to flag device code logins by risky users.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Persistence | |
| Privilege Escalation | |
| Stealth |
References
Telemetry Coverage
Rule Body
union SigninLogs, AADNonInteractiveUserSignInLogs
| where TimeGenerated > ago(1h)
| where ResultSignature =~ "SUCCESS"
| where AuthenticationProtocol =~ "deviceCode"
| join kind=inner (AADUserRiskEvents | where TimeGenerated > ago(1d)) on UserPrincipalName
Stages and Predicates
Union (2 Sources)
Each leg below queries one source; the rule matches if any leg does. Sources: SigninLogs, AADNonInteractiveUserSignInLogs
Leg 1: SigninLogs
Leg 2: AADNonInteractiveUserSignInLogs
Applied to the Combined Result
| where TimeGenerated > ago(1h) | where ResultSignature =~ "SUCCESS" | where AuthenticationProtocol =~ "deviceCode" | join kind=inner (AADUserRiskEvents | where TimeGenerated > ago(1d)) on UserPrincipalName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
AuthenticationProtocol | eq |
| field:"AuthenticationProtocol" kind:eq value:"deviceCode" |
ResultSignature | eq |
| field:"ResultSignature" kind:eq value:"SUCCESS" |
Dumping LSASS Process Into a File
#Adversaries may attempt to access credential material stored in the process memory of the Local Security Authority Subsystem Service (LSASS). After a user logs on, the system generates and stores a variety of credential materials in LSASS process memory. These credential materials can be harvested by an administrative user or system and used to conduct lateral movement using alternate authentication materials. As well as in-memory techniques, the LSASS process memory can be dumped from the target host and analyzed on a local system. Ref: https://attack.mitre.org/techniques/T1003/001/
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Credential Access |
Telemetry Coverage
| Provider | Record / event type |
|---|---|
| Sysmon | Event ID 10: ProcessAccess |
Rule Body
id: a7b9df32-1367-402d-b385-882daf6e3020
name: Dumping LSASS Process Into a File
description: |
'Adversaries may attempt to access credential material stored in the process memory of the Local Security Authority Subsystem Service (LSASS).
After a user logs on, the system generates and stores a variety of credential materials in LSASS process memory.
These credential materials can be harvested by an administrative user or system and used to conduct lateral movement using alternate authentication materials.
As well as in-memory techniques, the LSASS process memory can be dumped from the target host and analyzed on a local system.
Ref: https://attack.mitre.org/techniques/T1003/001/'
severity: High
status: Available
requiredDataConnectors:
- connectorId: SecurityEvents
dataTypes:
- SecurityEvent
- connectorId: WindowsSecurityEvents
dataTypes:
- SecurityEvent
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- CredentialAccess
relevantTechniques:
- T1003.001
query: |
Event
| where EventLog =~ "Microsoft-Windows-Sysmon/Operational" and EventID==10
| parse EventData with * 'TargetImage">' TargetImage "<" * 'GrantedAccess">' GrantedAccess "<" * 'CallTrace">' CallTrace "<" *
| where GrantedAccess =~ "0x1FFFFF" and TargetImage =~ "C:\\Windows\\System32\\lsass.exe" and CallTrace has_any ("dbghelp.dll","dbgcore.dll")
| parse EventData with * 'SourceProcessGUID">' SourceProcessGUID "<" * 'SourceImage">' SourceImage "<" *
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, SourceProcessGUID, SourceImage, GrantedAccess, TargetImage, CallTrace
| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')
entityMappings:
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: Computer
- identifier: HostName
columnName: HostName
- identifier: DnsDomain
columnName: DnsDomain
- entityType: Process
fieldMappings:
- identifier: CommandLine
columnName: SourceImage
version: 1.0.3
kind: Scheduled
Stages and Predicates
Stage 1: source
Event
Stage 2: where
| where EventLog =~ "Microsoft-Windows-Sysmon/Operational" and EventID==10
Stage 3: parse
| parse EventData with * 'TargetImage">' TargetImage "<" * 'GrantedAccess">' GrantedAccess "<" * 'CallTrace">' CallTrace "<" *
Stage 4: where
| where GrantedAccess =~ "0x1FFFFF" and TargetImage =~ "C:\\Windows\\System32\\lsass.exe" and CallTrace has_any ("dbghelp.dll","dbgcore.dll")
Stage 5: parse
| parse EventData with * 'SourceProcessGUID">' SourceProcessGUID "<" * 'SourceImage">' SourceImage "<" *
Stage 6: summarize
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, SourceProcessGUID, SourceImage, GrantedAccess, TargetImage, CallTrace
Stage 7: extend
| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
CallTrace | match |
| field:"CallTrace" kind:match |
EventID | eq |
| field:"EventID" kind:eq value:"10" |
EventLog | eq |
| field:"EventLog" kind:eq value:"Microsoft-Windows-Sysmon/Operational" |
GrantedAccess | eq |
| field:"GrantedAccess" kind:eq value:"0x1FFFFF" |
TargetImage | eq |
| field:"TargetImage" kind:eq value:"C:\Windows\System32\lsass.exe" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
CallTrace | summarize |
Computer | summarize |
EndTime | summarize |
EventID | summarize |
GrantedAccess | summarize |
SourceImage | summarize |
SourceProcessGUID | summarize |
StartTime | summarize |
TargetImage | summarize |
DnsDomain | extend |
HostName | extend |
Imminent Ransomware
#This query checks for a series of commands that are commonly used by attackers to disable security tools and system recovery tools before deploying Macaw ransomware in an organization.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Persistence | |
| Defense Impairment |
Telemetry Coverage
Rule Body
id: bb46dd86-e642-48a4-975c-44f5ac2b5033
name: Imminent Ransomware
description: |
This query checks for a series of commands that are commonly used by attackers to disable security tools and system recovery tools before deploying Macaw ransomware in an organization.
severity: High
status: Available
requiredDataConnectors: []
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
- Persistence
relevantTechniques:
- T1562
- T1547
tags:
- Schema: _ASim_ProcessEvent
SchemaVersion: 0.1.4
- Ransomware Campaign
- Macaw Ransomware
query: |
_ASim_ProcessEvent
// Pivot on specific commands
| where CommandLine has_any("-ExclusionPath", "Set-MpPreference", "advfirewall", "-ExclusionExtension",
"-EnableControlledFolderAccess", "windefend", "onstart", "bcdedit", "Startup")
// Making list of found commands
| summarize CommandLine = make_set(CommandLine, 10000) by DvcId, Dvc, bin(TimeGenerated, 6h)
// Extending columns for later aggregration, based on TTP
| extend StartUpExclusionPath = iff(CommandLine has_all("-ExclusionPath", "Startup"), 1, 0)
| extend DefenderTamp = iff(CommandLine has "Set-MpPreference"
and CommandLine has_any(
"-SevereThreatDefaultAction 6"
"-HighThreatDefaultAction 6",
"-ModerateThreatDefaultAction 6",
"-LowThreatDefaultAction 6"
"-ScanScheduleDay 8"), 1, 0)
| extend NetshFirewallTampering = iff(CommandLine has_all( "netsh", "advfirewall", "allprofiles state off"), 1, 0)
| extend BatExclusion = iff(CommandLine has_all("-ExclusionExtension", ".bat"), 1, 0)
| extend ExeExclusion = iff(CommandLine has_all("-ExclusionExtension", ".exe"), 1, 0)
| extend DisableControlledFolderAccess = iff(CommandLine has_all("-EnableControlledFolderAccess", "Disabled"), 1, 0)
| extend ScDeleteDefend = iff(CommandLine has_all("sc", "delete", "windefend"), 1, 0)
| extend BootTampering = iff(CommandLine has_all("bcdedit", "default") and CommandLine has_any ("recoveryenabled No", "bootstatuspolicy ignoreallfailures"), 1, 0)
| extend SchTasks = iff(CommandLine has_all("/sc", "onstart", "system", "/create", "/delay"), 1, 0)
// Summarizing found commands
| summarize by NetshFirewallTampering ,BatExclusion, ExeExclusion, DisableControlledFolderAccess, ScDeleteDefend, SchTasks, BootTampering, DefenderTamp, StartUpExclusionPath, DvcId, Dvc, TimeGenerated
// Adding up each piece of evidence
| extend EvidenceCount = NetshFirewallTampering + BatExclusion + ExeExclusion + DisableControlledFolderAccess + ScDeleteDefend + SchTasks + BootTampering + DefenderTamp + StartUpExclusionPath
| where EvidenceCount > 4
| extend HostName = iff(Dvc has '.', substring(Dvc, 0, indexof(Dvc, '.')), Dvc)
| extend DnsDomain = iff(Dvc has '.', substring(Dvc, indexof(Dvc, '.') + 1), "")
entityMappings:
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: Dvc
- identifier: HostName
columnName: HostName
- identifier: DnsDomain
columnName: DnsDomain
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
_ASim_ProcessEvent
Stage 2: where
| where CommandLine has_any("-ExclusionPath", "Set-MpPreference", "advfirewall", "-ExclusionExtension",
"-EnableControlledFolderAccess", "windefend", "onstart", "bcdedit", "Startup")
Stage 3: summarize
| summarize CommandLine = make_set(CommandLine, 10000) by DvcId, Dvc, bin(TimeGenerated, 6h)
Stage 4: extend (9 consecutive steps)
| extend StartUpExclusionPath = iff(CommandLine has_all("-ExclusionPath", "Startup"), 1, 0)
| extend DefenderTamp = iff(CommandLine has "Set-MpPreference"
and CommandLine has_any(
"-SevereThreatDefaultAction 6"
"-HighThreatDefaultAction 6",
"-ModerateThreatDefaultAction 6",
"-LowThreatDefaultAction 6"
"-ScanScheduleDay 8"), 1, 0)
| extend NetshFirewallTampering = iff(CommandLine has_all( "netsh", "advfirewall", "allprofiles state off"), 1, 0)
| extend BatExclusion = iff(CommandLine has_all("-ExclusionExtension", ".bat"), 1, 0)
| extend ExeExclusion = iff(CommandLine has_all("-ExclusionExtension", ".exe"), 1, 0)
| extend DisableControlledFolderAccess = iff(CommandLine has_all("-EnableControlledFolderAccess", "Disabled"), 1, 0)
| extend ScDeleteDefend = iff(CommandLine has_all("sc", "delete", "windefend"), 1, 0)
| extend BootTampering = iff(CommandLine has_all("bcdedit", "default") and CommandLine has_any ("recoveryenabled No", "bootstatuspolicy ignoreallfailures"), 1, 0)
| extend SchTasks = iff(CommandLine has_all("/sc", "onstart", "system", "/create", "/delay"), 1, 0)
StartUpExclusionPath =CommandLine has "-ExclusionPath" and CommandLine has "Startup"10Stage 5: summarize
| summarize by NetshFirewallTampering ,BatExclusion, ExeExclusion, DisableControlledFolderAccess, ScDeleteDefend, SchTasks, BootTampering, DefenderTamp, StartUpExclusionPath, DvcId, Dvc, TimeGenerated
Stage 6: extend
| extend EvidenceCount = NetshFirewallTampering + BatExclusion + ExeExclusion + DisableControlledFolderAccess + ScDeleteDefend + SchTasks + BootTampering + DefenderTamp + StartUpExclusionPath
Stage 7: where
| where EvidenceCount > 4
Stage 8: extend
| extend HostName = iff(Dvc has '.', substring(Dvc, 0, indexof(Dvc, '.')), Dvc)
HostName =Dvc has "."substring(Dvc, 0, indexof(Dvc, '.'))DvcStage 9: extend
| extend DnsDomain = iff(Dvc has '.', substring(Dvc, indexof(Dvc, '.') + 1), "")
DnsDomain =Dvc has "."substring(Dvc, (indexof(Dvc, '.') + 1))""Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
CommandLine | match |
| field:"CommandLine" kind:match |
EvidenceCount | gt |
| field:"EvidenceCount" kind:gt value:"4" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
BatExclusion | summarize |
BootTampering | summarize |
DefenderTamp | summarize |
DisableControlledFolderAccess | summarize |
Dvc | summarize |
DvcId | summarize |
ExeExclusion | summarize |
NetshFirewallTampering | summarize |
ScDeleteDefend | summarize |
SchTasks | summarize |
StartUpExclusionPath | summarize |
TimeGenerated | summarize |
EvidenceCount | extend |
HostName | extend |
DnsDomain | extend |
Invalid Code for Multi-Factor Authentication Entered
#Detects failed multi-factor authentication attempts. This might indicate credential stuffing or brute-force attacks.
Rule Body
id: 5220a0b0-ab15-43cf-a77e-2273d35cfe8e
name: Invalid Code for Multi-Factor Authentication Entered
description: Detects failed multi-factor authentication attempts. This might indicate
credential stuffing or brute-force attacks.
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 == 40205\n| extend SID = extract(\"\
SID=\\\"([^\\\"]*)\\\"\", 1, SyslogMessage)\n| extend Endpoint = extract(\"Endpoint=\\\
\"([^\\\"]*)\\\"\", 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 [\"Endpoint\"] = Endpoint,\n [\"User SID\"] = SID,\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 == 40205
Stage 3: extend
| extend SID = extract("SID=\"([^\"]*)\"", 1, SyslogMessage)
Stage 4: extend
| extend Endpoint = extract("Endpoint=\"([^\"]*)\"", 1, SyslogMessage)
Stage 5: project
| project
Date = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),
DataSource = original_host,
EventId = instanceId,
UserName = user,
["Endpoint"] = Endpoint,
["User SID"] = SID,
MessageDetails = Description,
Severity = SeverityDescription
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
instanceId | eq |
| field:"instanceId" kind:eq value:"40205" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DataSource | project |
Date | project |
Endpoint | project |
EventId | project |
MessageDetails | project |
Severity | project |
User SID | project |
UserName | project |
Malware Detection Exclusions List Updated
#Detects when malware detection exclusions are updated. This might indicate potential compromise of backup data.
Rule Body
id: 401e91cb-b53f-41a5-b066-1c028b3b51db
name: Malware Detection Exclusions List Updated
description: Detects when malware detection exclusions are updated. This might indicate
potential compromise of backup data.
severity: Medium
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 == 42280\n| project\n Date =\
\ format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),\n DataSource = original_host,\n\
\ EventId = instanceId,\n UserName = user,\n MessageDetails = Description,\n\
\ Severity = SeverityDescription\n| project Date, DataSource, EventId, UserName,MessageDetails,Severity"
version: 1.0.1
kind: Scheduled
customDetails:
Date: Date
VbrHostName: DataSource
EventId: EventId
MessageDetails: MessageDetails
Severity: Severity
Stages and Predicates
Stage 1: source
Veeam_GetSecurityEvents
Stage 2: where
| where instanceId == 42280
Stage 3: project
| project
Date = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),
DataSource = original_host,
EventId = instanceId,
UserName = user,
MessageDetails = Description,
Severity = SeverityDescription
Stage 4: project
| project Date, DataSource, EventId, UserName,MessageDetails,Severity
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
instanceId | eq |
| field:"instanceId" kind:eq value:"42280" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DataSource | project |
Date | project |
EventId | project |
MessageDetails | project |
Severity | project |
UserName | project |
OCI - SSH scanner
#'Detects possible SSH scanning activity.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Reconnaissance |
Rule Body
id: e087d4fb-af0b-4e08-a067-b9ba9e5f8840
name: OCI - SSH scanner
description: |
'Detects possible SSH scanning activity.'
severity: High
status: Available
requiredDataConnectors:
- connectorId: OracleCloudInfrastructureLogsConnector
dataTypes:
- OCILogs
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Reconnaissance
relevantTechniques:
- T1595
query: |
let threshold = 5;
OCILogs
| where EventType contains 'vcn.flowlogs'
| where data_action_s =~ 'REJECT'
| where ipv4_is_private(DstIpAddr)
| where ipv4_is_private(SrcIpAddr) == False
| where DstPortNumber == 22
| summarize p_count = dcount(DstIpAddr) by SrcIpAddr, bin(TimeGenerated, 5m)
| where p_count > threshold
| extend IPCustomEntity = SrcIpAddr
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.1
kind: Scheduled
Stages and Predicates
Parameters
let threshold = 5;
Stage 1: source
OCILogs
Stage 2: where
| where EventType contains 'vcn.flowlogs'
Stage 3: where
| where data_action_s =~ 'REJECT'
Stage 4: where
| where ipv4_is_private(DstIpAddr)
Stage 5: where
| where ipv4_is_private(SrcIpAddr) == False
Stage 6: where
| where DstPortNumber == 22
Stage 7: summarize
| summarize p_count = dcount(DstIpAddr) by SrcIpAddr, bin(TimeGenerated, 5m)
Stage 8: where
| where p_count > threshold
Stage 9: extend
| extend IPCustomEntity = SrcIpAddr
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
DstIpAddr | cidr_match |
| field:"dest_ip" kind:cidr_match |
DstPortNumber | eq |
| field:"DstPortNumber" kind:eq value:"22" |
EventType | contains |
| field:"EventType" kind:contains value:"vcn.flowlogs" |
data_action_s | eq |
| field:"data_action_s" kind:eq value:"REJECT" |
p_count | gt |
| field:"p_count" kind:gt value:"5" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
SrcIpAddr | cidr_match | 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16, 127.0.0.0/8 | excludes:SrcIpAddr |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
SrcIpAddr | summarize |
p_count | summarize |
IPCustomEntity | extend |
PROD (TM018.1) - DOMAIN - Child Domain promoted within the Forest
#New child domain has been promoted within the Forest and should have the Tier Model deployed.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Privilege Escalation |
Telemetry Coverage
| Provider | Record / event type |
|---|---|
| Security-Auditing | Event ID 5137: A directory service object was created. |
Rule Body
id: ff1bec81-e241-44bf-98ed-c6e37805a2e3
name: 'PROD (TM018.1) - DOMAIN - Child Domain promoted within the Forest'
description: |
New child domain has been promoted within the Forest and should have the Tier Model deployed.
severity: High
requiredDataConnectors:
- connectorId: SecurityEvents
dataTypes:
- SecurityEvent
- connectorId: WindowsSecurityEvents
dataTypes:
- SecurityEvent
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
- PrivilegeEscalation
relevantTechniques:
- T1484.002
query: |
SecurityEvent
| where EventID == 5137 and EventData has '"ObjectClass">crossRef' and EventData has 'CN=Partitions,CN=Configuration'
| extend ObjectName = extract("(?i)CN=([^,]+),(?i)CN=Partitions,(?i)CN=Configuration", 1, EventData)
| extend ActivityType = extract("([a-zA-Z]+)\\.$", 1, Activity)
| extend Domain = extract("([^.]+\\.[^.]+)$", 1, Computer)
| project TimeGenerated
, ObjectName
, ActivityType
, Account
, Domain
, Computer
, Channel
, EventID
, EventData
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: ObjectName
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: Computer
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: Account
customDetails:
ObjectName: ObjectName
ActivityType: ActivityType
Account: Account
Domain: Domain
Computer: Computer
Channel: Channel
EventID: EventID
EventData: EventData
eventGroupingSettings:
aggregationKind: AlertPerResult
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: false
reopenClosedIncident: false
lookbackDuration: PT5H
matchingMethod: AllEntities
alertDetailsOverride:
alertDisplayNameFormat: '(TM018.1) A new Child Domain has been promoted and requires the Tier Model to be deployed'
alertDescriptionFormat: 'New child domains do not have a Tier Model by default. Deploy and configure the Tier Model within the new child domain.'
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
SecurityEvent
Stage 2: where
| where EventID == 5137 and EventData has '"ObjectClass">crossRef' and EventData has 'CN=Partitions,CN=Configuration'
Stage 3: extend (3 consecutive steps)
| extend ObjectName = extract("(?i)CN=([^,]+),(?i)CN=Partitions,(?i)CN=Configuration", 1, EventData)
| extend ActivityType = extract("([a-zA-Z]+)\\.$", 1, Activity)
| extend Domain = extract("([^.]+\\.[^.]+)$", 1, Computer)
Stage 4: project
| project TimeGenerated
, ObjectName
, ActivityType
, Account
, Domain
, Computer
, Channel
, EventID
, EventData
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventData | match |
| field:"EventData" kind:match |
EventID | eq |
| field:"EventID" kind:eq value:"5137" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Account | project |
ActivityType | project |
Channel | project |
Computer | project |
Domain | project |
EventData | project |
EventID | project |
ObjectName | project |
TimeGenerated | project |
SlackAudit - User email linked to account changed.
#'Detects when user email linked to account changes.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: 9d85feb3-7f54-4181-b143-68abb1a86823
name: SlackAudit - User email linked to account changed.
description: |
'Detects when user email linked to account changes.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: SlackAuditAPI
dataTypes:
- SlackAudit_CL
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1078
query: |
SlackAudit
| where TimeGenerated between (ago(14d) .. (1d))
| summarize max(TimeGenerated) by SrcUserName, SrcUserEmail
| join (SlackAudit
| where Action =~ 'user_login'
| project SrcIpAddr, SrcUserName, NewUserEmail = SrcUserEmail) on SrcUserName
| where NewUserEmail != SrcUserEmail
| extend AccountCustomEntity = SrcUserName
| extend IPCustomEntity = SrcIpAddr
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
alertDetailsOverride:
alertDisplayNameFormat: Slack user email changed for {{SrcUserName}}
alertDescriptionFormat: Slack audit detected a user email change for {{SrcUserName}} from {{SrcUserEmail}} to {{NewUserEmail}}.
customDetails:
SourceUserName: SrcUserName
OriginalUserEmail: SrcUserEmail
NewUserEmail: NewUserEmail
SourceIpAddress: SrcIpAddr
version: 1.0.1
kind: Scheduled
Stages and Predicates
Stage 1: source
SlackAudit
Stage 2: where
| where TimeGenerated between (ago(14d) .. (1d))
Stage 3: summarize
| summarize max(TimeGenerated) by SrcUserName, SrcUserEmail
Stage 4: join
| join (SlackAudit
| where Action =~ 'user_login'
| project SrcIpAddr, SrcUserName, NewUserEmail = SrcUserEmail) on SrcUserName
Stage 5: where
where NewUserEmail != SrcUserEmail
Stage 6: extend
extend AccountCustomEntity
Stage 7: extend
extend IPCustomEntity
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Action | eq |
| field:"Action" kind:eq value:"user_login" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
SrcUserEmail | summarize |
SrcUserName | summarize |
AccountCustomEntity | extend |
IPCustomEntity | extend |
Vectra AI Detect - Suspicious Behaviors by Category
#'Create an incident for each new malicious behavior detected by Vectra Detect for a specific Category. By default, it looks through all tactics. This can be modified to create incident only for a subset of tactics.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Credential Access | |
| Discovery | |
| Lateral Movement | |
| Collection | |
| Command & Control | |
| Exfiltration | |
| Impact |
Rule Body
id: 6cb75f65-231f-46c4-a0b3-50ff21ee6ed3
name: Vectra AI Detect - Suspicious Behaviors by Category
description: |
'Create an incident for each new malicious behavior detected by Vectra Detect for a specific Category.
By default, it looks through all tactics. This can be modified to create incident only for a subset of tactics.'
severity: Informational
status: Available
requiredDataConnectors:
- connectorId: CefAma
dataTypes:
- CommonSecurityLog
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
eventGroupingSettings:
aggregationKind: AlertPerResult
tactics:
- CredentialAccess
- Discovery
- LateralMovement
- Collection
- CommandAndControl
- Exfiltration
- Impact
relevantTechniques:
- T1003
- T1087
- T1021
- T1119
- T1071
- T1041
- T1499
query: |
// Edit this variable to only keep the tactics where an incident needs to be created (Defaults are: "COMMAND & CONTROL", "BOTNET ACTIVITY", "EXFILTRATION", "LATERAL MOVEMENT", "RECONNAISSANCE")
let configured_tactics = dynamic(["COMMAND & CONTROL", "BOTNET ACTIVITY", "EXFILTRATION", "LATERAL MOVEMENT", "RECONNAISSANCE"]);
CommonSecurityLog
| where DeviceVendor == "Vectra Networks"
| where DeviceProduct == "X Series"
| where DeviceEventClassID != "campaigns" and DeviceEventClassID != "hsc" and DeviceEventClassID != "audit" and DeviceEventClassID != "health" and DeviceEventClassID != "asc"
| extend Category = coalesce(
column_ifexists("DeviceEventCategory", ""),
extract("cat=(.+?)(;|$)", 1, AdditionalExtensions),
""
)
| project-rename threat_score = FlexNumber1
| project-rename certainty_score = FlexNumber2
| project-rename triaged = DeviceCustomString5
| where triaged != "True"
| project-rename vectra_URL = DeviceCustomString4
| project-rename detection_name = DeviceEventClassID
| extend Tactic = case( Category == "COMMAND & CONTROL", "CommandAndControl",
Category == "BOTNET ACTIVITY" , "Impact",
Category == "EXFILTRATION", "Exfiltration",
Category == "LATERAL MOVEMENT", "LateralMovement",
Category == "RECONNAISSANCE", "Discovery",
"UNKNOWN")
| extend level = case( threat_score < 50 and certainty_score < 50, "Low",
threat_score < 50 and certainty_score >= 50 , "Medium",
threat_score >= 50 and certainty_score <= 50, "High",
threat_score >= 50 and certainty_score >= 50, "Critical",
"UNKNOWN")
| extend Severity = case(level == "Info", "Informational",level == "Critical", "High", level)
| extend account = extract("account=(.+?);", 1, AdditionalExtensions)
| extend upn = iff(account matches regex ":", tostring(split(account,":")[1]) ,tostring(split(account,":")[0]))
| extend name = tostring(split(upn, "@")[0])
| extend upn_suffix = tostring(split(upn, "@")[1])
| extend source_entity = case(level == "Info", "Informational",level == "Critical", "High", level)
| where Category in (configured_tactics)
| summarize arg_max(threat_score, *) by source_entity , Activity
| sort by TimeGenerated
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: SourceHostName
- entityType: Account
fieldMappings:
- identifier: Name
columnName: name
- identifier: UPNSuffix
columnName: upn_suffix
alertDetailsOverride:
alertDisplayNameFormat: Vectra AI Detect - {{Activity}} detected
alertDescriptionFormat: Source entity is {{source_entity}} and category is {{Category}}. Threat score is {{threat_score}}.
alertSeverityColumnName: Severity
alertDynamicProperties:
- alertProperty: AlertLink
value: vectra_URL
- alertProperty: ProductName
value: DeviceProduct
- alertProperty: ProviderName
value: DeviceVendor
- alertProperty: ConfidenceScore
value: certainty_score
customDetails:
AttackType: Activity
AttackCategory: Category
version: 1.1.1
kind: Scheduled
Stages and Predicates
Parameters
let configured_tactics = dynamic(["COMMAND & CONTROL", "BOTNET ACTIVITY", "EXFILTRATION", "LATERAL MOVEMENT", "RECONNAISSANCE"]);
Stage 1: source
CommonSecurityLog
Stage 2: where
| where DeviceVendor == "Vectra Networks"
Stage 3: where
| where DeviceProduct == "X Series"
Stage 4: where
| where DeviceEventClassID != "campaigns" and DeviceEventClassID != "hsc" and DeviceEventClassID != "audit" and DeviceEventClassID != "health" and DeviceEventClassID != "asc"
Stage 5: extend
| extend Category = coalesce(
column_ifexists("DeviceEventCategory", ""),
extract("cat=(.+?)(;|$)", 1, AdditionalExtensions),
""
)
Stage 6: project-rename
| project-rename threat_score = FlexNumber1
Stage 7: project-rename
| project-rename certainty_score = FlexNumber2
Stage 8: project-rename
| project-rename triaged = DeviceCustomString5
Stage 9: where
| where triaged != "True"
Stage 10: project-rename
| project-rename vectra_URL = DeviceCustomString4
Stage 11: project-rename
| project-rename detection_name = DeviceEventClassID
Stage 12: extend (8 consecutive steps)
| extend Tactic = case( Category == "COMMAND & CONTROL", "CommandAndControl",
Category == "BOTNET ACTIVITY" , "Impact",
Category == "EXFILTRATION", "Exfiltration",
Category == "LATERAL MOVEMENT", "LateralMovement",
Category == "RECONNAISSANCE", "Discovery",
"UNKNOWN")
| extend level = case( threat_score < 50 and certainty_score < 50, "Low",
threat_score < 50 and certainty_score >= 50 , "Medium",
threat_score >= 50 and certainty_score <= 50, "High",
threat_score >= 50 and certainty_score >= 50, "Critical",
"UNKNOWN")
| extend Severity = case(level == "Info", "Informational",level == "Critical", "High", level)
| extend account = extract("account=(.+?);", 1, AdditionalExtensions)
| extend upn = iff(account matches regex ":", tostring(split(account,":")[1]) ,tostring(split(account,":")[0]))
| extend name = tostring(split(upn, "@")[0])
| extend upn_suffix = tostring(split(upn, "@")[1])
| extend source_entity = case(level == "Info", "Informational",level == "Critical", "High", level)
Tactic =Category == "COMMAND & CONTROL""CommandAndControl"Category == "BOTNET ACTIVITY""Impact"Category == "EXFILTRATION""Exfiltration"Category == "LATERAL MOVEMENT""LateralMovement"Category == "RECONNAISSANCE""Discovery""UNKNOWN"Stage 13: where
| where Category in (configured_tactics)
Stage 14: summarize
| summarize arg_max(threat_score, *) by source_entity , Activity
Stage 15: sort
| sort by TimeGenerated
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Category | in |
| field:"Category" kind:in |
DeviceEventClassID | ne |
| field:"DeviceEventClassID" kind:ne |
DeviceProduct | eq |
| field:"DeviceProduct" kind:eq value:"X Series" |
DeviceVendor | eq |
| field:"DeviceVendor" kind:eq value:"Vectra Networks" |
triaged | ne |
| field:"DeviceCustomString5" kind:ne value:"True" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Activity | summarize |
source_entity | summarize |