Detection rules › Kusto

Kusto rules: 1s

Alsid Golden Ticket

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

'Searches for Golden Ticket attacks'

MITRE ATT&CK Coverage

Rule Body

id: 21ab3f52-6d79-47e3-97f8-ad65f2cb29fb
name: Alsid Golden Ticket
description: |
    'Searches for Golden Ticket attacks'
severity: High
requiredDataConnectors:
  - connectorId: AlsidForAD
    dataTypes:
      - AlsidForADLog_CL
queryFrequency: 2h
queryPeriod: 2h
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
  - CredentialAccess
relevantTechniques:
  - T1558.001
query: |
    afad_parser
    | where MessageType == 2 and Codename == "Golden Ticket"
    | extend HostName = tostring(split(Host, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Host, '.'), 1, -1), '.'))
entityMappings:
  - entityType: Host
    fieldMappings:
      - identifier: HostName
        columnName: HostName
      - identifier: DnsDomain
        columnName: DnsDomain
version: 1.0.1
kind: Scheduled

Stages and Predicates

Stage 1: source

afad_parser

Stage 2: where

| where MessageType == 2 and Codename == "Golden Ticket"

Stage 3: extend

| extend HostName = tostring(split(Host, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Host, '.'), 1, -1), '.'))

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
Codenameeq
  • Golden Ticket corpus 3 (kusto 3)
field:"Codename" kind:eq value:"Golden Ticket"
MessageTypeeq
  • 2 corpus 21 (kusto 21)
field:"MessageType" kind:eq value:"2"

Output Fields

These fields are emitted when the rule matches.

FieldSource
DnsDomainextend
HostNameextend

Alsid Indicators of Exposures

#
Status
available
Severity
low
Time window
2h
Group by
Severity
Source
github.com/Azure/Azure-Sentinel

'Searches for triggered Indicators of Exposures'

MITRE ATT&CK Coverage

TacticTechniques
Credential Access

Rule Body

id: 154fde9f-ae00-4422-a8da-ef00b11da3fc
name: Alsid Indicators of Exposures
description: |
    'Searches for triggered Indicators of Exposures'
severity: Low
requiredDataConnectors:
  - connectorId: AlsidForAD
    dataTypes:
      - AlsidForADLog_CL
queryFrequency: 2h
queryPeriod: 2h
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
  - CredentialAccess
relevantTechniques:
  - T1110
query: |
    let SeverityTable=datatable(Severity:string,Level:int) [
    "low", 1,
    "medium", 2,
    "high", 3,
    "critical", 4
    ];
    afad_parser
    | where MessageType == 0
    | lookup kind=leftouter SeverityTable on Severity
    | order by Level
    | extend HostName = tostring(split(Host, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Host, '.'), 1, -1), '.'))
entityMappings:
  - entityType: Host
    fieldMappings:
      - identifier: HostName
        columnName: HostName
      - identifier: DnsDomain
        columnName: DnsDomain
version: 1.0.1
kind: Scheduled

Stages and Predicates

Let Binding: SeverityTable used in Stage 3

let SeverityTable = datatable(Severity:string,Level:int) [
"low", 1,
"medium", 2,
"high", 3,
"critical", 4
];

Stage 1: source

afad_parser

Stage 2: where

| where MessageType == 0

Stage 3: kusto:lookup

lookup kind=leftouter (SeverityTable) on Severity

Stage 4: sort

sort by Level

Stage 5: extend

extend DnsDomain, HostName

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
MessageTypeeq
  • 0 corpus 15 (kusto 15)
field:"MessageType" kind:eq value:"0"

Output Fields

These fields are emitted when the rule matches.

FieldSource
DnsDomainextend
HostNameextend

Box - File containing sensitive data

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

'Detects files which potentialy may contain sensitive data such as passwords, authentication tokens, secret keys.'

MITRE ATT&CK Coverage

Rule Body

id: 266746ae-5eaf-4068-a980-5d630f435c46
name: Box - File containing sensitive data
description: |
  'Detects files which potentialy may contain sensitive data such as passwords, authentication tokens, secret keys.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: BoxDataConnector
    dataTypes:
      - BoxEvents_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Exfiltration
relevantTechniques:
  - T1048
query: |
  BoxEvents
  | where SourceItemName =~ 'id_rsa' or SourceItemName contains 'password' or SourceItemName contains 'key' or SourceItemName contains '_key' or SourceItemName contains '.ssh' or SourceItemName endswith '.npmrc' or SourceItemName endswith '.muttrc' or SourceItemName contains 'config.json' or SourceItemName contains '.gitconfig' or SourceItemName endswith '.netrc' or SourceItemName endswith 'package.json' or SourceItemName endswith 'Gemfile' or SourceItemName endswith 'bower.json' or SourceItemName endswith 'config.gypi' or SourceItemName endswith 'travis.yml' or SourceFileName =~ 'id_rsa' or SourceFileName contains 'password' or SourceFileName contains 'key' or SourceFileName contains '_key' or SourceFileName contains '.ssh' or SourceFileName endswith '.npmrc' or SourceFileName endswith '.muttrc' or SourceFileName contains 'config.json' or SourceFileName contains '.gitconfig' or SourceFileName endswith '.netrc' or SourceFileName endswith 'package.json' or SourceFileName endswith 'Gemfile' or SourceFileName contains 'bower.json' or SourceFileName contains 'config.gypi' or SourceFileName contains 'travis.yml'
  | extend AccountCustomEntity = SrcUserName
  | extend IPCustomEntity = SrcIpAddr
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: AccountCustomEntity
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: IPCustomEntity
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

BoxEvents

Stage 2: where

