Detection rules › Kusto

Kusto rules: 0z

Acronis - Login from Abnormal IP - Low Occurrence

#
Severity
medium
Time window
14d
Group by
initiator_ip
Source
github.com/Azure/Azure-Sentinel

Suspicious login from an IP address observed up to two times in the last two weeks.

MITRE ATT&CK Coverage

TacticTechniques
Initial Access

Rule Body

id: 84037130-a623-46c2-9144-0c0955ac4112
name: Acronis - Login from Abnormal IP - Low Occurrence
description: Suspicious login from an IP address observed up to two times in the last two weeks.
severity: Medium
query: |
    CommonSecurityLog
    | where DeviceVendor == "Acronis audit"
    | extend initiator_ip = tostring(parse_json(DeviceCustomString1).initiator_ip)
    | summarize LoginCount = count() by initiator_ip
    | where LoginCount <= 2
    | order by LoginCount asc
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
    - InitialAccess
relevantTechniques:
    - T1078
incidentConfiguration:
    createIncident: true
    groupingConfiguration:
        enabled: true
        reopenClosedIncident: true
        lookbackDuration: P7D
        matchingMethod: Selected
        groupByEntities:
            - IP
eventGroupingSettings:
    aggregationKind: AlertPerResult
alertDetailsOverride:
    alertDisplayNameFormat: 'Acronis - Login from Abnormal IP ({{initiator_ip}}) - Low Occurrence ({{LoginCount}})'
    alertDynamicProperties: []
entityMappings:
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: initiator_ip
version: 1.0.0
kind: Scheduled
requiredDataConnectors: []

Stages and Predicates

Stage 1: source

CommonSecurityLog

Stage 2: where

| where DeviceVendor == "Acronis audit"

Stage 3: extend

| extend initiator_ip = tostring(parse_json(DeviceCustomString1).initiator_ip)

Stage 4: summarize

| summarize LoginCount = count() by initiator_ip

Stage 5: where

| where LoginCount <= 2

Stage 6: sort

| order by LoginCount asc

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
LoginCountsummarize
initiator_ipsummarize

BitSight - compromised systems detected

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

'Rule helps to detect whenever there is a compromised systems found in BitSight.'

MITRE ATT&CK Coverage

Rule Body

id: d68b758a-b117-4cb8-8e1d-dcab5a4a2f21
name: BitSight - compromised systems detected
description: |
  'Rule helps to detect whenever there is a compromised systems found in BitSight.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: BitSight
    dataTypes:
      - BitSightFindingsData
queryFrequency: 1d
queryPeriod: 24h
triggerOperator: GreaterThan
triggerThreshold: 0
tactics:
  - Execution
relevantTechniques:
  - T1203
query: |
    let timeframe = 24h;
    BitSightFindingsData
    | where ingestion_time() > ago(timeframe)
    | where RiskCategory == "Compromised Systems"
    | extend Severity = toreal(Severity)
    | extend Severity = case( Severity <= 6.9 and Severity >= 4.0, "Low",
                              Severity <= 8.9 and Severity >= 7.0, "Medium",
                              Severity <= 10.0 and Severity >= 9.0, "High",
                              "Informational")
    | project FirstSeen, CompanyName, Severity, RiskCategory, RiskVector, TemporaryId
incidentConfiguration:
    createIncident: true
eventGroupingSettings:
    aggregationKind: AlertPerResult
alertDetailsOverride:
    alertDisplayNameFormat: 'BitSight: Alert for {{RiskVector}} in {{CompanyName}} from BitSight'
    alertDescriptionFormat: 'Alert is generated for {{CompanyName}}.\n\nRisk Vector: {{RiskVector}}\nTemporaryId: {{TemporaryId}}\nRisk Category: Compromised Systems'
    alertSeverityColumnName: Severity
entityMappings:
  - entityType: Malware
    fieldMappings:
      - identifier: Name
        columnName: RiskVector
      - identifier: Category
        columnName: RiskCategory
version: 1.0.2
kind: Scheduled

Stages and Predicates

Parameters

let timeframe = 24h;

Stage 1: source

BitSightFindingsData

Stage 2: where

| where ingestion_time() > ago(timeframe)

Stage 3: where

| where RiskCategory == "Compromised Systems"

Stage 4: extend

| extend Severity = toreal(Severity)

Stage 5: extend

| extend Severity = case( Severity <= 6.9 and Severity >= 4.0, "Low",
                          Severity <= 8.9 and Severity >= 7.0, "Medium",
                          Severity <= 10.0 and Severity >= 9.0, "High",
                          "Informational")
Severity =
ifSeverity <= 6.9 and Severity >= 4.0"Low"
elifSeverity <= 8.9 and Severity >= 7.0"Medium"
elifSeverity <= 10.0 and Severity >= 9.0"High"
else"Informational"

Stage 6: project

| project FirstSeen, CompanyName, Severity, RiskCategory, RiskVector, TemporaryId

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
CompanyNameproject
FirstSeenproject
RiskCategoryproject
RiskVectorproject
Severityproject
TemporaryIdproject

Cisco Umbrella - Hack Tool User-Agent Detected

#
Severity
medium
Time window
15m
Source
github.com/Azure/Azure-Sentinel

'Detects suspicious user agent strings used by known hack tools'

MITRE ATT&CK Coverage

TacticTechniques
Command & ControlNo specific technique

Rule Body

id: 8d537f3c-094f-430c-a588-8a87da36ee3a
name: Cisco Umbrella - Hack Tool User-Agent Detected
description: |
  'Detects suspicious user agent strings used by known hack tools'
severity: Medium
requiredDataConnectors:
  - connectorId: CiscoUmbrellaDataConnector
    dataTypes:
      - Cisco_Umbrella_proxy_CL
queryFrequency: 15m
queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
tactics:
  - CommandAndControl
query: |
  let timeframe = 15m;
  let user_agents=dynamic([
                            '(hydra)',
                            ' arachni/',
                            ' BFAC ',
                            ' brutus ',
                            ' cgichk ',
                            'core-project/1.0',
                            ' crimscanner/',
                            'datacha0s',
                            'dirbuster',
                            'domino hunter',
                            'dotdotpwn',
                            'FHScan Core',
                            'floodgate',
                            'get-minimal',
                            'gootkit auto-rooter scanner',
                            'grendel-scan',
                            ' inspath ',
                            'internet ninja',
                            'jaascois',
                            ' zmeu ',
                            'masscan',
                            ' metis ',
                            'morfeus fucking scanner',
                            'n-stealth',
                            'nsauditor',
                            'pmafind',
                            'security scan',
                            'springenwerk',
                            'teh forest lobster',
                            'toata dragostea',
                            ' vega/',
                            'voideye',
                            'webshag',
                            'webvulnscan',
                            ' whcc/',
                            ' Havij',
                            'absinthe',
                            'bsqlbf',
                            'mysqloit',
                            'pangolin',
                            'sql power injector',
                            'sqlmap',
                            'sqlninja',
                            'uil2pn',
                            'ruler',
                            'Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729)'
                            ]);
  Cisco_Umbrella
  | where EventType == "proxylogs"
  | where TimeGenerated > ago(timeframe)
  | where HttpUserAgentOriginal has_any (user_agents)
  | extend Message = "Hack Tool User Agent"
  | project Message, SrcIpAddr, DstIpAddr, UrlOriginal, TimeGenerated, HttpUserAgentOriginal
entityMappings:
  - entityType: URL
    fieldMappings:
      - identifier: Url
        columnName: UrlOriginal
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SrcIpAddr
version: 1.1.2
kind: Scheduled

Stages and Predicates

Parameters

let timeframe = 15m;

Let Binding: user_agents used in Stage 4

let user_agents = dynamic([
                          '(hydra)',
                          ' arachni/',
                          ' BFAC ',
                          ' brutus ',
                          ' cgichk ',
                          'core-project/1.0',
                          ' crimscanner/',
                          'datacha0s',
                          'dirbuster',
                          'domino hunter',
                          'dotdotpwn',
                          'FHScan Core',
                          'floodgate',
                          'get-minimal',
                          'gootkit auto-rooter scanner',
                          'grendel-scan',
                          ' inspath ',
                          'internet ninja',
                          'jaascois',
                          ' zmeu ',
                          'masscan',
                          ' metis ',
                          'morfeus fucking scanner',
                          'n-stealth',
                          'nsauditor',
                          'pmafind',
                          'security scan',
                          'springenwerk',
                          'teh forest lobster',
                          'toata dragostea',
                          ' vega/',
                          'voideye',
                          'webshag',
                          'webvulnscan',
                          ' whcc/',
                          ' Havij',
                          'absinthe',
                          'bsqlbf',
                          'mysqloit',
                          'pangolin',
                          'sql power injector',
                          'sqlmap',
                          'sqlninja',
                          'uil2pn',
                          'ruler',
                          'Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729)'
                          ]);

Stage 1: source

