Detection rules › Kusto

Kusto rules: 14

Changes to Application Ownership

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

Detects changes to the ownership of an appplicaiton. Monitor these changes to make sure that they were authorized. Ref: https://learn.microsoft.com/en-gb/entra/architecture/security-operations-applications#new-owner

MITRE ATT&CK Coverage

Telemetry Coverage

PlatformRecord / event type
AzureAdd owner to application

Rules Detecting the Same Action

These rules filter on the same operation.

Rule Body

id: cc5780ce-3245-4bba-8bc1-e9048c2257ce
name: Changes to Application Ownership
description: |
  'Detects changes to the ownership of an appplicaiton.
    Monitor these changes to make sure that they were authorized.
    Ref: https://learn.microsoft.com/en-gb/entra/architecture/security-operations-applications#new-owner'
severity: Medium
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
      - AuditLogs
queryFrequency: 2h
queryPeriod: 2h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Persistence
  - PrivilegeEscalation
relevantTechniques:
  - T1078.004
tags:
  - AADSecOpsGuide
query: |
  AuditLogs
    | where Category =~ "ApplicationManagement"
    | where OperationName =~ "Add owner to application"
    | 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 TargetUserPrincipalName = TargetResources[0].userPrincipalName
    | extend TargetAadUserId = tostring(TargetResources[0].id)
    | extend mod_props = TargetResources[0].modifiedProperties
    | mv-expand mod_props
    | where mod_props.displayName =~ "Application.DisplayName"
    | extend TargetAppName = tostring(parse_json(tostring(mod_props.newValue)))
    | extend AddedUser = TargetUserPrincipalName
    | extend UpdatedBy = iif(isnotempty(InitiatingAppName), InitiatingAppName, InitiatingUserPrincipalName)
    | extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
    | extend TargetAccountName = tostring(split(TargetUserPrincipalName, "@")[0]), TargetAccountUPNSuffix = tostring(split(TargetUserPrincipalName, "@")[1])
    | project-reorder TimeGenerated, InitiatingAppName, InitiatingAppServicePrincipalId, InitiatingAadUserId, InitiatingUserPrincipalName, InitiatingIPAddress, TargetAppName, AddedUser, UpdatedBy
entityMappings:
  - 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: FullName
        columnName: TargetUserPrincipalName
      - identifier: Name
        columnName: TargetAccountName
      - identifier: UPNSuffix
        columnName: TargetAccountUPNSuffix
  - entityType: Account
    fieldMappings:
      - identifier: AadUserId
        columnName: TargetAadUserId
version: 1.1.2
kind: Scheduled
metadata:
    source:
        kind: Community
    author:
        name: Microsoft Security Research
    support:
        tier: Community
    categories:
        domains: [ "Security - Others" ]

Stages and Predicates

Stage 1: source

AuditLogs

Stage 2: where

| where Category =~ "ApplicationManagement"

Stage 3: where

| where OperationName =~ "Add owner to application"

Stage 4: 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 TargetUserPrincipalName = TargetResources[0].userPrincipalName
| extend TargetAadUserId = tostring(TargetResources[0].id)
| extend mod_props = TargetResources[0].modifiedProperties

Stage 5: mv-expand

| mv-expand mod_props

Stage 6: where

| where mod_props.displayName =~ "Application.DisplayName"

Stage 7: extend (5 consecutive steps)

| extend TargetAppName = tostring(parse_json(tostring(mod_props.newValue)))
| extend AddedUser = TargetUserPrincipalName
| extend UpdatedBy = iif(isnotempty(InitiatingAppName), InitiatingAppName, InitiatingUserPrincipalName)
| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
| extend TargetAccountName = tostring(split(TargetUserPrincipalName, "@")[0]), TargetAccountUPNSuffix = tostring(split(TargetUserPrincipalName, "@")[1])

Stage 8: project-reorder