| where SourceItemName =~ 'id_rsa' or SourceItemName contains 'password' or SourceItemName contains 'key' or SourceItemName contains '_key' or SourceItemName contains '.ssh' or SourceItemName endswith '.npmrc' or SourceItemName endswith '.muttrc' or SourceItemName contains 'config.json' or SourceItemName contains '.gitconfig' or SourceItemName endswith '.netrc' or SourceItemName endswith 'package.json' or SourceItemName endswith 'Gemfile' or SourceItemName endswith 'bower.json' or SourceItemName endswith 'config.gypi' or SourceItemName endswith 'travis.yml' or SourceFileName =~ 'id_rsa' or SourceFileName contains 'password' or SourceFileName contains 'key' or SourceFileName contains '_key' or SourceFileName contains '.ssh' or SourceFileName endswith '.npmrc' or SourceFileName endswith '.muttrc' or SourceFileName contains 'config.json' or SourceFileName contains '.gitconfig' or SourceFileName endswith '.netrc' or SourceFileName endswith 'package.json' or SourceFileName endswith 'Gemfile' or SourceFileName contains 'bower.json' or SourceFileName contains 'config.gypi' or SourceFileName contains 'travis.yml'

Stage 3: extend

| extend AccountCustomEntity = SrcUserName

Stage 4: extend

| extend IPCustomEntity = SrcIpAddr

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
SourceFileNamecontains
  • .gitconfig
  • .ssh
  • _key
  • bower.json
  • config.gypi
  • config.json
  • key
  • password
  • travis.yml
field:"SourceFileName" kind:contains
SourceFileNameends_with
  • .muttrc
  • .netrc
  • .npmrc
  • Gemfile
  • package.json
field:"SourceFileName" kind:ends_with
SourceFileNameeq
  • id_rsa
field:"SourceFileName" kind:eq value:"id_rsa"
SourceItemNamecontains
  • .gitconfig
  • .ssh
  • _key
  • config.json
  • key
  • password
field:"SourceItemName" kind:contains
SourceItemNameends_with
  • .muttrc
  • .netrc
  • .npmrc
  • Gemfile
  • bower.json
  • config.gypi
  • package.json
  • travis.yml
field:"SourceItemName" kind:ends_with
SourceItemNameeq
  • id_rsa
field:"SourceItemName" kind:eq value:"id_rsa"

Output Fields

These fields are emitted when the rule matches.

FieldSource
AccountCustomEntityextend
IPCustomEntityextend

Cognni Incidents for Medium Sensitivity HR 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
medium
Time window
5h
Source
github.com/Azure/Azure-Sentinel

'Display incidents in which medium sensitivity HR information was placed at risk by user sharing.'

MITRE ATT&CK Coverage

TacticTechniques
Collection

Rule Body

id: 75ff4f7d-0564-4a55-8b25-a75be951cde3
name: Cognni Incidents for Medium Sensitivity HR Information
description: |
  'Display incidents in which medium sensitivity HR information was placed at risk by user sharing.'
severity: Medium
requiredDataConnectors:
  - connectorId: CognniSentinelDataConnector
    dataTypes:
      - CognniIncidents_CL
queryFrequency: 5h
queryPeriod: 5h
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
  - Collection
relevantTechniques:
  - T1530
query: |
  let mediumRisk = 2;
  let hr = 'HR Information';
  CognniIncidents_CL 
  | where Severity == mediumRisk
  | where informationType_s == hr
  | 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 mediumRisk = 2;
let hr = 'HR Information';

Stage 1: source

CognniIncidents_CL

Stage 2: where

| where Severity == mediumRisk

Stage 3: where

| where informationType_s == hr

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

Flare lookalike domain results

#

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
medium
Time window
1h
Source
github.com/Azure/Azure-Sentinel

'This query searches for lookalike domains and SSL certificate registrations.'

MITRE ATT&CK Coverage

TacticTechniques
Reconnaissance

Rule Body

id: 8e5ae0d6-7f2d-475e-ada3-ed33441deeba
name: Flare lookalike domain results
description: |
    'This query searches for lookalike domains and SSL certificate registrations.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: Flare
    dataTypes:
      - FireworkV2_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Reconnaissance
relevantTechniques:
  - T1593
query: |
  FireworkV2_CL
  | where notempty(uid) and RiskScore >= 3
  | extend index_name = split(uid, "/")[0]
  | where index_name == "domain"
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

FireworkV2_CL

Stage 2: where

| where notempty(uid) and RiskScore >= 3

Stage 3: extend

| extend index_name = split(uid, "/")[0]

Stage 4: where

| where index_name == "domain"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
RiskScorege
  • 3 transforms: number
field:"RiskScore" kind:ge value:"3"
index_nameeq
  • domain
field:"index_name" kind:eq value:"domain"
uidis_not_null
  • (no value, null check)
field:"uid" kind:is_not_null

Output Fields

These fields are emitted when the rule matches.

FieldSource
index_nameextend

Guardian- BII Detection Policy Violation Detection

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

'This alert creates an incident when BII Detection Policy Violation detected from the Guardian.'

Rule Body

id: e7493b80-88d0-44fb-b11d-40a0467cc497
name: Guardian- BII Detection Policy Violation Detection
description: |
  'This alert creates an incident when BII Detection Policy Violation detected from the Guardian.'
severity: High
status: Available
requiredDataConnectors:
  - connectorId: BoschAIShield
    dataTypes:
      - Guardian
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics: []
relevantTechniques: []
query: |
  Guardian
  | where PolicyViolatedControlFeature =~ 'BII Detection'
  | where Severity =~ 'High'
entityMappings:
  - entityType: Host
    fieldMappings:
      - identifier: HostName
        columnName: HostName
      - identifier: NTDomain
        columnName: NTDomain
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SourceIP
eventGroupingSettings:
  aggregationKind: SingleAlert
alertDetailsOverride:
  alertDisplayNameFormat: Guardian- BII Detection Policy Violation detection
  alertDescriptionFormat: |
    This query detects BII Detection Policy Violation detected from the Guardian generated at {{TimeGenerated}}.\n\nPlease check the source for more information and investigate further.
  alertTacticsColumnName: null
  alertSeverityColumnName: Severity
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

Guardian

Stage 2: where