Cisco_Umbrella

Stage 2: where

| where EventType == "proxylogs"

Stage 3: where

| where TimeGenerated > ago(timeframe)

Stage 4: where

| where HttpUserAgentOriginal has_any (user_agents)

Stage 5: extend

| extend Message = "Hack Tool User Agent"

Stage 6: project

| project Message, SrcIpAddr, DstIpAddr, UrlOriginal, TimeGenerated, HttpUserAgentOriginal

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
EventTypeeq
  • proxylogs
field:"EventType" kind:eq value:"proxylogs"
HttpUserAgentOriginalmatch
  • BFAC transforms: term
  • Havij transforms: term
  • arachni/ transforms: term
  • brutus transforms: term
  • cgichk transforms: term
  • crimscanner/ transforms: term
  • inspath transforms: term
  • metis transforms: term
  • vega/ transforms: term
  • whcc/ transforms: term
  • zmeu transforms: term
  • (hydra) transforms: term
  • FHScan Core transforms: term
  • Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729) transforms: term
  • absinthe transforms: term
  • bsqlbf transforms: term
  • core-project/1.0 transforms: term
  • datacha0s transforms: term
  • dirbuster transforms: term
  • domino hunter transforms: term
  • dotdotpwn transforms: term
  • floodgate transforms: term
  • get-minimal transforms: term
  • gootkit auto-rooter scanner transforms: term
  • grendel-scan transforms: term
  • internet ninja transforms: term
  • jaascois transforms: term
  • masscan transforms: term
  • morfeus fucking scanner transforms: term
  • mysqloit transforms: term
  • n-stealth transforms: term
  • nsauditor transforms: term
  • pangolin transforms: term
  • pmafind transforms: term
  • ruler transforms: term
  • security scan transforms: term
  • springenwerk transforms: term
  • sql power injector transforms: term
  • sqlmap transforms: term
  • sqlninja transforms: term
  • teh forest lobster transforms: term
  • toata dragostea transforms: term
  • uil2pn transforms: term
  • voideye transforms: term
  • webshag transforms: term
  • webvulnscan transforms: term
field:"HttpUserAgentOriginal" kind:match

Output Fields

These fields are emitted when the rule matches.

FieldSource
DstIpAddrproject
HttpUserAgentOriginalproject
Messageproject
SrcIpAddrproject
TimeGeneratedproject
UrlOriginalproject

Cyble Vision Alerts Vulnerability

#

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
low
Time window
30m
Source
github.com/Azure/Azure-Sentinel

'Detects SSL/TLS and application vulnerabilities from CybleVision. Extracts host, IP, port, severity, vulnerability ID and first-seen metadata using the Alerts_Vulnerability parser. Incidents grouped per service.'

MITRE ATT&CK Coverage

Rule Body

id: 0e0cdda9-4536-4cc9-91cf-736e8957ed26
name: Cyble Vision Alerts Vulnerability
description: |
  'Detects SSL/TLS and application vulnerabilities from CybleVision. Extracts host, IP, port, severity, vulnerability ID and first-seen metadata using the Alerts_Vulnerability parser. Incidents grouped per service.'
severity: Low
status: Available
requiredDataConnectors:
- connectorId: CybleVisionAlerts
  dataTypes:
  - CybleVisionAlerts_CL
enabled: true
queryFrequency: 30m
queryPeriod: 30m
triggerOperator: GreaterThan
triggerThreshold: 0
suppressionDuration: PT5H
eventGroupingSettings:
  aggregationKind: AlertPerResult
tactics:
- Reconnaissance
- Execution
- Discovery
relevantTechniques:
- T1595
- T1203
- T1046
subTechniques: []
query: |
  Alerts_vulnerability 
  | where Service == "vulnerability" 
  | extend MappedSeverity = Severity
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: false
    reopenClosedIncident: false
    lookbackDuration: PT5H
    matchingMethod: AllEntities
alertDetailsOverride:
  alertDisplayNameFormat: CybleVision Vulnerability {{V_Title}}
  alertDescriptionFormat: |
    A vulnerability was detected for host {{V_Host}} (IP {{V_IP}}, Port {{V_Port}}).
  alertDynamicProperties: []
customDetails:
  MappedSeverity: Severity
  Status: Status
  AlertID: AlertID
  Service: Service
  Title: V_Title
  V_Port: V_Port
  V_VulnID: V_VulnID
  V_Type: V_Type
  V_Confidence: V_Confidence
  V_FirstSeen: V_FirstSeen
  V_LastSeen: V_LastSeen
entityMappings:
- entityType: Host
  fieldMappings:
  - identifier: HostName
    columnName: V_Host
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: V_IP
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

Alerts_vulnerability

Stage 2: where

| where Service == "vulnerability"

Stage 3: extend

| extend MappedSeverity = Severity

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
Serviceeq
  • vulnerability
field:"Service" kind:eq value:"vulnerability"

Output Fields

These fields are emitted when the rule matches.

FieldSource
MappedSeverityextend

Detecting UAC bypass - elevated COM interface

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

This query identifies processes spawned with high integrity from dllhost.exe with a command line that contains one of three specific CLSID GUIDs.

MITRE ATT&CK Coverage

TacticTechniques
Impact

Telemetry Coverage

Rule Body

id: 2d5efc71-2e91-4ca2-8506-857eecb453ec
name: Detecting UAC bypass - elevated COM interface
description: |
  This query identifies processes spawned with high integrity from dllhost.exe with a command line that contains one of three specific CLSID GUIDs.
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: MicrosoftThreatProtection
    dataTypes:
      - DeviceProcessEvents
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Impact
relevantTechniques:
  - T1490
query: |
  DeviceProcessEvents
  | where InitiatingProcessFileName =~ "dllhost.exe"
  | where ProcessIntegrityLevel == "High"
  | where InitiatingProcessCommandLine has_any ("E9495B87-D950-4AB5-87A5-FF6D70BF3E90", "3E5FC7F9-9A51-4367-9063-A120244FBEC7", "D2E7041B-2927-42fb-8E9F-7CE93B6DC937")

entityMappings:
  - entityType: Host
    fieldMappings:
      - identifier: FullName
        columnName: DeviceName
  - entityType: Account
    fieldMappings:
      - identifier: Sid
        columnName: AccountSid
      - identifier: Name
        columnName: AccountName
      - identifier: NTDomain
        columnName: AccountDomain
  - entityType: Process
    fieldMappings:
      - identifier: CommandLine
        columnName: ProcessCommandLine
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

DeviceProcessEvents

Stage 2: where

| where InitiatingProcessFileName =~ "dllhost.exe"

Stage 3: where

| where ProcessIntegrityLevel == "High"

Stage 4: where

| where InitiatingProcessCommandLine has_any ("E9495B87-D950-4AB5-87A5-FF6D70BF3E90", "3E5FC7F9-9A51-4367-9063-A120244FBEC7", "D2E7041B-2927-42fb-8E9F-7CE93B6DC937")

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
InitiatingProcessCommandLinematch
  • 3E5FC7F9-9A51-4367-9063-A120244FBEC7 transforms: term
  • D2E7041B-2927-42fb-8E9F-7CE93B6DC937 transforms: term
  • E9495B87-D950-4AB5-87A5-FF6D70BF3E90 transforms: term
field:"ParentCommandLine" kind:match
InitiatingProcessFileNameeq
  • dllhost.exe corpus 8 (elastic 5, kusto 2, splunk 1)
field:"parent_process_basename" kind:eq value:"dllhost.exe"
ProcessIntegrityLeveleq
  • High corpus 3 (kusto 3)
field:"IntegrityLevel" kind:eq value:"High"

Detecting UAC bypass - modify Windows Store settings

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

This query identifies modification a specific registry key and then launching wsreset.exe that resets the Windows Store settings.

MITRE ATT&CK Coverage

TacticTechniques
Impact

Telemetry Coverage

Rule Body

id: 8b8fbf9c-35d4-474b-8151-a40173521293
name: Detecting UAC bypass - modify Windows Store settings
description: |
  This query identifies modification a specific registry key and then launching wsreset.exe that resets the Windows Store settings.
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: MicrosoftThreatProtection
    dataTypes:
      - DeviceProcessEvents
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Impact
relevantTechniques:
  - T1490
query: |
  DeviceProcessEvents
  | where InitiatingProcessFileName =~ "wsreset.exe"
  | where ProcessIntegrityLevel == "High"

entityMappings:
  - entityType: Host
    fieldMappings:
      - identifier: FullName
        columnName: DeviceName
  - entityType: Account
    fieldMappings:
      - identifier: Sid
        columnName: AccountSid
      - identifier: Name
        columnName: AccountName
      - identifier: NTDomain
        columnName: AccountDomain
  - entityType: Process
    fieldMappings:
      - identifier: CommandLine
        columnName: ProcessCommandLine
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

DeviceProcessEvents

Stage 2: where

| where InitiatingProcessFileName =~ "wsreset.exe"

