Detection rules › Kusto

Kusto rules: 1r

AWSCloudTrail - Creation of Access Key for IAM User

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

Detects creation of a new IAM access key on an existing user account, which could be used to establish persistence. This action should be validated by the AWS account administrator. Reference: https://stratus-red-team.cloud/attack-techniques/AWS/aws.persistence.iam-backdoor-user/

MITRE ATT&CK Coverage

Telemetry Coverage

Rules Detecting the Same Action

These rules filter on the same operation.

Rule Body

id: 9a6554e6-63d9-4f94-9b32-64d1d40628f2
name: AWSCloudTrail - Creation of Access Key for IAM User
description: |
  Detects creation of a new IAM access key on an existing user account, which could be used to establish persistence. This action should be validated by the AWS account administrator. Reference: https://stratus-red-team.cloud/attack-techniques/AWS/aws.persistence.iam-backdoor-user/
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: AWS
    dataTypes:
      - AWSCloudTrail
queryFrequency: 15m
queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Persistence
relevantTechniques:
  - T1098.001
query: |
    AWSCloudTrail
    | where EventName == "CreateAccessKey" 
    | project-away SourceSystem,Category,Type,TenantId,EventVersion,SessionIssuerAccountId
    | extend UserName = substring(UserIdentityPrincipalid, indexof_regex(UserIdentityPrincipalid, ":") + 1)
    | extend Name = split(UserName,'@')[0],UpnSuffix = split(UserName,'@')[1]
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: Name
      - identifier: UPNSuffix
        columnName: UpnSuffix
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SourceIpAddress
customDetails:
  EventName: EventName
  AWSRegion: AWSRegion
  UserAgent: UserAgent
alertDetailsOverride:
  alertDisplayNameFormat: IAM access key created by {{Name}} in {{AWSRegion}}
  alertDescriptionFormat: User {{Name}} (principal {{UserIdentityPrincipalid}}) created a new IAM access key in region {{AWSRegion}}.
version: 1.0.2
kind: Scheduled

Stages and Predicates

Stage 1: source

AWSCloudTrail

Stage 2: where

| where EventName == "CreateAccessKey"

Stage 3: project-away

| project-away SourceSystem,Category,Type,TenantId,EventVersion,SessionIssuerAccountId

Stage 4: extend

| extend UserName = substring(UserIdentityPrincipalid, indexof_regex(UserIdentityPrincipalid, ":") + 1)

Stage 5: extend

| extend Name = split(UserName,'@')[0],UpnSuffix = split(UserName,'@')[1]

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
EventNameeq
  • CreateAccessKey corpus 3 (panther 2, kusto 1)
field:"aws::eventName" kind:eq value:"CreateAccessKey"

Output Fields

These fields are emitted when the rule matches.

FieldSource
UserNameextend
Nameextend
UpnSuffixextend

Dataverse - SharePoint document management site added or updated

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

Identifies modifications of SharePoint document management integration. Document management allows storage of data located externally to Dataverse. Combine this analytics rule with the MSBizApps-Add-SharePointSite-To-Watchlist Playbook to automatically update the Dataverse-SharePointSites watchlist. This watchlist can be used to correlate events between Dataverse and SharePoint when using the Office 365 data connector.

MITRE ATT&CK Coverage

Telemetry Coverage

Rule Body

id: c4c3510a-0ee0-4561-9835-47882ffa7f46
kind: Scheduled
name: Dataverse - SharePoint document management site added or updated
description: Identifies modifications of SharePoint document management integration.
  Document management allows storage of data located externally to Dataverse. Combine
  this analytics rule with the MSBizApps-Add-SharePointSite-To-Watchlist Playbook
  to automatically update the Dataverse-SharePointSites watchlist. This watchlist
  can be used to correlate events between Dataverse and SharePoint when using the
  Office 365 data connector.
severity: Informational
status: Available
requiredDataConnectors:
  - connectorId: Dataverse
    dataTypes:
      - DataverseActivity
queryFrequency: 1h
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Exfiltration
relevantTechniques:
  - T1567
  - T1537