| where PolicyViolatedControlFeature =~ 'BII Detection'

Stage 3: where

| where Severity =~ 'High'

Indicators

These rows show field, operator, and value matches.

HoneyLabs TI Map IP Entity to SigninLogs

#
Severity
medium
Time window
14d
Group by
$left.TI_ipEntity, $right.CS_ipEntity, CS_ipEntity, Id
Source
github.com/Azure/Azure-Sentinel

Identifies sign-ins (interactive and non-interactive) from IP addresses that HoneyLabs honeypot telemetry has observed running exploit or loader commands. A hit means credential access is being attempted from infrastructure with recent, evidenced malicious activity. Indicator Confidence reflects how much evidence HoneyLabs holds (90 = 100+ observed attacks, 60 = a single sighting); raise the threshold in the query to trade coverage for precision.

MITRE ATT&CK Coverage

TacticTechniques
Initial Access
Credential Access

Telemetry Coverage

Rule Body

id: a573396f-06ed-4139-bccc-e0f88a2cf625
name: HoneyLabs TI Map IP Entity to SigninLogs
version: 1.0.0
kind: Scheduled
description: |
  'Identifies sign-ins (interactive and non-interactive) from IP addresses that HoneyLabs honeypot telemetry has observed running exploit or loader commands. A hit means credential access is being attempted from infrastructure with recent, evidenced malicious activity. Indicator Confidence reflects how much evidence HoneyLabs holds (90 = 100+ observed attacks, 60 = a single sighting); raise the threshold in the query to trade coverage for precision.'
severity: Medium
requiredDataConnectors:
  - connectorId: ThreatIntelligenceTaxii
    dataTypes:
      - ThreatIntelligenceIndicator
  - connectorId: AzureActiveDirectory
    dataTypes:
      - SigninLogs
  - connectorId: AzureActiveDirectory
    dataTypes:
      - AADNonInteractiveUserSignInLogs
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - InitialAccess
  - CredentialAccess
relevantTechniques:
  - T1190
  - T1110
query: |
  let dt_lookBack = 1h;
  let ioc_lookBack = 14d;
  let HoneyLabs_IPs = ThreatIntelIndicators
    | where TimeGenerated >= ago(ioc_lookBack)
    | where IsActive == true and ValidUntil > now()
    | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by Id
    | where SourceSystem startswith 'HoneyLabs'
    | where ObservableKey == 'ipv4-addr:value'
    | extend TI_ipEntity = tostring(ObservableValue),
             HoneyLabsConfidence = Confidence,
             HoneyLabsLabels = tostring(Data.labels),
             IndicatorDescription = tostring(Data.description),
             HoneyLabsReport = strcat('https://honeylabs.net/lookup/', tostring(ObservableValue));
  let aadSignin = SigninLogs | where TimeGenerated >= ago(dt_lookBack)
    | project TimeGenerated, IPAddress, UserPrincipalName, ResultType, AppDisplayName, Location;
  let aadNonInt = AADNonInteractiveUserSignInLogs | where TimeGenerated >= ago(dt_lookBack)
    | project TimeGenerated, IPAddress, UserPrincipalName, ResultType, AppDisplayName, Location;
  HoneyLabs_IPs
  | join kind=innerunique (union isfuzzy=true aadSignin, aadNonInt
      | extend CS_ipEntity = IPAddress
      | extend Signin_TimeGenerated = TimeGenerated
  ) on $left.TI_ipEntity == $right.CS_ipEntity
  | where Signin_TimeGenerated < ValidUntil
  | summarize Signin_TimeGenerated = arg_max(Signin_TimeGenerated, *) by Id, CS_ipEntity
  | project Signin_TimeGenerated, IndicatorDescription, Id, ValidUntil, HoneyLabsConfidence,
    HoneyLabsLabels, HoneyLabsReport, TI_ipEntity, CS_ipEntity, UserPrincipalName, ResultType,
    AppDisplayName, Location
  | extend timestamp = Signin_TimeGenerated
entityMappings:
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: CS_ipEntity
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: UserPrincipalName

Stages and Predicates

Parameters

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

let HoneyLabs_IPs is inlined into the numbered stages below.

Let Binding: aadSignin

let aadSignin = SigninLogs | where TimeGenerated >= ago(dt_lookBack)
  | project TimeGenerated, IPAddress, UserPrincipalName, ResultType, AppDisplayName, Location;

Let Binding: aadNonInt

let aadNonInt = AADNonInteractiveUserSignInLogs | where TimeGenerated >= ago(dt_lookBack)
  | project TimeGenerated, IPAddress, UserPrincipalName, ResultType, AppDisplayName, Location;

Stages 1 to 7 define let HoneyLabs_IPs as the rule's main pipeline source. Stages 8 to 12 use it.

Stage 1: source

ThreatIntelIndicators

Stage 2: where

| where TimeGenerated >= ago(ioc_lookBack)

Stage 3: where

| where IsActive == true and ValidUntil > now()

Stage 4: summarize

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

Stage 5: where

| where SourceSystem startswith 'HoneyLabs'

Stage 6: where

| where ObservableKey == 'ipv4-addr:value'

Stage 7: extend

| extend TI_ipEntity = tostring(ObservableValue),
           HoneyLabsConfidence = Confidence,
           HoneyLabsLabels = tostring(Data.labels),
           IndicatorDescription = tostring(Data.description),
           HoneyLabsReport = strcat('https://honeylabs.net/lookup/', tostring(ObservableValue))

Stage 8: join

join kind=innerunique (...) on $left.TI_ipEntity, $right.CS_ipEntity

Stage 9: where

where Signin_TimeGenerated < ValidUntil

Stage 10: summarize

summarize Signin_TimeGenerated by Id, CS_ipEntity

Stage 11: project

project AppDisplayName, CS_ipEntity, HoneyLabsConfidence, HoneyLabsLabels, HoneyLabsReport, Id, IndicatorDescription, Location, ResultType, Signin_TimeGenerated, TI_ipEntity, UserPrincipalName, ValidUntil