Stage 3: where

| where ProcessIntegrityLevel == "High"

Indicators

These rows show field, operator, and value matches.

Excessive NXDOMAIN DNS Queries

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

'This creates an incident in the event a client generates excessive amounts of DNS queries for non-existent domains.'

MITRE ATT&CK Coverage

TacticTechniques
Command & Control

Rule Body

id: b8266f81-2715-41a6-9062-42486cbc9c73
name: Excessive NXDOMAIN DNS Queries
description: |
  'This creates an incident in the event a client generates excessive amounts of DNS queries for non-existent domains.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: SyslogAma
    datatypes:
      - Syslog
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - CommandAndControl
relevantTechniques:
  - T1568
  - T1008
query: |
  let threshold = 200;
  Infoblox_dnsclient
  | where isnotempty(DnsResponseCode)
  | where DnsResponseCode =~ "NXDOMAIN"
  | summarize count() by SrcIpAddr, bin(TimeGenerated,15m)
  | where count_ > threshold
  | join kind=inner (Infoblox_dnsclient
      | where isnotempty(DnsResponseCode)
      | where DnsResponseCode =~ "NXDOMAIN"
      ) on SrcIpAddr
entityMappings:
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SrcIpAddr
version: 1.0.5
kind: Scheduled

Stages and Predicates

Parameters

let threshold = 200;

Stage 1: source

Infoblox_dnsclient

Stage 2: where

| where isnotempty(DnsResponseCode)

Stage 3: where

| where DnsResponseCode =~ "NXDOMAIN"

Stage 4: summarize

| summarize count() by SrcIpAddr, bin(TimeGenerated,15m)

Stage 5: where

| where count_ > threshold

Stage 6: join

| join kind=inner (Infoblox_dnsclient
    | where isnotempty(DnsResponseCode)
    | where DnsResponseCode =~ "NXDOMAIN"
    ) on SrcIpAddr

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
SrcIpAddrsummarize

Gain Code Execution on ADFS Server via SMB + Remote Service or Scheduled Task

#
Status
available
Severity
medium
Time window
7d
Group by
$left.SubjectLogonId, $right.TargetLogonId
Source
github.com/Azure/Azure-Sentinel

This query detects instances where an attacker has gained the ability to execute code on an ADFS Server through SMB and Remote Service or Scheduled Task.

MITRE ATT&CK Coverage

TacticTechniques
Lateral Movement

Telemetry Coverage

Rule Body

id: 12dcea64-bec2-41c9-9df2-9f28461b1295
name: Gain Code Execution on ADFS Server via SMB + Remote Service or Scheduled Task
description: |
   'This query detects instances where an attacker has gained the ability to execute code on an ADFS Server through SMB and Remote Service or Scheduled Task.'
severity: Medium
requiredDataConnectors:
  - connectorId: SecurityEvents
    dataTypes:
      - SecurityEvent
  - connectorId: WindowsSecurityEvents
    dataTypes:
      - SecurityEvent
queryFrequency: 1d
queryPeriod: 7d
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
  - LateralMovement
relevantTechniques:
  - T1210
tags:
  - Solorigate
  - NOBELIUM
