Detection rules › Kusto

Kusto rules: 2x

AV detections related to Hive Ransomware

#
Severity
high
Time window
1d
Group by
$left.DeviceName, $right.CompromisedEntity, AlertSeverity, CompromisedEntity, Description, DeviceId, DisplayName, Entities, ProductName, PublicIP, TenantId, ThreatFamilyName, ThreatName
Author
Microsoft Security Research
Source
github.com/Azure/Azure-Sentinel

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

TacticTechniques
Impact

Telemetry Coverage

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 =
ifDomainIndex != -1substring(CompromisedEntity, (DomainIndex + 1))
elseCompromisedEntity

Stage 7: project-away

project-away DomainIndex

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
ProviderNameeq
  • MDATP
field:"ProviderName" kind:eq value:"MDATP"
ThreatFamilyNamein
  • Ransom:Win32/Hive
  • Ransom:Win64/Hive
field:"ThreatFamilyName" kind:in
ThreatNamein
  • Ransom:Win32/Hive
  • Ransom:Win64/Hive
field:"ThreatName" kind:in

Output Fields

These fields are emitted when the rule matches.

FieldSource
AlertSeveritysummarize
CompromisedEntitysummarize
Descriptionsummarize
DeviceIdsummarize
DisplayNamesummarize
Entitiessummarize
ProductNamesummarize
PublicIPsummarize
TenantIdsummarize
ThreatFamilyNamesummarize
ThreatNamesummarize
HostNameextend
HostNameDomainextend

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.

Status
available
Severity
high
Time window
5h
Source
github.com/Azure/Azure-Sentinel

'Display incidents in which highly sensitive business information was placed at risk by user sharing.'

MITRE ATT&CK Coverage

TacticTechniques
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.

Output Fields

These fields are emitted when the rule matches.

FieldSource
AccountCustomEntityextend

Corelight - Possible Typo Squatting or Punycode Phishing HTTP Request

#
Status
available
Severity
medium
Time window
1h
Source
github.com/Azure/Azure-Sentinel

'Detects when an HTTP request was made to a domain that was using unicode/punycode.'

MITRE ATT&CK Coverage

TacticTechniques
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.

FieldKindValuesSearch
hostmatch
  • xn-- transforms: term
field:"host" kind:match value:"xn--"
methodeq
  • GET
field:"method" kind:eq value:"GET"
referreris_null
  • (no value, null check)
field:"referrer" kind:is_null

CreepyDrive request URL sequence

#
Severity
high
Time window
1d
Group by
SourceHostName, SourceIP
Author
Thomas McElroy
Source
github.com/Azure/Azure-Sentinel

'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

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.

FieldKindValuesSearch
Eventsge
  • 20 transforms: number
field:"Events" kind:ge value:"20"
RequestURLis_not_null
  • (no value, null check)
field:"RequestURL" kind:is_not_null

Output Fields

These fields are emitted when the rule matches.

FieldSource
Eventssummarize
SourceHostNamesummarize
SourceIPsummarize

Detect device code login with user risk

#
Group by
UserPrincipalName
Author
Robbe Van den Daele
Source
github.com/HybridBrothers/Hunting-Queries-Detection-Rules

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

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.

Dumping LSASS Process Into a File

#
Status
available
Severity
high
Time window
1h
Group by
CallTrace, Computer, EventID, GrantedAccess, SourceImage, SourceProcessGUID, TargetImage
Source
github.com/Azure/Azure-Sentinel

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

TacticTechniques
Credential Access

Telemetry Coverage

ProviderRecord / event type
SysmonEvent 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.

FieldKindValuesSearch
CallTracematch
  • dbgcore.dll transforms: term
  • dbghelp.dll transforms: term
field:"CallTrace" kind:match
EventIDeq
  • 10 corpus 7 (elastic 6, kusto 1)
field:"EventID" kind:eq value:"10"
EventLogeq
  • Microsoft-Windows-Sysmon/Operational corpus 7 (kusto 7)
field:"EventLog" kind:eq value:"Microsoft-Windows-Sysmon/Operational"
GrantedAccesseq
  • 0x1FFFFF corpus 9 (sigma 7, splunk 1, kusto 1)
field:"GrantedAccess" kind:eq value:"0x1FFFFF"
TargetImageeq
  • C:\Windows\System32\lsass.exe corpus 2 (elastic 1, kusto 1)
field:"TargetImage" kind:eq value:"C:\Windows\System32\lsass.exe"

Output Fields

These fields are emitted when the rule matches.

FieldSource
CallTracesummarize
Computersummarize
EndTimesummarize
EventIDsummarize
GrantedAccesssummarize
SourceImagesummarize
SourceProcessGUIDsummarize
StartTimesummarize
TargetImagesummarize
DnsDomainextend
HostNameextend

Imminent Ransomware

#
Status
available
Severity
high
Time window
6h
Group by
BatExclusion, BootTampering, DefenderTamp, DisableControlledFolderAccess, Dvc, DvcId, ExeExclusion, NetshFirewallTampering, ScDeleteDefend, SchTasks, StartUpExclusionPath, TimeGenerated
Source
github.com/Azure/Azure-Sentinel

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

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 =
ifCommandLine has "-ExclusionPath" and CommandLine has "Startup"1
else0