| project-reorder TimeGenerated, InitiatingAppName, InitiatingAppServicePrincipalId, InitiatingAadUserId, InitiatingUserPrincipalName, InitiatingIPAddress, TargetAppName, AddedUser, UpdatedBy

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
InitiatingAppNameextend
InitiatingAppServicePrincipalIdextend
InitiatingUserPrincipalNameextend
InitiatingAadUserIdextend
InitiatingIPAddressextend
TargetUserPrincipalNameextend
TargetAadUserIdextend
mod_propsextend
TargetAppNameextend
AddedUserextend
UpdatedByextend
InitiatingAccountNameextend
InitiatingAccountUPNSuffixextend
TargetAccountNameextend
TargetAccountUPNSuffixextend

ContraForce - Destructive workspace action

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

'Identifies destructive actions against the ContraForce workspace or its account: workspace deletion, account deactivation, and account purge. These actions terminate or remove the security service delivery for the affected workspace and should always correspond to a planned offboarding; anything else warrants immediate investigation.'

MITRE ATT&CK Coverage

Rule Body

id: c5e9a1d7-4b2f-4e6c-8a9d-7f3b1c5e2a84
name: ContraForce - Destructive workspace action
description: |
  'Identifies destructive actions against the ContraForce workspace or its account: workspace
  deletion, account deactivation, and account purge. These actions terminate or remove the
  security service delivery for the affected workspace and should always correspond to a
  planned offboarding; anything else warrants immediate investigation.'
severity: High
requiredDataConnectors:
  - connectorId: ContraForceEvents
    dataTypes:
      - ContraForceEvents_CL
queryFrequency: 5m
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
  - Impact
relevantTechniques:
  - T1485
  - T1531
query: |
  ContraForceEvents_CL
  | where ingestion_time() > ago(5m)
  | where ActivityType in ("WorkspaceDeleted", "AccountDeactivated", "AccountPurged")
  | extend Meta = parse_json(Metadata)
  | project TimeGenerated, EventId, CfWorkspaceId, ActivityType, ActivityAction,
            ActorName, ActorEmail, TargetResourceType, TargetResourceId, TargetResourceName, Metadata
eventGroupingSettings:
  aggregationKind: AlertPerResult
alertDetailsOverride:
  alertDisplayNameFormat: 'ContraForce destructive action: {{ActivityType}} on {{TargetResourceName}}'
  alertDescriptionFormat: '{{ActorName}} performed {{ActivityType}} on {{TargetResourceName}}.'
customDetails:
  EventId: EventId
  ActorEmail: ActorEmail
  TargetResourceId: TargetResourceId
  CfWorkspaceId: CfWorkspaceId
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: false
    lookbackDuration: PT2H
    matchingMethod: Selected
    groupByCustomDetails:
      - EventId
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

ContraForceEvents_CL

Stage 2: where

| where ingestion_time() > ago(5m)

Stage 3: where

| where ActivityType in ("WorkspaceDeleted", "AccountDeactivated", "AccountPurged")

Stage 4: extend

| extend Meta = parse_json(Metadata)

Stage 5: project

| project TimeGenerated, EventId, CfWorkspaceId, ActivityType, ActivityAction,
          ActorName, ActorEmail, TargetResourceType, TargetResourceId, TargetResourceName, Metadata

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
ActivityTypein
  • AccountDeactivated
  • AccountPurged
  • WorkspaceDeleted
field:"ActivityType" kind:in

Output Fields

These fields are emitted when the rule matches.

FieldSource
ActivityActionproject
ActivityTypeproject
ActorEmailproject
ActorNameproject
CfWorkspaceIdproject
EventIdproject
Metadataproject
TargetResourceIdproject
TargetResourceNameproject
TargetResourceTypeproject
TimeGeneratedproject

Cyble Vision Alerts Darkweb Data Breaches

#

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 darkweb credential leakage and data breach records from CybleVision. Extracts leaked username, email, password hashes, registration dates, and metadata using the Alerts_DarkwebDataBreaches parser. Incidents grouped per service.'

MITRE ATT&CK Coverage

Rule Body

id: 588a2ee5-978a-43f7-9c10-6d76d82026ef
name: "Cyble Vision Alerts Darkweb Data Breaches"
description: |
  'Detects darkweb credential leakage and data breach records from CybleVision. Extracts leaked username, email, password hashes, registration dates, and metadata using the Alerts_DarkwebDataBreaches 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