query: |
  let timeframe = 1d;
  // Adjust for a longer timeframe for identifying ADFS Servers
  let lookback = 6d;
  // Identify ADFS Servers
  let ADFS_Servers = (
  SecurityEvent
  | where TimeGenerated > ago(timeframe+lookback)
  | where EventID == 4688 and SubjectLogonId != "0x3e4"
  | where NewProcessName has "Microsoft.IdentityServer.ServiceHost.exe"
  | distinct Computer
  );
  SecurityEvent
  | where TimeGenerated > ago(timeframe)
  | where Computer in~ (ADFS_Servers)
  | where Account !endswith "$"
  // Check for scheduled task events
  | where EventID in (4697, 4698, 4699, 4700, 4701, 4702)
  | extend EventDataParsed = parse_xml(EventData)
  | extend SubjectLogonId = tostring(EventDataParsed.EventData.Data[3]["#text"])
  // Check specifically for access to IPC$ share and PIPE\svcctl and PIPE\atsvc for Service Control Services and Schedule Control Services
  | union (
      SecurityEvent
      | where TimeGenerated > ago(timeframe)
      | where Computer in~ (ADFS_Servers)
      | where Account !endswith "$"
      | where EventID == 5145
      | where RelativeTargetName =~ "svcctl" or RelativeTargetName  =~ "atsvc"
  )
  // Check for lateral movement
  | join kind=inner
  (SecurityEvent
  | where TimeGenerated > ago(timeframe)
  | where Account !endswith "$"
  | where EventID == 4624 and LogonType == 3
  ) on $left.SubjectLogonId == $right.TargetLogonId
  | project TimeGenerated, Account, Computer, EventID, RelativeTargetName
  | extend timestamp = TimeGenerated
  | extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
  | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
  | extend AccountName = tostring(split(Account, @'\')[1]), AccountNTDomain = tostring(split(Account, @'\')[0])
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: Account
      - identifier: Name
        columnName: AccountName
      - identifier: NTDomain
        columnName: AccountNTDomain
  - entityType: Host
    fieldMappings:
      - identifier: FullName
        columnName: Computer
      - identifier: HostName
        columnName: HostName
      - identifier: DnsDomain
        columnName: HostNameDomain
version: 1.2.1
kind: Scheduled

Stages and Predicates

Parameters

let timeframe = 1d;
let lookback = 6d;

Let Binding: ADFS_Servers used in Stages 1, 4, 12

let ADFS_Servers = (
SecurityEvent
| where TimeGenerated > ago(timeframe+lookback)
| where EventID == 4688 and SubjectLogonId != "0x3e4"
| where NewProcessName has "Microsoft.IdentityServer.ServiceHost.exe"
| distinct Computer
);

Stage 1: source

let ADFS_Servers

Stage 2: source

SecurityEvent

Stage 3: where

| where TimeGenerated > ago(timeframe)

Stage 4: where

| where Computer in~ (ADFS_Servers)

Stage 5: where

| where Account !endswith "$"

Stage 6: where

| where EventID in (4697, 4698, 4699, 4700, 4701, 4702)

Stage 7: extend

| extend EventDataParsed = parse_xml(EventData)

Stage 8: extend

| extend SubjectLogonId = tostring(EventDataParsed.EventData.Data[3]["#text"])

Stage 9: union

union of 1 branches

Stage 10: source

SecurityEvent

Stage 11: where

| where TimeGenerated > ago(timeframe)

Stage 12: where

| where Computer in~ (ADFS_Servers)

Stage 13: where

| where Account !endswith "$"

Stage 14: where

| where EventID == 5145

Stage 15: where

| where RelativeTargetName =~ "svcctl" or RelativeTargetName  =~ "atsvc"

Stage 16: join

| join kind=inner
(SecurityEvent
| where TimeGenerated > ago(timeframe)
| where Account !endswith "$"
| where EventID == 4624 and LogonType == 3
) on $left.SubjectLogonId == $right.TargetLogonId

Stage 17: project

project Account, Computer, EventID, RelativeTargetName, TimeGenerated

Stage 18: extend (4 consecutive steps)

extend AccountNTDomain, AccountName, DomainIndex, HostName, HostNameDomain, timestamp

Indicators

These rows show field, operator, and value matches.

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
Accountends_with$excludes:Account field:"Account" value:"$"

Output Fields

These fields are emitted when the rule matches.

FieldSource
Accountproject
Computerproject
EventIDproject
RelativeTargetNameproject
TimeGeneratedproject
timestampextend
DomainIndexextend
HostNameextend
HostNameDomainextend
AccountNTDomainextend
AccountNameextend

GitHub - Oauth application - a client secret was removed

#
Status
available
Severity
medium
Time window
7d
Source
github.com/Azure/Azure-Sentinel

Detect activities when a client secret was removed. This query runs every day and its severity is Medium.

MITRE ATT&CK Coverage

TacticTechniques
Initial Access

Telemetry Coverage

Rule Body

id: 0b85a077-8ba5-4cb5-90f7-1e882afe10c5
name: GitHub - Oauth application - a client secret was removed
description: |
  'Detect activities when a client secret was removed. This query runs every day and its severity is Medium.'
severity: Medium
status: Available
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 7d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - InitialAccess
relevantTechniques:
  - T1078
query: |
    GitHubAuditData
    | where Action == "oauth_application.remove_client_secret"
    | extend AccountName = tostring(split(Actor, "@")[0]), AccountUPNSuffix = tostring(split(Actor, "@")[1])
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: Actor
      - identifier: Name
        columnName: AccountName
      - identifier: UPNSuffix
        columnName: AccountUPNSuffix
version: 1.0.1
kind: Scheduled

Stages and Predicates

Stage 1: source

GitHubAuditData

Stage 2: where

| where Action == "oauth_application.remove_client_secret"

Stage 3: extend

| extend AccountName = tostring(split(Actor, "@")[0]), AccountUPNSuffix = tostring(split(Actor, "@")[1])

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
Actioneq
  • oauth_application.remove_client_secret
field:"Action" kind:eq value:"oauth_application.remove_client_secret"

Output Fields

These fields are emitted when the rule matches.

FieldSource
AccountNameextend
AccountUPNSuffixextend

GitHub Two Factor Auth Disable

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

Two-factor authentication is a process where a user is prompted during the sign-in process for an additional form of identification, such as to enter a code on their cellphone or to provide a fingerprint scan. Two factor authentication reduces the risk of account takeover. Attacker will want to disable such security tools in order to go undetected.

MITRE ATT&CK Coverage

TacticTechniques
Defense Impairment

Telemetry Coverage

Rules Detecting the Same Action

These rules filter on the same operation.

Rule Body

id: 3ff0fffb-d963-40c0-b235-3404f915add7
name: GitHub Two Factor Auth Disable
description: |
  'Two-factor authentication is a process where a user is prompted during the sign-in process for an additional form of identification, such as to enter a code on their cellphone or to provide a fingerprint scan. Two factor authentication reduces the risk of account takeover. Attacker will want to disable such security tools in order to go undetected. '
severity: Medium
status: Available
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - DefenseEvasion
relevantTechniques:
  - T1562
query: |
  GitHubAuditData
  | where Action == "org.disable_two_factor_requirement"
  | project TimeGenerated, Action, Actor, Country, Repository
  | extend Name = iif(Actor contains "@", split(Actor, "@")[0], Actor)
  | extend UPNSuffix = iif(Actor contains "@", split(Actor, "@")[1], "")
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: Actor
      - identifier: Name
        columnName: Name
      - identifier: UPNSuffix
        columnName: UPNSuffix
version: 1.0.2
kind: Scheduled

Stages and Predicates

Stage 1: source

GitHubAuditData

Stage 2: where

| where Action == "org.disable_two_factor_requirement"

Stage 3: project

| project TimeGenerated, Action, Actor, Country, Repository

Stage 4: extend

| extend Name = iif(Actor contains "@", split(Actor, "@")[0], Actor)

Stage 5: extend

| extend UPNSuffix = iif(Actor contains "@", split(Actor, "@")[1], "")

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
Actioneq
  • org.disable_two_factor_requirement corpus 2 (kusto 2)
field:"Action" kind:eq value:"org.disable_two_factor_requirement"

Output Fields

These fields are emitted when the rule matches.

FieldSource
Actionproject
Actorproject
Countryproject
Repositoryproject
TimeGeneratedproject
Nameextend
UPNSuffixextend

Lookout - Device Compliance and Security Status Changes (v2)

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

'Monitors device compliance status changes and security posture degradation using Lookout Mobile Risk API v2 enhanced device fields. Detects devices becoming non-compliant, security status changes, and potential device compromise indicators with detailed device context and MDM integration data.'

MITRE ATT&CK Coverage

Rule Body

id: 9c5b6d8f-3a02-4e9b-af4c-2d7e9b1f5a8c
name: Lookout - Device Compliance and Security Status Changes (v2)
description: |
  'Monitors device compliance status changes and security posture degradation using Lookout Mobile Risk API v2 enhanced device fields. Detects devices becoming non-compliant, security status changes, and potential device compromise indicators with detailed device context and MDM integration data.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: LookoutAPI
    dataTypes:
      - LookoutEvents
queryFrequency: 10m
queryPeriod: 30m
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Discovery
  - DefenseEvasion
  - Persistence
relevantTechniques:
  - T1418
  - T1629
  - T1655
query: |
  LookoutEvents
  | where EventType == "DEVICE"
  | where DeviceComplianceStatus in ("Non-Compliant", "Partial") 
     or DeviceSecurityStatus in ("THREATS_HIGH", "THREATS_MEDIUM")
     or ChangeType == "UPDATE"
  | extend 
      DeviceRiskScore = case(
          DeviceSecurityStatus == "THREATS_HIGH", 9,
          DeviceSecurityStatus == "THREATS_MEDIUM", 6,
          DeviceSecurityStatus == "THREATS_LOW", 3,
          DeviceComplianceStatus == "Non-Compliant", 7,
          DeviceComplianceStatus == "Partial", 4,
          1
      ),
      ComplianceReason = case(
          isempty(DeviceCheckinTime), "No Recent Check-in",
          DeviceActivationStatus != "ACTIVE", "Inactive Device",
          isempty(ClientLookoutSDKVersion), "Missing Security Client",
          "Configuration Issue"
      ),
      PlatformRisk = case(
          DevicePlatform == "ANDROID" and DeviceOSVersion matches regex @"^[1-9]\..*", "Outdated Android",
          DevicePlatform == "IOS" and DeviceOSVersion matches regex @"^1[0-4]\..*", "Outdated iOS",
          DevicePlatform == "UNKNOWN", "Unknown Platform",
          "Current"
      )
  | extend MDMIntegrationStatus = case(
      isnotempty(MDMConnectorId) and isnotempty(MDMExternalId), "Fully Integrated",
      isnotempty(MDMConnectorId), "Partial Integration", 
      "Not Integrated"
  )
  | extend SecurityPosture = case(
      DeviceRiskScore >= 8, "Critical",
      DeviceRiskScore >= 6, "High",
      DeviceRiskScore >= 4, "Medium",
      "Low"
  )
  | project
      TimeGenerated,
      EventId,
      DeviceGuid,
      DevicePlatform,
      DeviceOSVersion,
      DeviceManufacturer,
      DeviceModel,
      DeviceEmailAddress,
      DeviceActivationStatus,
      DeviceSecurityStatus,
      DeviceComplianceStatus,
      DeviceRiskScore,
      SecurityPosture,
      ComplianceReason,
      PlatformRisk,
      DeviceCheckinTime,
      DeviceActivatedAt,
      DeviceDeactivatedAt,
      DeviceGroupGuid,
      ClientLookoutSDKVersion,
      ClientOTAVersion,
      ClientPackageName,
      ClientPackageVersion,
      MDMConnectorId,
      MDMConnectorUuid,
      MDMExternalId,
      MDMIntegrationStatus,
      ActorType,
      ActorGuid,
      ChangeType
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: DeviceEmailAddress
  - entityType: Host
    fieldMappings:
      - identifier: HostName
        columnName: DeviceGuid
      - identifier: OSFamily
        columnName: DevicePlatform
      - identifier: OSVersion
        columnName: DeviceOSVersion
customDetails:
  DevicePlatform: DevicePlatform
  DeviceSecStatus: DeviceSecurityStatus
  DevCompliance: DeviceComplianceStatus
  DeviceRiskScore: DeviceRiskScore
  SecurityPosture: SecurityPosture
  ComplianceReason: ComplianceReason
  PlatformRisk: PlatformRisk
  MDMIntegration: MDMIntegrationStatus
  ClientSDKVersion: ClientLookoutSDKVersion
  DeviceManufacturer: DeviceManufacturer
  DeviceModel: DeviceModel
alertDetailsOverride:
  alertDisplayNameFormat: "Device Compliance Issue: {{SecurityPosture}} Risk on {{DevicePlatform}} Device"
  alertDescriptionFormat: "{{SecurityPosture}} posture with {{DeviceComplianceStatus}} compliance"
  alertTacticsColumnName: SecurityPosture
  alertSeverityColumnName: SecurityPosture
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: false
    lookbackDuration: P1D
    matchingMethod: Selected
    groupByEntities:
      - Account
      - Host
    groupByAlertDetails:
      - DeviceGuid
    groupByCustomDetails:
      - SecurityPosture
      - DevicePlatform
eventGroupingSettings:
  aggregationKind: AlertPerResult
suppressionEnabled: false
suppressionDuration: PT30M
version: 2.0.3
kind: Scheduled

Stages and Predicates

Stage 1: source

LookoutEvents

Stage 2: where

| where EventType == "DEVICE"

Stage 3: where

| where DeviceComplianceStatus in ("Non-Compliant", "Partial") 
   or DeviceSecurityStatus in ("THREATS_HIGH", "THREATS_MEDIUM")
   or ChangeType == "UPDATE"

Stage 4: extend (3 consecutive steps)

| extend 
    DeviceRiskScore = case(
        DeviceSecurityStatus == "THREATS_HIGH", 9,
        DeviceSecurityStatus == "THREATS_MEDIUM", 6,
        DeviceSecurityStatus == "THREATS_LOW", 3,
        DeviceComplianceStatus == "Non-Compliant", 7,
        DeviceComplianceStatus == "Partial", 4,
        1
    ),
    ComplianceReason = case(
        isempty(DeviceCheckinTime), "No Recent Check-in",
        DeviceActivationStatus != "ACTIVE", "Inactive Device",
        isempty(ClientLookoutSDKVersion), "Missing Security Client",
        "Configuration Issue"
    ),
    PlatformRisk = case(
        DevicePlatform == "ANDROID" and DeviceOSVersion matches regex @"^[1-9]\..*", "Outdated Android",
        DevicePlatform == "IOS" and DeviceOSVersion matches regex @"^1[0-4]\..*", "Outdated iOS",
        DevicePlatform == "UNKNOWN", "Unknown Platform",
        "Current"
    )
| extend MDMIntegrationStatus = case(
    isnotempty(MDMConnectorId) and isnotempty(MDMExternalId), "Fully Integrated",
    isnotempty(MDMConnectorId), "Partial Integration", 
    "Not Integrated"
)
| extend SecurityPosture = case(
    DeviceRiskScore >= 8, "Critical",
    DeviceRiskScore >= 6, "High",
    DeviceRiskScore >= 4, "Medium",
    "Low"
)
ComplianceReason =
ifisempty(DeviceCheckinTime)"No Recent Check-in"
elifDeviceActivationStatus != "ACTIVE""Inactive Device"
elifisempty(ClientLookoutSDKVersion)"Missing Security Client"
else"Configuration Issue"
DeviceRiskScore =
ifDeviceSecurityStatus == "THREATS_HIGH"9
elifDeviceSecurityStatus == "THREATS_MEDIUM"6
elifDeviceSecurityStatus == "THREATS_LOW"3
elifDeviceComplianceStatus == "Non-Compliant"7
elifDeviceComplianceStatus == "Partial"4
else1
PlatformRisk =
ifDevicePlatform == "ANDROID" and DeviceOSVersion matches regex @"^[1-9]\..*""Outdated Android"
elifDevicePlatform == "IOS" and DeviceOSVersion matches regex @"^1[0-4]\..*""Outdated iOS"
elifDevicePlatform == "UNKNOWN""Unknown Platform"
else"Current"

Stage 5: project

| project
    TimeGenerated,
    EventId,
    DeviceGuid,
    DevicePlatform,
    DeviceOSVersion,
    DeviceManufacturer,
    DeviceModel,
    DeviceEmailAddress,
    DeviceActivationStatus,
    DeviceSecurityStatus,
    DeviceComplianceStatus,
    DeviceRiskScore,
    SecurityPosture,
    ComplianceReason,
    PlatformRisk,
    DeviceCheckinTime,
    DeviceActivatedAt,
    DeviceDeactivatedAt,
    DeviceGroupGuid,
    ClientLookoutSDKVersion,
    ClientOTAVersion,
    ClientPackageName,
    ClientPackageVersion,
    MDMConnectorId,
    MDMConnectorUuid,
    MDMExternalId,
    MDMIntegrationStatus,
    ActorType,
    ActorGuid,
    ChangeType

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
ActorGuidproject
ActorTypeproject
ChangeTypeproject
ClientLookoutSDKVersionproject
ClientOTAVersionproject
ClientPackageNameproject
ClientPackageVersionproject
ComplianceReasonproject
DeviceActivatedAtproject
DeviceActivationStatusproject
DeviceCheckinTimeproject
DeviceComplianceStatusproject
DeviceDeactivatedAtproject
DeviceEmailAddressproject
DeviceGroupGuidproject
DeviceGuidproject
DeviceManufacturerproject
DeviceModelproject
DeviceOSVersionproject
DevicePlatformproject
DeviceRiskScoreproject
DeviceSecurityStatusproject
EventIdproject
MDMConnectorIdproject
MDMConnectorUuidproject
MDMExternalIdproject
MDMIntegrationStatusproject
PlatformRiskproject
SecurityPostureproject
TimeGeneratedproject

Mimecast Targeted Threat Protection - URL Protect

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

'Detects malicious scan results and actions which are not allowed.'

MITRE ATT&CK Coverage

TacticTechniques
Initial Access

Rule Body

id: 952faed4-c6a6-4873-aeb9-b348e9ce5aba
name: Mimecast Targeted Threat Protection - URL Protect
description: |
  'Detects malicious scan results and actions which are not allowed.'
severity: High
status: Available
requiredDataConnectors:
  - connectorId: MimecastTTPAPI
    dataTypes:
      - MimecastTTPUrl
queryFrequency: 30m
queryPeriod: 30m
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
- Discovery
relevantTechniques:
- T0865
query: |
  MimecastTTPUrl
  | where ['Scan Result'] == "malicious" and Action != "allow"
  | extend  From_User_EmailAddress = ['From User Email Address'],MessageID = ['Message ID'] , User_EmailAddress = ['User Email Address'], SendingIP = ['Sending IP']
suppressionDuration: 5h
suppressionEnabled: false
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: false
    lookbackDuration: P7D
    matchingMethod: AllEntities
eventGroupingSettings:
  aggregationKind: AlertPerResult
entityMappings:
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SendingIP
  - entityType: MailMessage
    fieldMappings:
      - identifier: Sender
        columnName: From_User_EmailAddress
      - identifier: InternetMessageId
        columnName: MessageID
      - identifier: Recipient
        columnName: User_EmailAddress
  - entityType: URL
    fieldMappings:
      - identifier: Url
        columnName: Url
version: 1.0.1
kind: Scheduled

Stages and Predicates

Stage 1: source

MimecastTTPUrl

Stage 2: where

| where ['Scan Result'] == "malicious" and Action != "allow"

Stage 3: extend

| extend  From_User_EmailAddress = ['From User Email Address'],MessageID = ['Message ID'] , User_EmailAddress = ['User Email Address'], SendingIP = ['Sending IP']

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
Actionne
  • allow
field:"Action" kind:ne value:"allow"
Scan Resulteq
  • malicious transforms: kusto_literal_column
field:"Scan Result" kind:eq value:"malicious"

Output Fields

These fields are emitted when the rule matches.

FieldSource
From_User_EmailAddressextend
MessageIDextend
SendingIPextend
User_EmailAddressextend

Oracle - Oracle WebLogic Exploit CVE-2021-2109

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

'Detects exploitation of Oracle WebLogic vulnerability CVE-2021-2109'

MITRE ATT&CK Coverage

TacticTechniques
Initial Access

Rule Body

id: 67950168-5740-11ec-bf63-0242ac130002
name: Oracle - Oracle WebLogic Exploit CVE-2021-2109 
description: |
  'Detects exploitation of Oracle WebLogic vulnerability CVE-2021-2109'
severity: High
status: Available
requiredDataConnectors:
  - connectorId: CustomLogsAma
    dataTypes:
      - OracleWebLogicServer_CL
queryFrequency: 10m
queryPeriod: 10m
triggerOperator: gt
triggerThreshold: 0
tactics:
  - InitialAccess
relevantTechniques:
  - T1190
query: |
  OracleWebLogicServerEvent
  | where HttpRequestMethod =~ "GET"
  | where UrlOriginal has_all ("ldap://", "com.bea.console.handles.JndiBindingHandle", "AdminServer")
  | extend UrlCustomEntity = UrlOriginal
entityMappings:
  - entityType: URL
    fieldMappings:
      - identifier: Url
        columnName: UrlCustomEntity
version: 1.0.3
kind: Scheduled

Stages and Predicates

Stage 1: source

OracleWebLogicServerEvent

Stage 2: where

| where HttpRequestMethod =~ "GET"

Stage 3: where

| where UrlOriginal has_all ("ldap://", "com.bea.console.handles.JndiBindingHandle", "AdminServer")

Stage 4: extend

| extend UrlCustomEntity = UrlOriginal

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
HttpRequestMethodeq
  • GET
field:"HttpRequestMethod" kind:eq value:"GET"
UrlOriginalmatch
  • AdminServer transforms: term
  • com.bea.console.handles.JndiBindingHandle transforms: term
  • ldap:// transforms: term
field:"UrlOriginal" kind:match

Output Fields

These fields are emitted when the rule matches.

FieldSource
UrlCustomEntityextend

Probable AdFind Recon Tool Usage (Normalized Process Events)

#
Severity
high
Time window
1h
Author
Yuval Naor
Source
github.com/Azure/Azure-Sentinel

Identifies the host and account that executed AdFind by hash and filename in addition to common and unique flags that are used by many threat actors in discovery. To use this analytics rule, make sure you have deployed the ASIM normalization parsers

MITRE ATT&CK Coverage

TacticTechniques
Discovery

Telemetry Coverage

Rule Body

id: 45076281-35ae-45e0-b443-c32aa0baf965
name: Probable AdFind Recon Tool Usage (Normalized Process Events)
description: |
  'Identifies the host and account that executed AdFind by hash and filename in addition to common and unique flags that are used by many threat actors in discovery.
  To use this analytics rule, make sure you have deployed the [ASIM normalization parsers](https://aka.ms/ASimProcessEvent)'
severity: High
requiredDataConnectors: []
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Discovery
relevantTechniques:
  - T1018
tags:
  - Id: c63ae777-d5e0-4113-8c9a-c2c9d3d09fcd
    version: 1.0.0
  - Schema: ASIMProcessEvent
    SchemaVersion: 0.1.0

query: |
  let args = dynamic(["objectcategory","domainlist","dcmodes","adinfo","trustdmp","computers_pwdnotreqd","Domain Admins", "objectcategory=person", "objectcategory=computer", "objectcategory=*","dclist"]);
  let parentProcesses = dynamic(["pwsh.exe","powershell.exe","cmd.exe"]);
  imProcessCreate
  //looks for execution from a shell
  | where ActingProcessName has_any (parentProcesses)
  | extend ActingProcessFileName = tostring(split(ActingProcessName, '\\')[-1])
  | where ActingProcessFileName in~ (parentProcesses)
  // main filter
  | where Process hassuffix "AdFind.exe" or TargetProcessSHA256 == "c92c158d7c37fea795114fa6491fe5f145ad2f8c08776b18ae79db811e8e36a3"
  // AdFind common Flags to check for from various threat actor TTPs
  or CommandLine has_any (args)
  | extend AlgorithmType = "SHA256"
  | extend AccountName = tostring(split(User, @'\')[1]), AccountNTDomain = tostring(split(User, @'\')[0])
  | extend HostName = tostring(split(Dvc, ".")[0]), DomainIndex = toint(indexof(Dvc, '.'))
  | extend HostNameDomain = iff(DomainIndex != -1, substring(Dvc, DomainIndex + 1), Dvc)
  | project-away DomainIndex
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: User
      - identifier: Name
        columnName: AccountName
      - identifier: NTDomain
        columnName: AccountNTDomain
  - entityType: Host
    fieldMappings:
      - identifier: FullName
        columnName: Dvc
      - identifier: HostName
        columnName: HostName
      - identifier: DnsDomain
        columnName: HostNameDomain
  - entityType: Process
    fieldMappings:
      - identifier: ProcessId
        columnName: ActingProcessName
      - identifier: CommandLine
        columnName: CommandLine
  - entityType: FileHash
    fieldMappings:
      - identifier: Algorithm
        columnName: AlgorithmType
      - identifier: Value
        columnName: TargetProcessSHA256
version: 1.1.6
kind: Scheduled
metadata:
    source:
        kind: Community
    author:
        name: Yuval Naor
    support:
        tier: Community
    categories:
        domains: [ "Security - Threat Intelligence" ]

Stages and Predicates

Parameters

let parentProcesses = dynamic(["pwsh.exe","powershell.exe","cmd.exe"]);

Let Binding: args used in Stage 5

let args = dynamic(["objectcategory","domainlist","dcmodes","adinfo","trustdmp","computers_pwdnotreqd","Domain Admins", "objectcategory=person", "objectcategory=computer", "objectcategory=*","dclist"]);

Stage 1: source

imProcessCreate

Stage 2: where

| where ActingProcessName has_any (parentProcesses)

Stage 3: extend

| extend ActingProcessFileName = tostring(split(ActingProcessName, '\\')[-1])

Stage 4: where

| where ActingProcessFileName in~ (parentProcesses)

Stage 5: where

| where Process hassuffix "AdFind.exe" or TargetProcessSHA256 == "c92c158d7c37fea795114fa6491fe5f145ad2f8c08776b18ae79db811e8e36a3"
or CommandLine has_any (args)

Stage 6: extend (4 consecutive steps)

| extend AlgorithmType = "SHA256"
| extend AccountName = tostring(split(User, @'\')[1]), AccountNTDomain = tostring(split(User, @'\')[0])
| extend HostName = tostring(split(Dvc, ".")[0]), DomainIndex = toint(indexof(Dvc, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Dvc, DomainIndex + 1), Dvc)

Stage 7: project-away

| project-away DomainIndex

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
ActingProcessFileNamein
  • cmd.exe
  • powershell.exe
  • pwsh.exe
field:"ActingProcessFileName" kind:in
ActingProcessNamematch
  • cmd.exe transforms: term
  • powershell.exe transforms: term
  • pwsh.exe transforms: term
field:"ParentImage" kind:match
CommandLinematch
  • Domain Admins transforms: term corpus 2 (kusto 2)
  • adinfo transforms: term corpus 2 (kusto 2)
  • computers_pwdnotreqd transforms: term corpus 2 (kusto 2)
  • dclist transforms: term corpus 2 (kusto 2)
  • dcmodes transforms: term corpus 2 (kusto 2)
  • domainlist transforms: term corpus 2 (kusto 2)
  • objectcategory transforms: term corpus 2 (kusto 2)
  • objectcategory=* transforms: term corpus 2 (kusto 2)
  • objectcategory=computer transforms: term corpus 2 (kusto 2)
  • objectcategory=person transforms: term corpus 2 (kusto 2)
  • trustdmp transforms: term corpus 2 (kusto 2)
field:"CommandLine" kind:match
Processends_with
  • AdFind.exe
field:"Process" kind:ends_with value:"AdFind.exe"
TargetProcessSHA256eq
  • c92c158d7c37fea795114fa6491fe5f145ad2f8c08776b18ae79db811e8e36a3 corpus 2 (kusto 2)
field:"sha256" kind:eq value:"c92c158d7c37fea795114fa6491fe5f145ad2f8c08776b18ae79db811e8e36a3"

Output Fields

These fields are emitted when the rule matches.

FieldSource
ActingProcessFileNameextend
AlgorithmTypeextend
AccountNTDomainextend
AccountNameextend
HostNameextend
HostNameDomainextend

Service Principal Assigned Privileged Role

#
Severity
medium
Time window
1d
Author
Microsoft Security Research
Source
github.com/Azure/Azure-Sentinel

Detects a privileged role being added to a Service Principal. Ensure that any assignment to a Service Principal is valid and appropriate - Service Principals should not be assigned to very highly privileged roles such as Global Admin. Ref: https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-privileged-accounts#changes-to-privileged-accounts

MITRE ATT&CK Coverage

TacticTechniques
Privilege Escalation

Telemetry Coverage

Rule Body

id: 84cccc86-5c11-4b3a-aca6-7c8f738ed0f7
name: Service Principal Assigned Privileged Role
description: |
  'Detects a privileged role being added to a Service Principal.
    Ensure that any assignment to a Service Principal is valid and appropriate - Service Principals should not be assigned to very highly privileged roles such as Global Admin.
    Ref: https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-privileged-accounts#changes-to-privileged-accounts'
severity: Medium
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
      - AuditLogs
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - PrivilegeEscalation
relevantTechniques:
  - T1078.004
tags:
  - AADSecOpsGuide
query: |
  AuditLogs
    | where OperationName has_all ("member to role", "add")
    | where Result =~ "Success"
    | extend type_ = tostring(TargetResources[0].type)
    | where type_ =~ "ServicePrincipal"
    | where isnotempty(TargetResources)
    | extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
    | extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
    | extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
    | extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
    | extend InitiatingIPAddress = tostring(InitiatedBy.user.ipAddress)
    | extend InitiatedBy = tostring(iff(isnotempty(InitiatingUserPrincipalName),InitiatingUserPrincipalName, InitiatingAppName))
    | extend ServicePrincipalName = tostring(TargetResources[0].displayName)
    | extend ServicePrincipalId = tostring(TargetResources[0].id)
    | mv-expand TargetResources[0].modifiedProperties
    | extend TargetResources_0_modifiedProperties = columnifexists("TargetResources_0_modifiedProperties", '')
    | where isnotempty(TargetResources_0_modifiedProperties)
    | extend displayName = tostring(TargetResources_0_modifiedProperties.displayName), newValue = tostring(parse_json(tostring(TargetResources_0_modifiedProperties.newValue)))
    | where displayName == "Role.DisplayName" and newValue contains "admin"
    | extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
    | extend TargetRole = newValue
    | project-reorder TimeGenerated, ServicePrincipalName, ServicePrincipalId, InitiatedBy, TargetRole, InitiatingIPAddress
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: InitiatingAppName
      - identifier: AadUserId
        columnName: InitiatingAppServicePrincipalId
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: InitiatingUserPrincipalName
      - identifier: Name
        columnName: InitiatingAccountName
      - identifier: UPNSuffix
        columnName: InitiatingAccountUPNSuffix
  - entityType: Account
    fieldMappings:
      - identifier: AadUserId
        columnName: InitiatingAadUserId
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: ServicePrincipalName
      - identifier: AadUserId
        columnName: ServicePrincipalId
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: InitiatingIPAddress
version: 1.1.1
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

AuditLogs

Stage 2: where

| where OperationName has_all ("member to role", "add")

Stage 3: where

| where Result =~ "Success"

Stage 4: extend

| extend type_ = tostring(TargetResources[0].type)

Stage 5: where

| where type_ =~ "ServicePrincipal"

Stage 6: where

| where isnotempty(TargetResources)

Stage 7: extend (8 consecutive steps)

| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend InitiatingIPAddress = tostring(InitiatedBy.user.ipAddress)
| extend InitiatedBy = tostring(iff(isnotempty(InitiatingUserPrincipalName),InitiatingUserPrincipalName, InitiatingAppName))
| extend ServicePrincipalName = tostring(TargetResources[0].displayName)
| extend ServicePrincipalId = tostring(TargetResources[0].id)

Stage 8: mv-expand

| mv-expand TargetResources[0].modifiedProperties

Stage 9: extend

| extend TargetResources_0_modifiedProperties = columnifexists("TargetResources_0_modifiedProperties", '')

Stage 10: where

| where isnotempty(TargetResources_0_modifiedProperties)

Stage 11: extend

| extend displayName = tostring(TargetResources_0_modifiedProperties.displayName), newValue = tostring(parse_json(tostring(TargetResources_0_modifiedProperties.newValue)))

Stage 12: where

| where displayName == "Role.DisplayName" and newValue contains "admin"

Stage 13: extend

| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])

Stage 14: extend

| extend TargetRole = newValue

Stage 15: project-reorder

| project-reorder TimeGenerated, ServicePrincipalName, ServicePrincipalId, InitiatedBy, TargetRole, InitiatingIPAddress

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
type_extend
InitiatingAppNameextend
InitiatingAppServicePrincipalIdextend
InitiatingUserPrincipalNameextend
InitiatingAadUserIdextend
InitiatingIPAddressextend
InitiatedByextend
ServicePrincipalNameextend
ServicePrincipalIdextend
TargetResources_0_modifiedPropertiesextend
displayNameextend
newValueextend
InitiatingAccountNameextend
InitiatingAccountUPNSuffixextend
TargetRoleextend

TI Map URL Entity to Syslog Data

#
Severity
medium
Time window
14d
Group by
Id, ObservableValue, Url
Source
github.com/Azure/Azure-Sentinel

'This query identifies any URL indicators of compromise (IOCs) from threat intelligence (TI) by searching for matches in Syslog data.'

MITRE ATT&CK Coverage

TacticTechniques
Command & Control

Rule Body

id: 4de24a28-dcd0-4a0d-bf14-96d8483dc05a
name: TI Map URL Entity to Syslog Data
description: |
  'This query identifies any URL indicators of compromise (IOCs) from threat intelligence (TI) by searching for matches in Syslog data.'
severity: Medium
requiredDataConnectors:
  - connectorId: Syslog
    dataTypes:
      - Syslog
  - connectorId: ThreatIntelligence
    dataTypes:
      - ThreatIntelIndicators
  - connectorId: ThreatIntelligenceTaxii
    dataTypes:
      - ThreatIntelIndicators
  - connectorId: MicrosoftDefenderThreatIntelligence
    dataTypes:
      - ThreatIntelIndicators
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - CommandAndControl
relevantTechniques:
  - T1071
query: |
  let dt_lookBack = 1h;
  let ioc_lookBack = 14d;
  ThreatIntelIndicators
  // Picking up only IOC's that contain the entities we want
  //extract key part of kv pair
  | extend IndicatorType = replace(@"\[|\]|\""", "", tostring(split(ObservableKey, ":", 0)))
  | where IndicatorType == "url"
  | extend Url = ObservableValue
  | extend TrafficLightProtocolLevel = tostring(parse_json(AdditionalFields).TLPLevel)
  | where TimeGenerated >= ago(ioc_lookBack)
  | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id, ObservableValue
  | where IsActive and (ValidUntil > now() or isempty(ValidUntil))
     | project-reorder *, Tags, TrafficLightProtocolLevel, Url, Type
  // using innerunique to keep perf fast and result set low, we only need one match to indicate potential malicious activity that needs to be investigated
  | join kind=innerunique (
    Syslog
    | where TimeGenerated >= ago(dt_lookBack)
    // Extract URL from the Syslog message but only take messages that include URLs
    | extend Url = extract("(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)", 1,SyslogMessage)
    | extend Syslog_TimeGenerated = TimeGenerated
  ) on Url
  | where Syslog_TimeGenerated < ValidUntil
  | summarize Syslog_TimeGenerated  = arg_max(Syslog_TimeGenerated , *) by Id, Url
  | extend Description = tostring(parse_json(Data).description)
  | extend ActivityGroupNames = extract(@"ActivityGroup:(\S+)", 1, tostring(parse_json(Data).labels))
  | project timestamp = Syslog_TimeGenerated, Description, ActivityGroupNames, Id, Type, ValidUntil, Confidence, SyslogMessage, Computer, ProcessName, Url, HostIP
entityMappings:
  - entityType: Host
    fieldMappings:
      - identifier: HostName
        columnName: Computer
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: HostIP
  - entityType: URL
    fieldMappings:
      - identifier: Url
        columnName: Url
version: 1.2.8
kind: Scheduled

Stages and Predicates

Parameters

let dt_lookBack = 1h;
let ioc_lookBack = 14d;

Stage 1: source

ThreatIntelIndicators

Stage 2: extend

| extend IndicatorType = replace(@"\[|\]|\""", "", tostring(split(ObservableKey, ":", 0)))

Stage 3: where

| where IndicatorType == "url"

Stage 4: extend

| extend Url = ObservableValue

Stage 5: extend

| extend TrafficLightProtocolLevel = tostring(parse_json(AdditionalFields).TLPLevel)

Stage 6: where

| where TimeGenerated >= ago(ioc_lookBack)

Stage 7: summarize

| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id, ObservableValue

Stage 8: where

| where IsActive and (ValidUntil > now() or isempty(ValidUntil))

Stage 9: project-reorder

| project-reorder *, Tags, TrafficLightProtocolLevel, Url, Type

Stage 10: join

| join kind=innerunique (
  Syslog
  | where TimeGenerated >= ago(dt_lookBack)
  | extend Url = extract("(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)", 1,SyslogMessage)
  | extend Syslog_TimeGenerated = TimeGenerated
) on Url

Stage 11: where

where Syslog_TimeGenerated < ValidUntil

Stage 12: summarize

summarize Syslog_TimeGenerated by Id, Url

Stage 13: extend

extend Description

Stage 14: extend

extend ActivityGroupNames

Stage 15: project

project ActivityGroupNames, Computer, Confidence, Description, HostIP, Id, ProcessName, SyslogMessage, Type, Url, ValidUntil, timestamp

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
ActivityGroupNamesproject
Computerproject
Confidenceproject
Descriptionproject
HostIPproject
Idproject
ProcessNameproject
SyslogMessageproject
Typeproject
Urlproject
ValidUntilproject
timestampproject

Veeam ONE Backup Copy RPO

#

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
5m
Source
github.com/Azure/Azure-Sentinel

Detects Veeam ONE Backup Copy RPO violation alerts.

Rule Body

id: 7fb6d1b6-48e4-442b-ba4d-1b5fb5fa379b
name: Veeam ONE Backup Copy RPO
description: Detects Veeam ONE Backup Copy RPO violation alerts.
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 == 365
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 == 365

Indicators

These rows show field, operator, and value matches.

VMware SD-WAN Edge - Network Anomaly Detection - Potential Fragmentation Attack

#
Severity
low
Time window
1h
Source
github.com/Azure/Azure-Sentinel

The VMware SD-WAN Edge appliance received packets potentially part of an IP Fragmentation attack or indicating an MTU mismatch. An IP fragmentation attack is a cyberattack that exploits how IP packets are fragmented and reassembled. IP fragmentation is a process by which large IP packets are broken down into smaller packets to transmit them over networks with smaller Maximum Transmission Unit (MTU) sizes. Attackers can exploit IP fragmentation in various ways, for example, Denial-of-service attacks, address spoofing, or even information disclosure. This analytics rule analyzes Syslog streams; these alerts are not reported by default if Search API is used.

MITRE ATT&CK Coverage

Rule Body

id: ce207901-ed7b-49ae-ada7-033e1fbb1240
name: VMware SD-WAN Edge - Network Anomaly Detection - Potential Fragmentation Attack
version: 1.0.0
kind: Scheduled
description: |-
  The VMware SD-WAN Edge appliance received packets potentially part of an IP Fragmentation attack or indicating an MTU mismatch.

  An IP fragmentation attack is a cyberattack that exploits how IP packets are fragmented and reassembled. IP fragmentation is a process by which large IP packets are broken down into smaller packets to transmit them over networks with smaller Maximum Transmission Unit (MTU) sizes.

  Attackers can exploit IP fragmentation in various ways, for example, Denial-of-service attacks, address spoofing, or even information disclosure.

  This analytics rule analyzes Syslog streams; these alerts are not reported by default if Search API is used.
severity: Low
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
requiredDataConnectors:
  - connectorId: VMwareSDWAN
    dataTypes:
      - SDWAN
tactics:
- Impact
- DefenseEvasion
relevantTechniques:
- T1498
- T1599
query: |+
  Syslog
  | where SyslogMessage contains "VCF Drop"
  | where SyslogMessage contains "packet too big"
  | project-rename EdgeName=HostName
  | project-away Computer, HostIP, SourceSystem, Type
  | extend OverlaySegmentName = extract("SEGMENT_NAME=(.+) COUNT=", 1, SyslogMessage)
  | extend IpProtocol = extract("PROTO=(.+) SRC=", 1, SyslogMessage)
  | extend SrcIpAddress = extract("SRC=(.+) DST=", 1, SyslogMessage)
  | extend DstIpAddress = extract("DST=(.+) REASON=", 1, SyslogMessage)
  | extend EdgeFwAction = extract("ACTION=(.+) SEGMENT=", 1, SyslogMessage)
  | extend SyslogTag = extract("^(.+): ACTION=", 1, SyslogMessage)
  | extend pcktCount = extract("COUNT=([0-9]+)$", 1, SyslogMessage)
  | project
      TimeGenerated,
      EdgeFwAction,
      EdgeName,
      SrcIpAddress,
      IpProtocol,
      DstIpAddress,
      pcktCount,
      SyslogTag

suppressionEnabled: false
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: false
    lookbackDuration: 1h
    matchingMethod: AllEntities
    groupByEntities: []
    groupByAlertDetails: []
    groupByCustomDetails: []
eventGroupingSettings:
  aggregationKind: SingleAlert
customDetails:
  Edge_Name: EdgeName
entityMappings:
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: SrcIpAddress
suppressionDuration: 5h

Stages and Predicates

Stage 1: source

Syslog

Stage 2: where

| where SyslogMessage contains "VCF Drop"

Stage 3: where

| where SyslogMessage contains "packet too big"

Stage 4: project-rename

| project-rename EdgeName=HostName

Stage 5: project-away

| project-away Computer, HostIP, SourceSystem, Type

Stage 6: extend (7 consecutive steps)

| extend OverlaySegmentName = extract("SEGMENT_NAME=(.+) COUNT=", 1, SyslogMessage)
| extend IpProtocol = extract("PROTO=(.+) SRC=", 1, SyslogMessage)
| extend SrcIpAddress = extract("SRC=(.+) DST=", 1, SyslogMessage)
| extend DstIpAddress = extract("DST=(.+) REASON=", 1, SyslogMessage)
| extend EdgeFwAction = extract("ACTION=(.+) SEGMENT=", 1, SyslogMessage)
| extend SyslogTag = extract("^(.+): ACTION=", 1, SyslogMessage)
| extend pcktCount = extract("COUNT=([0-9]+)$", 1, SyslogMessage)

Stage 7: project

| project
    TimeGenerated,
    EdgeFwAction,
    EdgeName,
    SrcIpAddress,
    IpProtocol,
    DstIpAddress,
    pcktCount,
    SyslogTag

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
SyslogMessagecontains
  • VCF Drop
  • packet too big
field:"SyslogMessage" kind:contains

Output Fields

These fields are emitted when the rule matches.

FieldSource
DstIpAddressproject
EdgeFwActionproject
EdgeNameproject
IpProtocolproject
SrcIpAddressproject
SyslogTagproject
TimeGeneratedproject
pcktCountproject

Website blocked by ESET

#
Severity
low
Time window
5m
Source
github.com/Azure/Azure-Sentinel

'Create alert on websites blocked by ESET.'

MITRE ATT&CK Coverage

Rule Body

id: 7b84fc5b-9ffb-4e9b-945b-5d480e330b3f
name: Website blocked by ESET
description: |
  'Create alert on websites blocked by ESET.'
severity: Low
requiredDataConnectors:
  - connectorId: ESETPROTECT
    dataTypes:
      - ESETPROTECT
  - connectorId: SyslogAma
    datatypes:
      - Syslog
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Exfiltration
  - CommandAndControl
  - InitialAccess
relevantTechniques:
  - T1041
  - T1071
  - T1189
  - T1566
query: |
  ESETPROTECT
  | where EventType == 'FilteredWebsites_Event'
  | extend SrcUserName, FilePath, DvcHostname, DvcIpAddr
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: SrcUserName
  - entityType: Host
    fieldMappings:
      - identifier: FullName
        columnName: DvcHostname
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: DvcIpAddr
  - entityType: URL
    fieldMappings:
      - identifier: Url
        columnName: FilePath
version: 1.0.2
kind: Scheduled

Stages and Predicates

Stage 1: source

ESETPROTECT

Stage 2: where

| where EventType == 'FilteredWebsites_Event'

Stage 3: extend

| extend SrcUserName, FilePath, DvcHostname, DvcIpAddr

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
EventTypeeq
  • FilteredWebsites_Event
field:"EventType" kind:eq value:"FilteredWebsites_Event"

Output Fields

These fields are emitted when the rule matches.

FieldSource
DvcHostnameextend
DvcIpAddrextend
FilePathextend
SrcUserNameextend

XbowLowFindings

#

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
low
Time window
2h
Group by
AssetId, FindingId
Source
github.com/Azure/Azure-Sentinel

Creates an incident for each Low severity finding reported by XBOW that is currently in an open state. These findings represent minor security issues or best-practice violations that should be addressed as part of regular security maintenance. Each alert is deduplicated per finding so re-ingestion of the same finding does not produce duplicate incidents.

MITRE ATT&CK Coverage

TacticTechniques
DiscoveryNo specific technique

Rule Body

id: d2e4f1a8-7c9b-4356-8e0d-5a2b7c8e9f01
name: XbowLowFindings
description: |
  Creates an incident for each Low severity finding reported by XBOW that is currently
  in an open state. These findings represent minor security issues or best-practice
  violations that should be addressed as part of regular security maintenance. Each
  alert is deduplicated per finding so re-ingestion of the same finding does not
  produce duplicate incidents.
severity: Low
status: Available
requiredDataConnectors:
  - connectorId: XbowSecurityConnector
    dataTypes:
      - XbowFindings_CL
      - XbowAssets_CL
queryFrequency: 1h
queryPeriod: 2h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Discovery
relevantTechniques: []
query: |
  XbowFindings_CL
  | where TimeGenerated > ago(2h)
  | where tolower(Severity) == 'low'
  | where isempty(State) or tolower(State) == 'open'
  | summarize arg_max(TimeGenerated, *) by FindingId
  | join kind=leftouter (
      XbowAssets_CL
      | summarize arg_max(TimeGenerated, *) by AssetId
      | project AssetId, StartUrl
  ) on AssetId
  | project
      TimeGenerated,
      FindingId,
      FindingName,
      Severity,
      State,
      Summary,
      Impact,
      Mitigations,
      Recipe,
      AssetId,
      AssetName,
      OrganizationId,
      CreatedAt,
      StartUrl
eventGroupingSettings:
  aggregationKind: AlertPerResult
alertDetailsOverride:
  alertDisplayNameFormat: 'XBOW Low: {{FindingName}}'
  alertDescriptionFormat: 'Low severity finding on asset {{AssetName}} ({{AssetId}}). {{Summary}}'
customDetails:
  FindingID: FindingId
  FindingName: FindingName
  Severity: Severity
  State: State
  AssetID: AssetId
  AssetName: AssetName
  OrganizationID: OrganizationId
  CreatedAt: CreatedAt
  Mitigations: Mitigations
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: false
    lookbackDuration: 24h
    matchingMethod: Selected
    groupByCustomDetails:
      - FindingID
entityMappings:
  - entityType: URL
    fieldMappings:
      - identifier: Url
        columnName: StartUrl
version: 1.0.1
kind: Scheduled

Stages and Predicates

Stage 1: source

XbowFindings_CL

Stage 2: where

| where TimeGenerated > ago(2h)

Stage 3: where

| where tolower(Severity) == 'low'

Stage 4: where

| where isempty(State) or tolower(State) == 'open'

Stage 5: summarize

| summarize arg_max(TimeGenerated, *) by FindingId

Stage 6: join

| join kind=leftouter (
    XbowAssets_CL
    | summarize arg_max(TimeGenerated, *) by AssetId
    | project AssetId, StartUrl
) on AssetId

Stage 7: project

project AssetId, AssetName, CreatedAt, FindingId, FindingName, Impact, Mitigations, OrganizationId, Recipe, Severity, StartUrl, State, Summary, TimeGenerated

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
Severityeq
  • low transforms: tolower
field:"Severity" kind:eq value:"low"
Stateeq
  • open transforms: tolower
field:"State" kind:eq value:"open"
Stateis_null
  • (no value, null check)
field:"State" kind:is_null

Output Fields

These fields are emitted when the rule matches.

FieldSource
AssetIdproject
AssetNameproject
CreatedAtproject
FindingIdproject
FindingNameproject
Impactproject
Mitigationsproject
OrganizationIdproject
Recipeproject
Severityproject
StartUrlproject
Stateproject
Summaryproject
TimeGeneratedproject

Back to all Kusto rules