Stage 12: extend

extend timestamp

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
IsActiveeq
  • true corpus 12 (kusto 12)
field:"IsActive" kind:eq value:"true"
ObservableKeyeq
  • ipv4-addr:value corpus 10 (kusto 10)
field:"ObservableKey" kind:eq value:"ipv4-addr:value"
SourceSystemstarts_with
  • HoneyLabs corpus 4 (kusto 4)
field:"SourceSystem" kind:starts_with value:"HoneyLabs"

Output Fields

These fields are emitted when the rule matches.

FieldSource
AppDisplayNameproject
CS_ipEntityproject
HoneyLabsConfidenceproject
HoneyLabsLabelsproject
HoneyLabsReportproject
Idproject
IndicatorDescriptionproject
Locationproject
ResultTypeproject
Signin_TimeGeneratedproject
TI_ipEntityproject
UserPrincipalNameproject
ValidUntilproject
timestampextend

Hunt MDE with GSA events

#
Group by
$left.InitiatingProcessFileName, $left.Protocol, $left.RemotePort, $left.RemoteUrl, $right.DestinationFqdn, $right.DestinationPort, $right.InitiatingProcessName, $right.TransportProtocol, DeviceId
Author
Robbe Van den Daele
Source
github.com/HybridBrothers/Hunting-Queries-Detection-Rules

This rule correlates the Microsoft Defender for Endpoint DeviceNetworkEvents table with the Global Secure Access NetworkAccessTraffic table. By doing this, you can enrich the MDE events which contains detailed process information with the GSA events that contains detailed HTTP header information and more.

References

Telemetry Coverage

Rule Body

let gsa_events = NetworkAccessTraffic
    // Join DeviceInfo to get MDE DeviceID
    | join kind=inner ( 
        DeviceInfo
        | distinct DeviceId, AadDeviceId
    ) on $left.DeviceId == $right.AadDeviceId
    // Remove Entra Device ID from GSA logs
    | project-away DeviceId
    // Rename MDE Device ID to DeviceId column
    | project-rename DeviceId = DeviceId1;
// Get all MDE network events
DeviceNetworkEvents
// Get HTTP details if HTTP connection is logged
| extend HttpStatus = toint(todynamic(AdditionalFields).status_code),
    BytesIn = toint(todynamic(AdditionalFields).response_body_len),
    BytesOut = toint(todynamic(AdditionalFields).request_body_len),
    HttpMethod = tostring(todynamic(AdditionalFields).method),
    UrlHostname = tostring(todynamic(AdditionalFields).host),
    UrlPath = tostring(todynamic(AdditionalFields).uri),
    UserAgent = tostring(todynamic(AdditionalFields).user_agent),
    HttpVersion = tostring(todynamic(AdditionalFields).version)
// Join GSA logs
| join kind=inner gsa_events on 
    DeviceId,
    $left.RemoteUrl == $right.DestinationFqdn,
    $left.RemotePort == $right.DestinationPort,
    $left.Protocol == $right.TransportProtocol,
    $left.InitiatingProcessFileName == $right.InitiatingProcessName
| project-rename TimeGeneratedGsa = TimeGenerated1, TimestampMde = Timestamp
| project-away Type, TenantId, TimeGenerated, TenantId1, Type1, DeviceId1, AadDeviceId

let gsa_events = NetworkAccessTraffic
    // Join DeviceInfo to get MDE DeviceID
    | join kind=inner ( 
        DeviceInfo
        | distinct DeviceId, AadDeviceId
    ) on $left.DeviceId == $right.AadDeviceId
    // Remove Entra Device ID from GSA logs
    | project-away DeviceId
    // Rename MDE Device ID to DeviceId column
    | project-rename DeviceId = DeviceId1;
// Get all MDE network events
DeviceNetworkEvents
// Get HTTP details if HTTP connection is logged
| extend HttpStatus = toint(todynamic(AdditionalFields).status_code),
    BytesIn = toint(todynamic(AdditionalFields).response_body_len),
    BytesOut = toint(todynamic(AdditionalFields).request_body_len),
    HttpMethod = tostring(todynamic(AdditionalFields).method),
    UrlHostname = tostring(todynamic(AdditionalFields).host),
    UrlPath = tostring(todynamic(AdditionalFields).uri),
    UserAgent = tostring(todynamic(AdditionalFields).user_agent),
    HttpVersion = tostring(todynamic(AdditionalFields).version)
// Join GSA logs
| join kind=inner gsa_events on 
    DeviceId,
    $left.RemoteUrl == $right.DestinationFqdn,
    $left.RemotePort == $right.DestinationPort,
    $left.Protocol == $right.TransportProtocol,
    $left.InitiatingProcessFileName == $right.InitiatingProcessName
| project-rename TimeGeneratedGsa = TimeGenerated2, TimestampMde = TimeGenerated
| project-away Type, TenantId, TimeGenerated, TenantId1, Type1, DeviceId1, AadDeviceId

Stages and Predicates

Let Binding: gsa_events used in Stages 1, 4

let gsa_events = NetworkAccessTraffic
    | join kind=inner ( 
        DeviceInfo
        | distinct DeviceId, AadDeviceId
    ) on $left.DeviceId == $right.AadDeviceId
    | project-away DeviceId
    | project-rename DeviceId = DeviceId1;

Stage 1: source

let gsa_events

Stage 2: source

DeviceNetworkEvents

Stage 3: extend

extend BytesIn, BytesOut, HttpMethod, HttpStatus, HttpVersion, UrlHostname, UrlPath, UserAgent

Stage 4: join

join kind=inner (gsa_events) on DeviceId, $left.RemoteUrl, $right.DestinationFqdn, $left.RemotePort, $right.DestinationPort, $left.Protocol, $right.TransportProtocol, $left.InitiatingProcessFileName, $right.InitiatingProcessName

Stage 5: project-rename

project-rename