- InitialAccess
- Exfiltration
- Collection
relevantTechniques:
- T1589
- T1078
- T1048
- T1530
subTechniques: []
query: |
  Alerts_darkweb_data_breaches 
  | where Service == "darkweb_data_breaches" 
  | extend  MappedSeverity = Severity
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: false
    reopenClosedIncident: false
    lookbackDuration: PT5H
    matchingMethod: AllEntities
alertDetailsOverride:
  alertDisplayNameFormat: CybleVision Darkweb Breach for {{DB_Email}}
  alertDescriptionFormat: |
    Username {{DB_Username}} Registration date {{DB_RegistrationDate}} Breach source {{Breach_Source}}
  alertDynamicProperties: []
customDetails:
  MappedSeverity: Severity
  Status: Status
  AlertID: AlertID
  Service: Service
  LeakedEmail: DB_Email
  UserName: DB_Username
  PasswordHash: DB_PasswordHash
  DisplayName: DB_DisplayName
  RegistrationDate: DB_RegistrationDate
  BreachDate: DB_Date
  BreachSource: Breach_Source
  S3Key: DB_S3Key
  Structured: DB_Structured
  Tags: DB_Tags
entityMappings:
- entityType: Account
  fieldMappings:
  - identifier: Name
    columnName: DB_Username
- entityType: DNS
  fieldMappings:
  - identifier: DomainName
    columnName: Domain
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: IP
- entityType: Mailbox
  fieldMappings:
  - identifier: MailboxPrimaryAddress
    columnName: DB_Email
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

Alerts_darkweb_data_breaches

Stage 2: where

| where Service == "darkweb_data_breaches"

Stage 3: extend

| extend  MappedSeverity = Severity

Indicators

These rows show field, operator, and value matches.

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

Output Fields

These fields are emitted when the rule matches.

FieldSource
MappedSeverityextend

Cyble Vision Alerts Github

#

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

'This alert generates incidents for Github'

MITRE ATT&CK Coverage

Rule Body

id: 117e8f7c-8f44-4061-bcc2-b444b98a3838
name: Cyble Vision Alerts Github
description: |
  'This alert generates incidents for Github'
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:
- Collection
- CredentialAccess
relevantTechniques:
- T1213
- T1530
- T1552
subTechniques: []
query: |
  Alerts_github
  | where Service contains "github"
  | extend MappedSeverity = Severity
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: false
    reopenClosedIncident: false
    lookbackDuration: PT5H
    matchingMethod: AllEntities
alertDetailsOverride:
  alertDisplayNameFormat: Cyble Vision Alert for Github
  alertDescriptionFormat: This Rule generate incidents for Serviec Github
  alertDynamicProperties: []
customDetails:
  MappedSeverity: Severity
  Status: Status
  AlertID: AlertID
  Service: Service
  GitURl: git_url
  URL: html_url
  Repository: repo_full_name
  FileName: file_name
  Owner: owner_login
  SHA: sha
  Score: score
  OriginalSeverity: Severity
entityMappings:
- entityType: Account
  fieldMappings:
  - identifier: Name
    columnName: owner_login
- entityType: URL
  fieldMappings:
  - identifier: Url
    columnName: html_url
- entityType: File
  fieldMappings:
  - identifier: Name
    columnName: file_name
  - identifier: Directory
    columnName: file_path
version: 1.0.1
kind: Scheduled

Stages and Predicates

Stage 1: source

Alerts_github

Stage 2: where

| where Service contains "github"

Stage 3: extend

| extend MappedSeverity = Severity

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
Servicecontains
  • github
field:"Service" kind:contains value:"github"

Output Fields

These fields are emitted when the rule matches.

FieldSource
MappedSeverityextend

Denial of Service (Microsoft Defender for IoT)

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

'This alert leverages Defender for IoT to detect attacks that would prevent the use or proper operation of a DCS system including Denial of Service events.'

MITRE ATT&CK Coverage

TacticTechniques
Inhibit Response Function

Rule Body

id: e068187a-01f5-4737-bc13-25db4027b7ea
name: Denial of Service (Microsoft Defender for IoT)
description: |
  'This alert leverages Defender for IoT to detect attacks that would prevent the use or proper operation of a DCS system including Denial of Service events.'