Stage 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 =
ifDvc has "."substring(Dvc, 0, indexof(Dvc, '.'))
elseDvc

Stage 9: extend

| extend DnsDomain = iff(Dvc has '.', substring(Dvc, indexof(Dvc, '.') + 1), "")
DnsDomain =
ifDvc has "."substring(Dvc, (indexof(Dvc, '.') + 1))
else""

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
CommandLinematch
  • -EnableControlledFolderAccess transforms: term
  • -ExclusionExtension transforms: term
  • -ExclusionPath transforms: term corpus 2 (kusto 2)
  • Set-MpPreference transforms: term
  • Startup transforms: term
  • advfirewall transforms: term
  • bcdedit transforms: term
  • onstart transforms: term
  • windefend transforms: term
field:"CommandLine" kind:match
EvidenceCountgt
  • 4 transforms: number
field:"EvidenceCount" kind:gt value:"4"

Output Fields

These fields are emitted when the rule matches.

FieldSource
BatExclusionsummarize
BootTamperingsummarize
DefenderTampsummarize
DisableControlledFolderAccesssummarize
Dvcsummarize
DvcIdsummarize
ExeExclusionsummarize
NetshFirewallTamperingsummarize
ScDeleteDefendsummarize
SchTaskssummarize
StartUpExclusionPathsummarize
TimeGeneratedsummarize
EvidenceCountextend
HostNameextend
DnsDomainextend

Invalid Code for Multi-Factor Authentication Entered

#
Status
available
Severity
high
Time window
5m
Source
github.com/Azure/Azure-Sentinel

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.

Output Fields

These fields are emitted when the rule matches.

FieldSource
DataSourceproject
Dateproject
Endpointproject
EventIdproject
MessageDetailsproject
Severityproject
User SIDproject
UserNameproject

Malware Detection Exclusions List Updated

#
Status
available
Severity
medium
Time window
5m
Source
github.com/Azure/Azure-Sentinel

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.

Output Fields

These fields are emitted when the rule matches.

FieldSource
DataSourceproject
Dateproject
EventIdproject
MessageDetailsproject
Severityproject
UserNameproject

OCI - SSH scanner

#
Status
available
Severity
high
Time window
5m
Group by
SrcIpAddr
Source
github.com/Azure/Azure-Sentinel

'Detects possible SSH scanning activity.'

MITRE ATT&CK Coverage

TacticTechniques
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.

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
SrcIpAddrcidr_match10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16, 127.0.0.0/8excludes:SrcIpAddr

Output Fields

These fields are emitted when the rule matches.

FieldSource
SrcIpAddrsummarize
p_countsummarize
IPCustomEntityextend

PROD (TM018.1) - DOMAIN - Child Domain promoted within the Forest

#
Status
available
Severity
high
Time window
1h
Source
github.com/Azure/Azure-Sentinel

New child domain has been promoted within the Forest and should have the Tier Model deployed.

MITRE ATT&CK Coverage

Telemetry Coverage

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.

FieldKindValuesSearch
EventDatamatch
  • "ObjectClass">crossRef transforms: term
  • CN=Partitions,CN=Configuration transforms: term
field:"EventData" kind:match
EventIDeq
  • 5137 corpus 8 (kusto 5, elastic 3)
field:"EventID" kind:eq value:"5137"

Output Fields

These fields are emitted when the rule matches.

FieldSource
Accountproject
ActivityTypeproject
Channelproject
Computerproject
Domainproject
EventDataproject
EventIDproject
ObjectNameproject
TimeGeneratedproject

SlackAudit - User email linked to account changed.

#
Status
available
Severity
medium
Time window
14d
Group by
SrcUserEmail, SrcUserName
Source
github.com/Azure/Azure-Sentinel

'Detects when user email linked to account changes.'

MITRE ATT&CK Coverage

TacticTechniques
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.

FieldKindValuesSearch
Actioneq
  • user_login
field:"Action" kind:eq value:"user_login"

Output Fields

These fields are emitted when the rule matches.

FieldSource
SrcUserEmailsummarize
SrcUserNamesummarize
AccountCustomEntityextend
IPCustomEntityextend

Vectra AI Detect - Suspicious Behaviors by Category

#
Status
available
Severity
informational
Time window
5m
Group by
Activity, source_entity
Source
github.com/Azure/Azure-Sentinel

'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

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 =
ifCategory == "COMMAND & CONTROL""CommandAndControl"
elifCategory == "BOTNET ACTIVITY""Impact"
elifCategory == "EXFILTRATION""Exfiltration"
elifCategory == "LATERAL MOVEMENT""LateralMovement"
elifCategory == "RECONNAISSANCE""Discovery"
else"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.

Output Fields

These fields are emitted when the rule matches.

FieldSource
Activitysummarize
source_entitysummarize

Back to all Kusto rules