Stage 6: project-away

project-away AadDeviceId, DeviceId1, TenantId, TenantId1, TimeGenerated, Type, Type1

Output Fields

These fields are emitted when the rule matches.

FieldSource
BytesInextend
BytesOutextend
HttpMethodextend
HttpStatusextend
HttpVersionextend
UrlHostnameextend
UrlPathextend
UserAgentextend
TimeGeneratedGsaproject-rename
TimestampMdeproject-rename

Microsoft COVID-19 file hash indicator matches

#
Status
available
Severity
medium
Time window
14d
Group by
$left.FileHashValue, $right.FileHash, FileHashValue
Source
github.com/Azure/Azure-Sentinel

'Identifies a match in CommonSecurityLog Event data from any FileHash published in the Microsoft COVID-19 Threat Intel Feed - as described at https://www.microsoft.com/security/blog/2020/05/14/open-sourcing-covid-threat-intelligence/'

MITRE ATT&CK Coverage

Rule Body

id: 2be4ef67-a93f-4d8a-981a-88158cb73abd
name: Microsoft COVID-19 file hash indicator matches
description: |
  'Identifies a match in CommonSecurityLog Event data from any FileHash published in the Microsoft COVID-19 Threat Intel Feed - as described at https://www.microsoft.com/security/blog/2020/05/14/open-sourcing-covid-threat-intelligence/'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: CefAma
    dataTypes:
      - CommonSecurityLog
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Execution
relevantTechniques:
  - T1204.002