severity: High
status: Available
requiredDataConnectors:
  - connectorId: IoT
    dataTypes:
      - SecurityAlert (ASC for IoT)
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
tactics:
  - InhibitResponseFunction
relevantTechniques:
  - T0814
query: |
  SecurityAlert
  | where ProviderName == "IoTSecurity"
  | where AlertName == "Suspicion of Denial Of Service Attack"
  | extend ExtendedProperties = parse_json(ExtendedProperties)
  | where tostring(ExtendedProperties.isNew) == "True"
  | extend DeviceId = tostring(ExtendedProperties.DeviceId), 
           SourceDeviceAddress = tostring(ExtendedProperties.SourceDeviceAddress), 
           DestDeviceAddress = tostring(ExtendedProperties.DestinationDeviceAddress), 
           RemediationSteps = tostring(parse_json(RemediationSteps)[0]), 
           Protocol = tostring(ExtendedProperties.Protocol), 
           AlertManagementUri = tostring(ExtendedProperties.AlertManagementUri)
  | project
    TimeGenerated,
    DeviceId,
    ProductName,
    ProductComponentName,
    AlertSeverity,
    AlertName,
    Description,
    Protocol,
    SourceDeviceAddress,
    DestDeviceAddress,
    RemediationSteps,
    Tactics,
    Entities,
    VendorOriginalId,
    AlertLink,
    AlertManagementUri,
    Techniques
entityMappings:
sentinelEntitiesMappings:
  - columnName: Entities
eventGroupingSettings:
  aggregationKind: AlertPerResult
customDetails:
  Sensor: DeviceId
  Protocol: Protocol
  VendorOriginalId: VendorOriginalId
  AlertManagementUri: AlertManagementUri
alertDetailsOverride:
  alertDisplayNameFormat: (MDIoT) {{AlertName}}
  alertDescriptionFormat: (MDIoT) {{Description}}
  alertTacticsColumnName: Tactics
  alertSeverityColumnName: AlertSeverity
  alertDynamicProperties: 
    - alertProperty: ProductName
      value: ProductName
    - alertProperty: RemediationSteps
      value: RemediationSteps
    - alertProperty: Techniques
      value: Techniques
    - alertProperty: ProductComponentName
      value: ProductComponentName
    - alertProperty: AlertLink
      value: AlertLink
version: 1.0.3
kind: Scheduled

Stages and Predicates

Stage 1: source

SecurityAlert

Stage 2: where

| where ProviderName == "IoTSecurity"

Stage 3: where

| where AlertName == "Suspicion of Denial Of Service Attack"

Stage 4: extend

| extend ExtendedProperties = parse_json(ExtendedProperties)

Stage 5: where

| where tostring(ExtendedProperties.isNew) == "True"

Stage 6: extend

| extend DeviceId = tostring(ExtendedProperties.DeviceId), 
         SourceDeviceAddress = tostring(ExtendedProperties.SourceDeviceAddress), 
         DestDeviceAddress = tostring(ExtendedProperties.DestinationDeviceAddress), 
         RemediationSteps = tostring(parse_json(RemediationSteps)[0]), 
         Protocol = tostring(ExtendedProperties.Protocol), 
         AlertManagementUri = tostring(ExtendedProperties.AlertManagementUri)

Stage 7: project

| project
  TimeGenerated,
  DeviceId,
  ProductName,
  ProductComponentName,
  AlertSeverity,
  AlertName,
  Description,
  Protocol,
  SourceDeviceAddress,
  DestDeviceAddress,
  RemediationSteps,
  Tactics,
  Entities,
  VendorOriginalId,
  AlertLink,
  AlertManagementUri,
  Techniques

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
AlertNameeq
  • Suspicion of Denial Of Service Attack
field:"AlertName" kind:eq value:"Suspicion of Denial Of Service Attack"
ExtendedProperties.isNeweq
  • True transforms: tostring, kusto_dynamic_path corpus 15 (kusto 15)
field:"ExtendedProperties.isNew" kind:eq value:"True"
ProviderNameeq
  • IoTSecurity corpus 15 (kusto 15)
field:"ProviderName" kind:eq value:"IoTSecurity"

Output Fields

These fields are emitted when the rule matches.