query: |
  let query_frequency = 1h;
  DataverseActivity
  | where TimeGenerated >= ago(query_frequency)
  | where Message in ("Create", "Update") and EntityName == "sharepointsite"
  | mv-expand Fields
  | where Fields.Name == "absoluteurl"
  | extend
      SharePointAppId = int(20892),
      CloudAppId = int(32780),
      AccountName = tostring(split(UserId, '@')[0]),
      UPNSuffix = tostring(split(UserId, '@')[1]),
      SharePointUrl = tostring(Fields.Value)
  | project
      TimeGenerated,
      UserId,
      ClientIp,
      Message,
      SharePointUrl,
      InstanceUrl,
      CloudAppId,
      SharePointAppId,
      AccountName,
      UPNSuffix
eventGroupingSettings:
  aggregationKind: AlertPerResult
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: AccountName
      - identifier: UPNSuffix
        columnName: UPNSuffix
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: ClientIp
  - entityType: CloudApplication
    fieldMappings:
      - identifier: AppId
        columnName: CloudAppId
      - identifier: InstanceName
        columnName: InstanceUrl
  - entityType: CloudApplication
    fieldMappings:
      - identifier: AppId
        columnName: SharePointAppId
      - identifier: InstanceName
        columnName: SharePointUrl
alertDetailsOverride:
  alertDisplayNameFormat: 'Dataverse - Document management enabled or modified in
    {{{InstanceUrl}} '
  alertDescriptionFormat: '{{UserId}} made changes to document management in {{{InstanceUrl}}.
    Sharepoint site {{{SharePointUrl}} was added.'
version: 3.2.0

Stages and Predicates

Parameters

let query_frequency = 1h;

Stage 1: source

DataverseActivity

Stage 2: where

| where TimeGenerated >= ago(query_frequency)

Stage 3: where

| where Message in ("Create", "Update") and EntityName == "sharepointsite"

Stage 4: mv-expand

| mv-expand Fields

Stage 5: where

| where Fields.Name == "absoluteurl"

Stage 6: extend

| extend
    SharePointAppId = int(20892),
    CloudAppId = int(32780),
    AccountName = tostring(split(UserId, '@')[0]),
    UPNSuffix = tostring(split(UserId, '@')[1]),
    SharePointUrl = tostring(Fields.Value)

Stage 7: project

| project
    TimeGenerated,
    UserId,
    ClientIp,
    Message,
    SharePointUrl,
    InstanceUrl,
    CloudAppId,
    SharePointAppId,
    AccountName,
    UPNSuffix

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
AccountNameproject
ClientIpproject
CloudAppIdproject
InstanceUrlproject
Messageproject
SharePointAppIdproject
SharePointUrlproject
TimeGeneratedproject
UPNSuffixproject
UserIdproject

Encryption Password Changed

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

Detects when an encryption password is updated in Veeam Backup & Replication.

Rule Body

id: 58fcb721-35ec-4ea2-9f29-c99acde676b8
name: Encryption Password Changed
description: Detects when an encryption password is updated in Veeam Backup & Replication.
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 == 31700\n| extend Hint = extract(\"\
  Hint=\\\"([^\\\"]*)\\\"\", 1, SyslogMessage)\n| project\n    Date = format_datetime(TimeGenerated,\
  \ 'dd.MM.yyyy HH:mm'),\n    DataSource = original_host,\n    EventId = instanceId,\n\
  \    [\"User Name\"] = user,\n    [\"Hint\"] = Hint,\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 == 31700

Stage 3: extend

| extend Hint = extract("Hint=\"([^\"]*)\"", 1, SyslogMessage)

Stage 4: project

| project
    Date = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),
    DataSource = original_host,
    EventId = instanceId,
    ["User Name"] = user,
    ["Hint"] = Hint,
    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
Hintproject
MessageDetailsproject
Severityproject
User Nameproject

GitLab - Local Auth - No MFA

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

'This query checks GitLab Audit Logs to see if a user authenticated without MFA. Ot might mean that MFA was disabled for the GitLab server or that an external authentication provider was bypassed. This rule focuses on 'admin' privileges but the parameter can be adapted to also include all users.'

MITRE ATT&CK Coverage

TacticTechniques
Credential Access

Rule Body

id: e0b45487-5c79-482d-8ac0-695de8c031af
name: GitLab - Local Auth - No MFA 
description: |
  'This query checks GitLab Audit Logs to see if a user authenticated without MFA. Ot might mean that MFA was disabled for the GitLab server or that an external authentication provider was bypassed. This rule focuses on 'admin' privileges but the parameter can be adapted to also include all users.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: SyslogAma
    dataTypes: 
      - Syslog
queryFrequency: 1h
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - CredentialAccess
relevantTechniques:
  - T1110
query: |
  let isAdmin = true;
  GitLabAudit
  | where AuthenticationType == "standard" and ((isAdmin and TargetDetails contains "Administrator") or (isAdmin==false));
entityMappings:
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: IPAddress
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: AuthorUserName
version: 1.0.1
kind: Scheduled

Stages and Predicates

Parameters

let isAdmin = true;

Stage 1: source

GitLabAudit

Stage 2: where

| where AuthenticationType == "standard" and ((isAdmin and TargetDetails contains "Administrator") or (isAdmin==false));

Indicators

These rows show field, operator, and value matches.

Guardian- URL Reachability Policy Violation Detection

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

'This alert creates an incident when URL Reachability Policy Violation detected from the Guardian.'

Rule Body

id: 93a56919-105a-4ffe-9a8c-4ef6d0b101ac
name: Guardian- URL Reachability Policy Violation Detection
description: |
  'This alert creates an incident when URL Reachability Policy Violation detected from the Guardian.'
severity: Informational
status: Available
requiredDataConnectors:
  - connectorId: BoschAIShield
    dataTypes:
      - Guardian
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics: []
relevantTechniques: []
query: |
  Guardian
  | where PolicyViolatedControlFeature =~ 'URL Reachability'
  | where Severity =~ 'Informational'
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- URL Reachability Policy Violation detection
  alertDescriptionFormat: |
    This query detects URL Reachability 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 =~ 'URL Reachability'

Stage 3: where

| where Severity =~ 'Informational'

Indicators

These rows show field, operator, and value matches.

M2131_LogRetentionLessThan1Year

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

'This alert is designed to monitor log retention within the Maturity Model for Event Log Management (M-21-31) standard. The alert triggers when a log analytics workspace in active storage is configured for less than 1 year.'

MITRE ATT&CK Coverage

TacticTechniques
Discovery

Rule Body

id: 8178a514-1270-4e31-a1d9-aaafeb40122f
name: M2131_LogRetentionLessThan1Year
description: |
  'This alert is designed to monitor log retention within the Maturity Model for Event Log Management (M-21-31) standard. The alert triggers when a log analytics workspace in active storage is configured for less than 1 year.'
severity: Medium
status: Available
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Discovery
relevantTechniques:
  - T1082
query: |
  SecurityRecommendation
  | summarize arg_max(TimeGenerated, *) by RecommendationDisplayName, AssessedResourceId
  | where RecommendationDisplayName == "Activity log should be retained for at least one year"
  | summarize Failed = countif(RecommendationState == "Unhealthy"), Passed = countif(RecommendationState == "Healthy"), Total = countif(RecommendationState == "Healthy" or RecommendationState == "Unhealthy") by RecommendationDisplayName, AssessedResourceId
  | extend PassedControls = (Passed/todouble(Total))*100
  | extend RemediationLink = strcat('https://portal.azure.com/#blade/Microsoft_Azure_Security/SecurityMenuBlade/22')
  | project RecommendationDisplayName, AssessedResourceId, Total, PassedControls, Passed, Failed, RemediationLink, LastObserved=now()
  | where Failed > 0
  | sort by Failed desc
  | extend URLCustomEntity = RemediationLink, ResourceId = AssessedResourceId
entityMappings:
  - entityType: URL
    fieldMappings:
      - identifier: Url
        columnName: URLCustomEntity
  - entityType: AzureResource
    fieldMappings:
      - identifier: ResourceId
        columnName: AssessedResourceId
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

SecurityRecommendation

Stage 2: summarize

| summarize arg_max(TimeGenerated, *) by RecommendationDisplayName, AssessedResourceId

Stage 3: where

| where RecommendationDisplayName == "Activity log should be retained for at least one year"

Stage 4: summarize

| summarize Failed = countif(RecommendationState == "Unhealthy"), Passed = countif(RecommendationState == "Healthy"), Total = countif(RecommendationState == "Healthy" or RecommendationState == "Unhealthy") by RecommendationDisplayName, AssessedResourceId

Stage 5: extend

| extend PassedControls = (Passed/todouble(Total))*100

Stage 6: extend

| extend RemediationLink = strcat('https://portal.azure.com/#blade/Microsoft_Azure_Security/SecurityMenuBlade/22')

Stage 7: project

| project RecommendationDisplayName, AssessedResourceId, Total, PassedControls, Passed, Failed, RemediationLink, LastObserved=now()

Stage 8: where

| where Failed > 0

Stage 9: sort

| sort by Failed desc

Stage 10: extend

| extend URLCustomEntity = RemediationLink, ResourceId = AssessedResourceId

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
AssessedResourceIdproject
Failedproject
LastObservedproject
Passedproject
PassedControlsproject
RecommendationDisplayNameproject
RemediationLinkproject
Totalproject
ResourceIdextend
URLCustomEntityextend

OracleDBAudit - Unusual user activity on multiple tables

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

'Detects when user queries many tables in short period of time.'

MITRE ATT&CK Coverage

TacticTechniques
Collection

Rule Body

id: 75024e1c-26e7-4e73-821d-95e5decdd8db
name: OracleDBAudit - Unusual user activity on multiple tables 
description: |
  'Detects when user queries many tables in short period of time.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: SyslogAma
    datatypes:
      - Syslog
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Collection
relevantTechniques:
  - T1119
query: |
  let tbl_threshold = 10;
  OracleDatabaseAuditEvent
  | where isnotempty(DstUserName)
  | where DbAction =~ 'SELECT'
  | extend TableName = replace(@'[,\(\)]', '', extract(@'(?i)SELECT(.*?)FROM\s(.*?)\s', 2, Action))
  | where isnotempty(TableName)
  | where TableName !~ 'SELECT'
  | summarize tbl_count = dcount(TableName) by DstUserName, bucket = bin(TimeGenerated, 5m)
  | where tbl_count > tbl_threshold
  | extend AccountCustomEntity = DstUserName
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: AccountCustomEntity
version: 1.0.2
kind: Scheduled

Stages and Predicates

Parameters

let tbl_threshold = 10;

Stage 1: source

OracleDatabaseAuditEvent

Stage 2: where

| where isnotempty(DstUserName)

Stage 3: where

| where DbAction =~ 'SELECT'

Stage 4: extend

| extend TableName = replace(@'[,\(\)]', '', extract(@'(?i)SELECT(.*?)FROM\s(.*?)\s', 2, Action))

Stage 5: where

| where isnotempty(TableName)

Stage 6: where

| where TableName !~ 'SELECT'

Stage 7: summarize

| summarize tbl_count = dcount(TableName) by DstUserName, bucket = bin(TimeGenerated, 5m)

Stage 8: where

| where tbl_count > tbl_threshold

Stage 9: extend

| extend AccountCustomEntity = DstUserName

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
DstUserNamesummarize
bucketsummarize
tbl_countsummarize
AccountCustomEntityextend

Palo Alto Prisma Cloud - High risk score alert

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

'Detects alerts with high risk score value.'

MITRE ATT&CK Coverage

TacticTechniques
Initial Access

Rule Body

id: 617b02d8-0f47-4f3c-afed-1926a45e7b28
name: Palo Alto Prisma Cloud - High risk score alert
description: |
  'Detects alerts with high risk score value.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: PaloAltoPrismaCloud
    dataTypes:
      - PaloAltoPrismaCloud
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - InitialAccess
relevantTechniques:
  - T1133
query: |
  PaloAltoPrismaCloud
  | where Reason =~ 'NEW_ALERT'
  | where Status =~ 'open'
  | extend r_score = 0.85 * toint(RiskDetailRiskScoreMaxScore)
  | extend i_RiskDetailRiskScoreScore = toint(RiskDetailRiskScoreScore)
  | where i_RiskDetailRiskScoreScore > r_score
  | extend AccountCustomEntity = UserName
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: AccountCustomEntity
version: 1.0.1
kind: Scheduled

Stages and Predicates

Stage 1: source

PaloAltoPrismaCloud

Stage 2: where

| where Reason =~ 'NEW_ALERT'

Stage 3: where

| where Status =~ 'open'

Stage 4: extend

| extend r_score = 0.85 * toint(RiskDetailRiskScoreMaxScore)

Stage 5: extend

| extend i_RiskDetailRiskScoreScore = toint(RiskDetailRiskScoreScore)

Stage 6: where

| where i_RiskDetailRiskScoreScore > r_score

Stage 7: extend

| extend AccountCustomEntity = UserName

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
r_scoreextend
i_RiskDetailRiskScoreScoreextend
AccountCustomEntityextend

Palo Alto Prisma Cloud - Network ACLs Inbound rule to allow All Traffic

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

'Detects Network ACLs with Inbound rule to allow All Traffic.'

MITRE ATT&CK Coverage

TacticTechniques
Initial Access

Rule Body

id: 6098b34a-1e6b-440a-9e3b-fb4d5944ade1
name: Palo Alto Prisma Cloud - Network ACLs Inbound rule to allow All Traffic
description: |
  'Detects Network ACLs with Inbound rule to allow All Traffic.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: PaloAltoPrismaCloud
    dataTypes:
      - PaloAltoPrismaCloud
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - InitialAccess
relevantTechniques:
  - T1133
query: |
  PaloAltoPrismaCloud
  | where Reason =~ 'NEW_ALERT'
  | where Status =~ 'open'
  | where AlertMessage has 'Network ACLs with Inbound rule to allow All Traffic'
  | extend AccountCustomEntity = UserName
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: AccountCustomEntity
version: 1.0.1
kind: Scheduled

Stages and Predicates

Stage 1: source

PaloAltoPrismaCloud

Stage 2: where

| where Reason =~ 'NEW_ALERT'

Stage 3: where

| where Status =~ 'open'

Stage 4: where

| where AlertMessage has 'Network ACLs with Inbound rule to allow All Traffic'

Stage 5: extend

| extend AccountCustomEntity = UserName

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
AccountCustomEntityextend

Pathlock TDnR - Payment Request Changes

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

Detects changes to payment requests in SAP, forwarded by Pathlock Threat Detection and Response. Unauthorized modifications to payment requests may indicate financial fraud, duplicate payment schemes, or manipulation of treasury processes.

MITRE ATT&CK Coverage

TacticTechniques
Impact

Rule Body

id: 2a3b4c5d-6e7f-4a0b-8c1d-2e3f4a5b6c14
name: Pathlock TDnR - Payment Request Changes
kind: Scheduled
description: >-
  Detects changes to payment requests in SAP, forwarded by Pathlock Threat Detection and Response.
  Unauthorized modifications to payment requests may indicate financial fraud, duplicate payment
  schemes, or manipulation of treasury processes.
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: Pathlock_TDnR
    dataTypes:
      - Pathlock_TDnR_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Impact
relevantTechniques:
  - T1565
query: |
  Pathlock_TDnR_CL
  | where DataSource == "CHANGEDOC_PAYRQ"
  | project TimeGenerated, Sysid, DataSource, Eventid, Instance, Hostname, Bname,
            Tcode, Report, Area, Subid, SrcIp, DestIp, AffectedUser, LogLine,
            MsgType, MsgId, MsgNo, MessageV1, MessageV2, MessageV3, MessageV4, CentralTs
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: Bname
  - entityType: Host
    fieldMappings:
      - identifier: HostName
        columnName: Hostname
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SrcIp
eventGroupingSettings:
  aggregationKind: SingleAlert
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: false
    lookbackDuration: 5h
    matchingMethod: AnyAlert
    groupByEntities: []
    groupByAlertDetails: []
    groupByCustomDetails: []
suppressionDuration: 5h
suppressionEnabled: false
version: 1.0.0

Stages and Predicates

Stage 1: source

Pathlock_TDnR_CL

Stage 2: where

| where DataSource == "CHANGEDOC_PAYRQ"

Stage 3: project

| project TimeGenerated, Sysid, DataSource, Eventid, Instance, Hostname, Bname,
          Tcode, Report, Area, Subid, SrcIp, DestIp, AffectedUser, LogLine,
          MsgType, MsgId, MsgNo, MessageV1, MessageV2, MessageV3, MessageV4, CentralTs

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
AffectedUserproject
Areaproject
Bnameproject
CentralTsproject
DataSourceproject
DestIpproject
Eventidproject
Hostnameproject
Instanceproject
LogLineproject
MessageV1project
MessageV2project
MessageV3project
MessageV4project
MsgIdproject
MsgNoproject
MsgTypeproject
Reportproject
SrcIpproject
Subidproject
Sysidproject
Tcodeproject
TimeGeneratedproject

Stale last password change

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

'This query searches for stale last password change'

MITRE ATT&CK Coverage

TacticTechniques
Initial Access

Rule Body

id: 645A8724-5C7E-4A1F-81CB-C33AFF1439EB
name: Stale last password change
description: |
  'This query searches for stale last password change'
severity: Low
status: Available
requiredDataConnectors:
  - connectorId: SenservaPro
    dataTypes:
      - SenservaPro_CL
queryFrequency: 6h
queryPeriod: 6h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - InitialAccess
relevantTechniques:
  - T1566
query: |
  SenservaPro_CL
  | where ControlName_s == 'UserStaleLastPasswordChange'
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: ControlName_s
      - identifier: AadTenantId
        columnName: TenantId
      - identifier: DisplayName
        columnName: TenantDisplayName_s 
  - entityType: SecurityGroup
    fieldMappings:
      - identifier: DistinguishedName
        columnName: Group_s
  - entityType: AzureResource
    fieldMappings:
      - identifier: ResourceId
        columnName: SourceSystem 
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

SenservaPro_CL

Stage 2: where

| where ControlName_s == 'UserStaleLastPasswordChange'

Indicators

These rows show field, operator, and value matches.

Tenable.ad DCSync

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

'Searches for DCSync attacks.'

MITRE ATT&CK Coverage

TacticTechniques
Credential Access

Rule Body

id: 0c8d4de3-adb9-4161-a863-aa1e2c8bd959
name: Tenable.ad DCSync
description: |
    'Searches for DCSync attacks.'
severity: High
requiredDataConnectors:
  - connectorId: Tenable.ad
    dataTypes:
      - Tenable_ad_CL
queryFrequency: 2h
queryPeriod: 2h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - CredentialAccess
relevantTechniques:
  - T1003.006
query: |
  // For the query to work properly, make sure you have imported the afad_parser.kql parser into the workspace
  // Retrieve the parser here: https://raw.githubusercontent.com/tenable/Azure-Sentinel/Tenable.ad-connector/Solutions/TenableAD/Parsers/afad_parser.kql
  // Then, create the Kusto Function with alias afad_parser
  afad_parser
    | where MessageType == 2 and Codename == "DCSync"
    | 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 == "DCSync"

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
  • DCSync corpus 3 (kusto 3)
field:"Codename" kind:eq value:"DCSync"
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

TI Map URL Entity to EmailUrlInfo

#
Severity
medium
Time window
14d
Group by
$left.DomainName, $right.UrlDomain, IndicatorId, NetworkMessageId, 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 EmailUrlInfo.

MITRE ATT&CK Coverage

TacticTechniques
Command & Control

Telemetry Coverage

Rule Body

id: a0038239-72f4-4f7b-90ff-37f89f7881e0
name: TI Map URL Entity to EmailUrlInfo
description: |
  'This query identifies any URL indicators of compromise (IOCs) from threat intelligence (TI) by searching for matches in EmailUrlInfo.'
severity: Medium
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
      - EmailUrlInfo
  - connectorId: ThreatIntelligence
    dataTypes:
      - ThreatIntelligenceIndicator
  - connectorId: ThreatIntelligenceTaxii
    dataTypes:
      - ThreatIntelligenceIndicator
  - connectorId: MicrosoftDefenderThreatIntelligence
    dataTypes:
      - ThreatIntelligenceIndicator
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - CommandAndControl
relevantTechniques:
  - T1071
query: |
  let dt_lookBack = 1h;
  let ioc_lookBack = 14d;
  let EmailUrlInfo_ = materialize(EmailUrlInfo
      | where isnotempty(Url)
      | where TimeGenerated >= ago(dt_lookBack)
      | extend Url = tolower(Url)
      | extend EmailUrlInfo_TimeGenerated = TimeGenerated);
  let EmailUrls = EmailUrlInfo_ | distinct Url | summarize make_list(Url);
  let EmailUrlDomains = EmailUrlInfo_ | distinct UrlDomain | summarize make_list(UrlDomain);
  let EmailEvents_ = materialize(EmailEvents
      | where TimeGenerated >= ago(dt_lookBack));
  let TI = materialize(ThreatIntelligenceIndicator
      | where TimeGenerated >= ago(ioc_lookBack)
      | where (isnotempty(Url) or isnotempty(DomainName)) 
      | where tolower(Url) in (EmailUrls) or tolower(DomainName) in (EmailUrlDomains)
      | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
      | where Active == true and ExpirationDateTime > now());
  (union
      (TI | join kind=innerunique (EmailUrlInfo_) on Url),
      (TI | join kind=innerunique (EmailUrlInfo_) on $left.DomainName == $right.UrlDomain))
  | where EmailUrlInfo_TimeGenerated < ExpirationDateTime
  | summarize EmailUrlInfo_TimeGenerated = arg_max(EmailUrlInfo_TimeGenerated, *) by IndicatorId, Url
  | project EmailUrlInfo_TimeGenerated, Description, ActivityGroupNames, IndicatorId, ThreatType, ExpirationDateTime, ConfidenceScore, Url, UrlDomain, UrlLocation, NetworkMessageId
  | extend timestamp = EmailUrlInfo_TimeGenerated
  | join kind=inner (EmailEvents_) on NetworkMessageId
  | where DeliveryAction !has "Blocked"
  | extend Name = tostring(split(RecipientEmailAddress, '@', 0)[0]), UPNSuffix = tostring(split(RecipientEmailAddress, '@', 1)[0])
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: RecipientEmailAddress
      - identifier: Name
        columnName: Name
      - identifier: UPNSuffix
        columnName: UPNSuffix
  - entityType: URL
    fieldMappings:
      - identifier: Url
        columnName: Url
version: 1.0.2
kind: Scheduled

Stages and Predicates

Parameters

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

Let Binding: EmailUrlInfo_

let EmailUrlInfo_ = materialize(EmailUrlInfo
    | where isnotempty(Url)
    | where TimeGenerated >= ago(dt_lookBack)
    | extend Url = tolower(Url)
    | extend EmailUrlInfo_TimeGenerated = TimeGenerated);

Let Binding: EmailUrls

let EmailUrls = EmailUrlInfo_ | distinct Url | summarize make_list(Url);

Let Binding: EmailUrlDomains

let EmailUrlDomains = EmailUrlInfo_ | distinct UrlDomain | summarize make_list(UrlDomain);

Let Binding: EmailEvents_

let EmailEvents_ = materialize(EmailEvents
    | where TimeGenerated >= ago(dt_lookBack));

Union (2 Sources)

Each leg below queries one source; the rule matches if any leg does. Sources: TI, TI

Leg 1: TI

TI | join kind=innerunique (EmailUrlInfo_) on Url

Leg 2: TI

TI | join kind=innerunique (EmailUrlInfo_) on $left.DomainName == $right.UrlDomain

Applied to the Combined Result

| where EmailUrlInfo_TimeGenerated < ExpirationDateTime
| summarize EmailUrlInfo_TimeGenerated = arg_max(EmailUrlInfo_TimeGenerated, *) by IndicatorId, Url
| project EmailUrlInfo_TimeGenerated, Description, ActivityGroupNames, IndicatorId, ThreatType, ExpirationDateTime, ConfidenceScore, Url, UrlDomain, UrlLocation, NetworkMessageId
| extend timestamp = EmailUrlInfo_TimeGenerated
| join kind=inner (EmailEvents_) on NetworkMessageId
| where DeliveryAction !has "Blocked"
| extend Name = tostring(split(RecipientEmailAddress, '@', 0)[0]), UPNSuffix = tostring(split(RecipientEmailAddress, '@', 1)[0])

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
Activeeq
  • true
field:"Active" kind:eq value:"true"
DomainNamein
  • EmailUrlDomains transforms: tolower
field:"DomainName" kind:in value:"EmailUrlDomains"
DomainNameis_not_null
  • (no value, null check)
field:"DomainName" kind:is_not_null
Urlin
  • EmailUrls transforms: tolower
field:"Url" kind:in value:"EmailUrls"
Urlis_not_null
  • (no value, null check)
field:"Url" kind:is_not_null

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
DeliveryActionmatchBlockedexcludes:DeliveryAction field:"DeliveryAction" value:"Blocked"

Output Fields

These fields are emitted when the rule matches.

FieldSource
ActivityGroupNamesproject
ConfidenceScoreproject
Descriptionproject
EmailUrlInfo_TimeGeneratedproject
ExpirationDateTimeproject
IndicatorIdproject
NetworkMessageIdproject
ThreatTypeproject
Urlproject
UrlDomainproject
UrlLocationproject
timestampextend
Nameextend
UPNSuffixextend

UniFi Site Manager: IPS signature count dropped >50%

#
Status
available
Severity
medium
Time window
7d
Group by
SiteId, SiteName
Source
github.com/Azure/Azure-Sentinel

Identifies when the IPS signature ruleset count drops by more than half versus the 7-day maximum, indicating broken threat-intel feeds or rollback.

MITRE ATT&CK Coverage

TacticTechniques
Defense Impairment

Rule Body

id: aa188a24-783a-76a1-cd11-3bcac0e97de9
name: "UniFi Site Manager: IPS signature count dropped >50%"
description: |
  Identifies when the IPS signature ruleset count drops by more than half versus the 7-day maximum, indicating broken threat-intel feeds or rollback.
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: UniFiSiteManagerConnectorDefinition
    dataTypes:
      - Unifi_SiteManager_Sites_CL
queryFrequency: 6h
queryPeriod: 7d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - DefenseEvasion
relevantTechniques:
  - T1562
subTechniques:
  - T1562.001
query: |
  Unifi_SiteManager_Sites_CL
        | where TimeGenerated > ago(7d)
  | extend rulesCount = toint(SiteStatistics.gateway.ipsSignature.rulesCount)
        | where isnotnull(rulesCount)
        | summarize MaxCount = max(rulesCount), arg_max(TimeGenerated, rulesCount) by SiteId, SiteName
        | where MaxCount > 100 and toreal(rulesCount) / MaxCount < 0.5
        | extend DropPct = round(100.0 * (1 - toreal(rulesCount) / MaxCount), 1)
        | extend Activity = strcat('IPS rules dropped to ', rulesCount, ' (from ', MaxCount, ', -', DropPct, '%)')
        | project TimeGenerated, SiteId, SiteName, Activity, CurrentRules = rulesCount, PeakRules = MaxCount, DropPct
entityMappings:
  - entityType: Host
    fieldMappings:
      - identifier: HostName
        columnName: SiteId
      - identifier: DnsDomain
        columnName: SiteName
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: false
    lookbackDuration: PT12H
    matchingMethod: AllEntities
kind: Scheduled
version: 1.0.1

Stages and Predicates

Stage 1: source

Unifi_SiteManager_Sites_CL

Stage 2: where

| where TimeGenerated > ago(7d)

Stage 3: extend

| extend rulesCount = toint(SiteStatistics.gateway.ipsSignature.rulesCount)

Stage 4: where

| where isnotnull(rulesCount)

Stage 5: summarize

| summarize MaxCount = max(rulesCount), arg_max(TimeGenerated, rulesCount) by SiteId, SiteName

Stage 6: where

| where MaxCount > 100 and toreal(rulesCount) / MaxCount < 0.5

Stage 7: extend

| extend DropPct = round(100.0 * (1 - toreal(rulesCount) / MaxCount), 1)

Stage 8: extend

| extend Activity = strcat('IPS rules dropped to ', rulesCount, ' (from ', MaxCount, ', -', DropPct, '%)')

Stage 9: project

| project TimeGenerated, SiteId, SiteName, Activity, CurrentRules = rulesCount, PeakRules = MaxCount, DropPct

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
MaxCountgt
  • 100 transforms: number
field:"MaxCount" kind:gt value:"100"
rulesCountis_not_null
  • (no value, null check)
field:"rulesCount" kind:is_not_null

Output Fields

These fields are emitted when the rule matches.

FieldSource
Activityproject
CurrentRulesproject
DropPctproject
PeakRulesproject
SiteIdproject
SiteNameproject
TimeGeneratedproject

Back to all Kusto rules