query: |
  let dt_lookBack = 1h;
  let covidIndicators = (externaldata(TimeGenerated:datetime, FileHashValue:string, FileHashType: string, TlpLevel: string, Product: string, ThreatType: string, Description: string )
  [@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/Microsoft.Covid19.Indicators.csv"] with (format="csv"));
  let fileHashIndicators = covidIndicators
  | where isnotempty(FileHashValue);
  // Handle matches against both lower case and uppercase versions of the hash:
  (fileHashIndicators | extend FileHashValue = tolower(FileHashValue)
  | union (fileHashIndicators | extend FileHashValue = toupper(FileHashValue)))
  // 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 (
     CommonSecurityLog | where TimeGenerated >= ago(dt_lookBack)
     | where isnotempty(FileHash)
     | extend CommonSecurityLog_TimeGenerated = TimeGenerated
     )
  on $left.FileHashValue == $right.FileHash
  | summarize CommonSecurityLog_TimeGenerated = arg_max(CommonSecurityLog_TimeGenerated, *) by FileHashValue
  | project CommonSecurityLog_TimeGenerated, FileHashValue, FileHashType, Description, ThreatType,
  SourceIP, SourcePort, DestinationIP, DestinationPort, SourceUserID, SourceUserName, DeviceName, DeviceAction,
  RequestURL, DestinationUserName, DestinationUserID, ApplicationProtocol, Activity
  | extend AccountName = tostring(split(SourceUserName, "@")[0]), AccountUPNSuffix = tostring(split(SourceUserName, "@")[1])
  | extend HostName = tostring(split(DeviceName, ".")[0]), DomainIndex = toint(indexof(DeviceName, '.'))
  | extend HostNameDomain = iff(DomainIndex != -1, substring(DeviceName, DomainIndex + 1), DeviceName)
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: SourceUserName
      - identifier: Name
        columnName: AccountName
      - identifier: UPNSuffix
        columnName: AccountUPNSuffix
  - entityType: Host
    fieldMappings:
      - identifier: FullName
        columnName: DeviceName
      - identifier: HostName
        columnName: HostName
      - identifier: DnsDomain
        columnName: HostNameDomain
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SourceIP
  - entityType: FileHash
    fieldMappings:
      - identifier: Value
        columnName: FileHashValue
      - identifier: Algorithm
        columnName: FileHashType
version: 1.3.6
kind: Scheduled

Stages and Predicates

Parameters

let dt_lookBack = 1h;

let fileHashIndicators is inlined into the numbered stages below.

Let Binding: covidIndicators

let covidIndicators = (externaldata(TimeGenerated:datetime, FileHashValue:string, FileHashType: string, TlpLevel: string, Product: string, ThreatType: string, Description: string )
[@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/Microsoft.Covid19.Indicators.csv"] with (format="csv"));

Stages 1 to 2 define let fileHashIndicators as the rule's main pipeline source. Stages 3 to 11 combine it with further branches.

Stage 1: source

externaldata(...)

Stage 2: where

where isnotempty(FileHashValue)

Stage 3: extend

extend FileHashValue

Stage 4: union

union of 1 branches

Stage 5: source

externaldata(...)

Stage 6: where

where isnotempty(FileHashValue)

Stage 7: extend

extend FileHashValue

Stage 8: join

| join kind=innerunique (
   CommonSecurityLog | where TimeGenerated >= ago(dt_lookBack)
   | where isnotempty(FileHash)
   | extend CommonSecurityLog_TimeGenerated = TimeGenerated
   )
on $left.FileHashValue == $right.FileHash

Stage 9: summarize

summarize CommonSecurityLog_TimeGenerated by FileHashValue

Stage 10: project

project Activity, ApplicationProtocol, CommonSecurityLog_TimeGenerated, Description, DestinationIP, DestinationPort, DestinationUserID, DestinationUserName, DeviceAction, DeviceName, FileHashType, FileHashValue, RequestURL, SourceIP, SourcePort, SourceUserID, SourceUserName, ThreatType

Stage 11: extend (3 consecutive steps)

extend AccountName, AccountUPNSuffix, DomainIndex, HostName, HostNameDomain

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
FileHashis_not_null
  • (no value, null check)
field:"FileHash" kind:is_not_null
FileHashValueis_not_null
  • (no value, null check)
field:"FileHashValue" kind:is_not_null

Output Fields

These fields are emitted when the rule matches.

FieldSource
Activityproject
ApplicationProtocolproject
CommonSecurityLog_TimeGeneratedproject
Descriptionproject
DestinationIPproject
DestinationPortproject
DestinationUserIDproject
DestinationUserNameproject
DeviceActionproject
DeviceNameproject
FileHashTypeproject
FileHashValueproject
RequestURLproject
SourceIPproject
SourcePortproject
SourceUserIDproject
SourceUserNameproject
ThreatTypeproject
AccountNameextend
AccountUPNSuffixextend
DomainIndexextend
HostNameextend
HostNameDomainextend

PROD (TM013.1) - OU - Block Inheritance was Enabled on an OU

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

Blocking Inheritance on an OU will deny Tier Model GPOs from applying.

MITRE ATT&CK Coverage

Telemetry Coverage

Rule Body

id: 17371300-904a-4af5-9550-cf57ee727bb7
name: 'PROD (TM013.1) - OU - Block Inheritance was Enabled on an OU'
description: |
  Blocking Inheritance on an OU will deny Tier Model GPOs from applying.
severity: High
requiredDataConnectors:
  - connectorId: SecurityEvents
    dataTypes:
      - SecurityEvent
  - connectorId: WindowsSecurityEvents
    dataTypes:
      - SecurityEvent
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
  - DefenseEvasion
relevantTechniques:
  - T1484.001
query: |
  SecurityEvent
  | where EventID == 5136
      and Activity has "modified"
      and EventData has '"ObjectClass">organizationalUnit'
      and EventData has '<Data Name="AttributeLDAPDisplayName">gPOptions</Data>'
  | extend ObjectName = extract("<Data Name=\"ObjectDN\">((?i)OU=[^,]+(,(?i)OU=[^,]+)*),(?i)DC=", 1, EventData)
  | extend AttributeLDAP = extract("<Data Name=\"AttributeLDAPDisplayName\">([^<]+)</Data>", 1, EventData)
  | extend AttributeValue = extract("<Data Name=\"AttributeValue\">([0-9]+)</Data>", 1, EventData)
  | extend ActivityType = case(
      AttributeValue == "1", "Block Inheritance Enabled",
      AttributeValue == "0", "Block Inheritance Disabled",
      "Block Inheritance Modified")
  | extend ObjectClass = extract("<Data Name=\"ObjectClass\">([^<]+)</Data>", 1, EventData)
  | extend Domain = extract("([^.]+\\.[^.]+)$", 1, Computer)
  | project TimeGenerated
      , ObjectName
      , ObjectClass
      , ActivityType
      , AttributeLDAP
      , 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
  ObjectClass: ObjectClass
  ActivityType: ActivityType
  AttributeLDAP: AttributeLDAP
  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: '(TM013.1) An OU was configured for Block Inheritance and is overwriting Tier Model GPOs'
  alertDescriptionFormat: 'Block Inheritance was configured by {{Account}}'
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

SecurityEvent

Stage 2: where

| where EventID == 5136
    and Activity has "modified"
    and EventData has '"ObjectClass">organizationalUnit'
    and EventData has '<Data Name="AttributeLDAPDisplayName">gPOptions</Data>'

Stage 3: extend (6 consecutive steps)

| extend ObjectName = extract("<Data Name=\"ObjectDN\">((?i)OU=[^,]+(,(?i)OU=[^,]+)*),(?i)DC=", 1, EventData)
| extend AttributeLDAP = extract("<Data Name=\"AttributeLDAPDisplayName\">([^<]+)</Data>", 1, EventData)
| extend AttributeValue = extract("<Data Name=\"AttributeValue\">([0-9]+)</Data>", 1, EventData)
| extend ActivityType = case(
    AttributeValue == "1", "Block Inheritance Enabled",
    AttributeValue == "0", "Block Inheritance Disabled",
    "Block Inheritance Modified")
| extend ObjectClass = extract("<Data Name=\"ObjectClass\">([^<]+)</Data>", 1, EventData)
| extend Domain = extract("([^.]+\\.[^.]+)$", 1, Computer)

Stage 4: project

| project TimeGenerated
    , ObjectName
    , ObjectClass
    , ActivityType
    , AttributeLDAP
    , Account
    , Domain
    , Computer
    , Channel
    , EventID
    , EventData

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
Activitymatch
  • modified transforms: term corpus 10 (kusto 10)
field:"Activity" kind:match value:"modified"
EventDatamatch
  • "ObjectClass">organizationalUnit transforms: term corpus 5 (kusto 5)
  • <Data Name="AttributeLDAPDisplayName">gPOptions</Data> transforms: term
field:"EventData" kind:match
EventIDeq
  • 5136 corpus 20 (kusto 18, elastic 2)
field:"EventID" kind:eq value:"5136"

Output Fields

These fields are emitted when the rule matches.

FieldSource
Accountproject
ActivityTypeproject
AttributeLDAPproject
Channelproject
Computerproject
Domainproject
EventDataproject
EventIDproject
ObjectClassproject
ObjectNameproject
TimeGeneratedproject

Radiflow - New Activity Detected

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

'Generates an incident when a new asset or MAC is detected either by Radiflow's iSID.'

MITRE ATT&CK Coverage

TacticTechniques
Initial Access
Initial Access

Rule Body

id: 8177ecff-30a1-4d4f-9a82-7fbb69019504
name: Radiflow - New Activity Detected
description: |
  'Generates an incident when a new asset or MAC is detected either by Radiflow's iSID.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: RadiflowIsid
    dataTypes:
      - RadiflowEvent
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1133
- T0848
query: |
  RadiflowEvent
  | where DeviceProduct =~ 'iSID'
  | where EventClassID in (1, 2, 3, 155)
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: false
    lookbackDuration: 1h
    matchingMethod: AllEntities
    groupByEntities: []
    groupByAlertDetails: []
    groupByCustomDetails: []
eventGroupingSettings:
  aggregationKind: AlertPerResult
alertDetailsOverride:
  alertDisplayNameFormat: 'New Activity Detected (MAC: {{SourceMACAddress}} - IP: {{SourceIP}})'
  alertDescriptionFormat: A previously undetected asset, link or entity has been detected in the network. Please check whether the activity is legitimate.
  alertSeverityColumnName: EventSeverity
  alertDynamicProperties: []
suppressionEnabled: false
suppressionDuration: 5h
customDetails:
  SourceMAC: SourceMACAddress
  SourceType: SourceType
  SourceVendor: SourceVendor
  SourceVLAN: SourceVLAN
  DestinationMAC: DestinationMACAddress
  DestinationType: DestinationType
  DestinationVendor: DestinationVendor
  Port: Port
  Protocol: Protocol
  SourceHostName: SourceHostName
  SourceIP: SourceIP
  DestinationHostName: DestinationHostName
  DestinationIP: DestinationIP
entityMappings:
- entityType: Host
  fieldMappings:
  - identifier: HostName
    columnName: SourceHostName
  - identifier: NetBiosName
    columnName: SourceHostName
- entityType: Host
  fieldMappings:
  - identifier: HostName
    columnName: DestinationHostName
  - identifier: NetBiosName
    columnName: DestinationHostName
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: SourceIP
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: DestinationIP
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

RadiflowEvent

Stage 2: where

| where DeviceProduct =~ 'iSID'

Stage 3: where

| where EventClassID in (1, 2, 3, 155)

Indicators

These rows show field, operator, and value matches.

Starting or Stopping HealthService to Avoid Detection

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

This query detects events where an actor is stopping or starting HealthService to disable telemetry collection/detection from the agent. The query requires a SACL to audit for access request to the service.

MITRE ATT&CK Coverage

TacticTechniques
Defense Impairment

Telemetry Coverage

Rule Body

id: 2bc7b4ae-eeaa-4538-ba15-ef298ec1ffae
name: Starting or Stopping HealthService to Avoid Detection
description: |
   'This query detects events where an actor is stopping or starting HealthService to disable telemetry collection/detection from the agent.
    The query requires a SACL to audit for access request to the service.'
severity: Medium
requiredDataConnectors:
  - connectorId: SecurityEvents
    dataTypes:
      - SecurityEvent
  - connectorId: WindowsSecurityEvents
    dataTypes:
      - SecurityEvent
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
  - DefenseEvasion
relevantTechniques:
  - T1562.001
tags:
  - Solorigate
  - NOBELIUM
query: |
  SecurityEvent
  | where EventID == 4656
  | extend EventData = parse_xml(EventData).EventData.Data
  | mv-expand bagexpansion=array EventData
  | evaluate bag_unpack(EventData)
  | extend Key = tostring(column_ifexists('@Name', "")), Value = column_ifexists('#text', "")
  | evaluate pivot(Key, any(Value), TimeGenerated, TargetAccount, Computer, EventSourceName, Channel, Task, Level, EventID, Activity, TargetLogonId, SourceComputerId, EventOriginId, Type, _ResourceId, TenantId, SourceSystem, ManagementGroupName, IpAddress, Account)
  | extend ObjectServer = column_ifexists('ObjectServer', ""), ObjectType = column_ifexists('ObjectType', ""), ObjectName = column_ifexists('ObjectName', "")
  | where isnotempty(ObjectServer) and isnotempty(ObjectType) and isnotempty(ObjectName)
  | where ObjectServer =~ "SC Manager" and ObjectType =~ "SERVICE OBJECT" and ObjectName =~ "HealthService"
  // Comment out the join below if the SACL only audits users that are part of the Network logon users, i.e. with user/group target pointing to "NU."
  | join kind=leftouter (
    SecurityEvent
    | where EventID == 4624
  ) on TargetLogonId
  | project TimeGenerated, Computer, Account, TargetAccount, IpAddress,TargetLogonId, ObjectServer, ObjectType, ObjectName
  | extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
  | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
  | extend AccountName = tostring(split(TargetAccount, @'\')[1]), AccountNTDomain = tostring(split(TargetAccount, @'\')[0])
  | extend timestamp = TimeGenerated
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: TargetAccount
      - identifier: Name
        columnName: AccountName
      - identifier: NTDomain
        columnName: AccountNTDomain
  - entityType: Host
    fieldMappings:
      - identifier: FullName
        columnName: Computer
      - identifier: HostName
        columnName: HostName
      - identifier: DnsDomain
        columnName: HostNameDomain
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: IpAddress
version: 1.0.2
kind: Scheduled

Stages and Predicates

Stage 1: source

SecurityEvent

Stage 2: where

| where EventID == 4656

Stage 3: extend

| extend EventData = parse_xml(EventData).EventData.Data

Stage 4: mv-expand

| mv-expand bagexpansion=array EventData

Stage 5: evaluate

| evaluate bag_unpack(EventData)

Stage 6: extend

| extend Key = tostring(column_ifexists('@Name', "")), Value = column_ifexists('#text', "")

Stage 7: evaluate

| evaluate pivot(Key, any(Value), TimeGenerated, TargetAccount, Computer, EventSourceName, Channel, Task, Level, EventID, Activity, TargetLogonId, SourceComputerId, EventOriginId, Type, _ResourceId, TenantId, SourceSystem, ManagementGroupName, IpAddress, Account)

Stage 8: extend

| extend ObjectServer = column_ifexists('ObjectServer', ""), ObjectType = column_ifexists('ObjectType', ""), ObjectName = column_ifexists('ObjectName', "")

Stage 9: where

| where isnotempty(ObjectServer) and isnotempty(ObjectType) and isnotempty(ObjectName)

Stage 10: where

| where ObjectServer =~ "SC Manager" and ObjectType =~ "SERVICE OBJECT" and ObjectName =~ "HealthService"

Stage 11: join

| join kind=leftouter (
  SecurityEvent
  | where EventID == 4624
) on TargetLogonId

Stage 12: project

project Account, Computer, IpAddress, ObjectName, ObjectServer, ObjectType, TargetAccount, TargetLogonId, TimeGenerated

Stage 13: extend (4 consecutive steps)

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

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
EventIDeq
  • 4624 corpus 8 (chronicle 4, kusto 3, elastic 1)
  • 4656 corpus 4 (kusto 4)
field:"EventID" kind:eq
ObjectNameeq
  • HealthService
field:"ObjectName" kind:eq value:"HealthService"
ObjectNameis_not_null
  • (no value, null check)
field:"ObjectName" kind:is_not_null
ObjectServereq
  • SC Manager
field:"ObjectServer" kind:eq value:"SC Manager"
ObjectServeris_not_null
  • (no value, null check)
field:"ObjectServer" kind:is_not_null
ObjectTypeeq
  • SERVICE OBJECT
field:"ObjectType" kind:eq value:"SERVICE OBJECT"
ObjectTypeis_not_null
  • (no value, null check)
field:"ObjectType" kind:is_not_null

Output Fields

These fields are emitted when the rule matches.

FieldSource
Accountproject
Computerproject
IpAddressproject
ObjectNameproject
ObjectServerproject
ObjectTypeproject
TargetAccountproject
TargetLogonIdproject
TimeGeneratedproject
DomainIndexextend
HostNameextend
HostNameDomainextend
AccountNTDomainextend
AccountNameextend
timestampextend

Tenant Replica Stopped

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

Detects when a tenant replica stops.

Rule Body

id: ef029652-d004-44e9-a70a-48dd71818aaa
name: Tenant Replica Stopped
description: Detects when a tenant replica stops.
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 == 26900\n| project\n    Date\
  \ = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),\n    DataSource = original_host,\n\
  \    EventId = instanceId,\n    [\"User Name\"] = user,\n  MessageDetails = Description,\n\
  \   Severity = SeverityDescription"
version: 1.0.1
kind: Scheduled
customDetails:
  Date: Date
  VbrHostName: DataSource
  EventId: EventId
  MessageDetails: MessageDetails
  Severity: Severity

Stages and Predicates

Stage 1: source

Veeam_GetSecurityEvents

Stage 2: where

| where instanceId == 26900

Stage 3: project

| project
    Date = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),
    DataSource = original_host,
    EventId = instanceId,
    ["User Name"] = user,
  MessageDetails = Description,
   Severity = SeverityDescription

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
DataSourceproject
Dateproject
EventIdproject
MessageDetailsproject
Severityproject
User Nameproject

Veeam ONE Application with No Recent Data Backup Sessions

#

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 applications with no recent backup sessions.

Rule Body

id: 73e36985-d65d-4852-b3cc-5e8f4b64b39c
name: Veeam ONE Application with No Recent Data Backup Sessions
description: Detects applications with no recent backup sessions.
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 == 391
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 == 391

Indicators

These rows show field, operator, and value matches.

VMware ESXi - Multiple VMs stopped

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

'Detects when multiple VMs ware stopped by user.'

MITRE ATT&CK Coverage

TacticTechniques
Impact

Rule Body

id: 5fe1af14-cd40-48ff-b581-3a12a1f90785
name: VMware ESXi - Multiple VMs stopped
description: |
  'Detects when multiple VMs ware stopped by user.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: SyslogAma
    datatypes:
      - Syslog
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Impact
relevantTechniques:
  - T1529
query: |
  let threshold = 5;
  VMwareESXi
  | where SyslogMessage has ('VmPoweredOffEvent')
  | extend SrcUsername = extract(@'\[info\]\s+\[(.*?)\]', 1, SyslogMessage)
  | extend DstHostname = extract(@'\[\d+\]\s+\[(.*?)\s+on', 1, SyslogMessage)
  | summarize st_vm = make_set(DstHostname,200) by SrcUsername, bin(TimeGenerated, 5m)
  | where array_length(st_vm) > threshold
  | extend hostname = iff(array_length(st_vm) > 0, st_vm[0], "")
  | extend NTDomain = tostring(split(hostname, '\\', 0)[0]), Name = tostring(split(SrcUsername, '\\', 1)[0]), HostName = tostring(split(hostname, '.', 0)[0]), DnsDomain = tostring(split(SrcUsername, '\\', 1)[0])
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: Name
      - identifier: DnsDomain
        columnName: DnsDomain
  - entityType: Host
    fieldMappings:
      - identifier: HostName
        columnName: HostName
      - identifier: NTDomain
        columnName: NTDomain
version: 1.0.3
kind: Scheduled

Stages and Predicates

Parameters

let threshold = 5;

Stage 1: source

VMwareESXi

Stage 2: where

| where SyslogMessage has ('VmPoweredOffEvent')

Stage 3: extend

| extend SrcUsername = extract(@'\[info\]\s+\[(.*?)\]', 1, SyslogMessage)

Stage 4: extend

| extend DstHostname = extract(@'\[\d+\]\s+\[(.*?)\s+on', 1, SyslogMessage)

Stage 5: summarize

| summarize st_vm = make_set(DstHostname,200) by SrcUsername, bin(TimeGenerated, 5m)

Stage 6: where

| where array_length(st_vm) > threshold

Stage 7: extend

| extend hostname = iff(array_length(st_vm) > 0, st_vm[0], "")
hostname =
ifst_vm > 0st_vm[0]
else""

Stage 8: extend

| extend NTDomain = tostring(split(hostname, '\\', 0)[0]), Name = tostring(split(SrcUsername, '\\', 1)[0]), HostName = tostring(split(hostname, '.', 0)[0]), DnsDomain = tostring(split(SrcUsername, '\\', 1)[0])

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
SyslogMessagematch
  • VmPoweredOffEvent transforms: term
field:"SyslogMessage" kind:match value:"VmPoweredOffEvent"

Output Fields

These fields are emitted when the rule matches.

FieldSource
SrcUsernamesummarize
st_vmsummarize
hostnameextend
DnsDomainextend
HostNameextend
NTDomainextend
Nameextend

Back to all Kusto rules