FieldSource
AlertLinkproject
AlertManagementUriproject
AlertNameproject
AlertSeverityproject
Descriptionproject
DestDeviceAddressproject
DeviceIdproject
Entitiesproject
ProductComponentNameproject
ProductNameproject
Protocolproject
RemediationStepsproject
SourceDeviceAddressproject
Tacticsproject
Techniquesproject
TimeGeneratedproject
VendorOriginalIdproject

Exchange Worker Process Making Remote Call

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

This query dynamically identifies Exchange servers and then looks for instances where the IIS worker process initiates a call out to a remote URL using either cmd.exe or powershell.exe. This behaviour was described as post-compromise behaviour following exploitation of CVE-2022-41040 and CVE-2022-41082, this pattern of activity was use to download additional tools to the server. This suspicious activity is generic.

MITRE ATT&CK Coverage

Telemetry Coverage

Rule Body

id: 2c701f94-783c-4cd4-bc9b-3b3334976090
name: Exchange Worker Process Making Remote Call
description: |
  'This query dynamically identifies Exchange servers and then looks for instances where the IIS worker process initiates a call out to a remote URL using either cmd.exe or powershell.exe.
  This behaviour was described as post-compromise behaviour following exploitation of CVE-2022-41040 and CVE-2022-41082, this pattern of activity was use to download additional tools to the server. This suspicious activity is generic.'
severity: Medium
requiredDataConnectors:
  - connectorId: AzureMonitor(IIS)
    dataTypes:
      - W3CIISLog
  - connectorId: MicrosoftThreatProtection
    dataTypes:
    - DeviceProcessEvents
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt 
triggerThreshold: 0
tactics:
  - Execution
relevantTechniques:
  - T1059.001
  - T1059.003
query: |
  let suspiciousCmdLineKeywords = dynamic(["http://", "https://"]);
  // Identify exchange servers based on known paths
  // Summarize these to get a list of exchange server hostnames
  let exchangeServers = W3CIISLog
  | where csUriStem has_any("/owa/","/ews/","/ecp/","/autodiscover/")
  // Only where successful, rule out failed scanning
  | where scStatus startswith "2"
  | summarize by Computer;
  DeviceProcessEvents
  | where DeviceName in~ (exchangeServers)
  // Where the IIS worker process initiated CMD or PowerShell
  | where InitiatingProcessParentFileName == "w3wp.exe"
  | where InitiatingProcessFileName has_any("cmd.exe", "powershell.exe")
  // Where CMD or PowerShell command line included parameters associated with CVE-2022-41040/CVE-2022-41082 exploitation
  | where ProcessCommandLine has_any(suspiciousCmdLineKeywords)
  | project TimeGenerated, DeviceId, DeviceName, InitiatingProcessFileName, ProcessCommandLine, AccountDomain = InitiatingProcessAccountDomain, AccountName = InitiatingProcessAccountName
  | extend Account = strcat(AccountDomain, "\\", AccountName)
  | 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: Account
      - identifier: Name
        columnName: AccountName
      - identifier: NTDomain
        columnName: AccountDomain
  - entityType: Host
    fieldMappings:
      - identifier: FullName
        columnName: DeviceName
      - identifier: HostName
        columnName: HostName
      - identifier: NTDomain
        columnName: HostNameDomain
version: 1.1.2
kind: Scheduled
metadata:
    source:
        kind: Community
    author:
        name: Microsoft Security Community
    support:
        tier: Community
    categories:
        domains: [ "Application" ]

Stages and Predicates

Parameters

let suspiciousCmdLineKeywords = dynamic(["http://", "https://"]);

Let Binding: exchangeServers used in Stage 2

let exchangeServers = W3CIISLog
| where csUriStem has_any("/owa/","/ews/","/ecp/","/autodiscover/")
| where scStatus startswith "2"
| summarize by Computer;

Stage 1: source

DeviceProcessEvents

Stage 2: where

| where DeviceName in~ (exchangeServers)

Stage 3: where

| where InitiatingProcessParentFileName == "w3wp.exe"

Stage 4: where

| where InitiatingProcessFileName has_any("cmd.exe", "powershell.exe")

Stage 5: where

| where ProcessCommandLine has_any(suspiciousCmdLineKeywords)

Stage 6: project

| project TimeGenerated, DeviceId, DeviceName, InitiatingProcessFileName, ProcessCommandLine, AccountDomain = InitiatingProcessAccountDomain, AccountName = InitiatingProcessAccountName

Stage 7: extend (3 consecutive steps)

| extend Account = strcat(AccountDomain, "\\", AccountName)
| extend HostName = tostring(split(DeviceName, ".")[0]), DomainIndex = toint(indexof(DeviceName, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(DeviceName, DomainIndex + 1), DeviceName)

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
DeviceNamein
  • exchangeServers
field:"Computer" kind:in value:"exchangeServers"
InitiatingProcessFileNamematch
  • cmd.exe transforms: term corpus 2 (kusto 2)
  • powershell.exe transforms: term corpus 2 (kusto 2)
field:"parent_process_basename" kind:match
InitiatingProcessParentFileNameeq
  • w3wp.exe
field:"grandparent_process_basename" kind:eq value:"w3wp.exe"
ProcessCommandLinematch
  • http:// transforms: term
  • https:// transforms: term
field:"CommandLine" kind:match

Output Fields

These fields are emitted when the rule matches.

FieldSource
AccountDomainproject
AccountNameproject
DeviceIdproject
DeviceNameproject
InitiatingProcessFileNameproject
ProcessCommandLineproject
TimeGeneratedproject
Accountextend
DomainIndexextend
HostNameextend
HostNameDomainextend

SSG_Security_Incidents

#
Severity
high
Source
github.com/Azure/Azure-Sentinel

The security analytic rule is designed to scrutinize network activity involving private IP addresses within an organization's internal network. By filtering log entries to include only those where either the source or the destination IP is private, the rule focuses on internal communications that could indicate unauthorized access, internal threats, or other security anomalies.

MITRE ATT&CK Coverage

TacticTechniques
Impact

Rule Body

id: d41fa731-45a2-4b23-bb1d-29896fbc5298
name: SSG_Security_Incidents
version: 1.0.0
kind: NRT
description: The security analytic rule is designed to scrutinize network activity involving private IP addresses within an organization's internal network. By filtering log entries to include only those where either the source or the destination IP is private, the rule focuses on internal communications that could indicate unauthorized access, internal threats, or other security anomalies.
severity: HIGH
tactics:
  - Impact
relevantTechniques:
  - T1486
query: |
  SINECSecurityGuard_CL
  | where ipv4_is_private(source_ip) or ipv4_is_private(destination_ip)
  | project source_ip, destination_ip, signature_id, signature_name
suppressionEnabled: false
eventGroupingSettings:
  aggregationKind: AlertPerResult
suppressionDuration: 5h
alertDetailsOverride:
  alertDisplayNameFormat: '{{signature_name}} '
  alertDescriptionFormat: 'Alert {{signature_name}} generated from {{source_ip}} to {{destination_ip}} '
  alertDynamicProperties: []
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: false
    lookbackDuration: 5m
    matchingMethod: AnyAlert
    groupByEntities:
    - IP
    groupByAlertDetails: []
    groupByCustomDetails:
    - Source_IP
entityMappings:
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: source_ip
- entityType: IP
  fieldMappings:
  - identifier: Address
    columnName: destination_ip
customDetails:
  Source_IP: source_ip

Stages and Predicates

Stage 1: source

SINECSecurityGuard_CL

Stage 2: where

| where ipv4_is_private(source_ip) or ipv4_is_private(destination_ip)

Stage 3: project

| project source_ip, destination_ip, signature_id, signature_name

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
destination_ipcidr_match
  • 10.0.0.0/8
  • 127.0.0.0/8
  • 169.254.0.0/16
  • 172.16.0.0/12
  • 192.168.0.0/16
field:"destination_ip" kind:cidr_match
source_ipcidr_match
  • 10.0.0.0/8
  • 127.0.0.0/8
  • 169.254.0.0/16
  • 172.16.0.0/12
  • 192.168.0.0/16
field:"src_ip" kind:cidr_match

Output Fields

These fields are emitted when the rule matches.

FieldSource
destination_ipproject
signature_idproject
signature_nameproject
source_ipproject

Back to all Kusto rules