Detection rules › Kusto

BTP - Audit log service unavailable

Status
available
Severity
high
Time window
7d
Group by
SubaccountName, Tenant
Source
github.com/Azure/Azure-Sentinel

Identifies SAP BTP subaccounts that have not reported audit logs for an unusual period. This could indicate that the audit log service has been disabled or tampered with, potentially by an attacker attempting to hide malicious activity. It may also indicate service key expiry or SAP BTP service availability problems.

MITRE ATT&CK coverage

Rule body kusto

id: 8a3b5c7d-9e1f-4a2b-8c6d-3e5f7a9b1c2d
kind: Scheduled
name: BTP - Audit log service unavailable
description: |
  Identifies SAP BTP subaccounts that have not reported audit logs for an unusual period.
  This could indicate that the audit log service has been disabled or tampered with,
  potentially by an attacker attempting to hide malicious activity. It may also indicate
  service key expiry or SAP BTP service availability problems.
severity: High
status: Available
requiredDataConnectors:
  - connectorId: SAPBTPAuditEvents
    dataTypes:
      - SAPBTPAuditLog_CL
queryFrequency: 1h
queryPeriod: 7d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - DefenseEvasion
relevantTechniques:
  - T1562.008
query: |
  // Configure the detection threshold (in minutes) - adjust based on your environment
  let detection_threshold_in_minutes = 60;
  // Lookback period to identify known subaccounts
  let lookback = 7d;
  // Get all known subaccounts and their last log time
  let last_activity = SAPBTPAuditLog_CL
      | where TimeGenerated > ago(lookback)
      | summarize LastLogTime = max(TimeGenerated) by SubaccountName, Tenant;
  // Identify subaccounts with no recent activity exceeding the threshold
  last_activity
  | where datetime_diff('minute', now(), LastLogTime) > detection_threshold_in_minutes
  | extend TimeSinceLastLog = datetime_diff('minute', now(), LastLogTime)
  | project 
      SubaccountName,
      Tenant,
      LastLogTime,
      TimeSinceLastLog,
      CloudApp = "SAP BTP"
eventGroupingSettings:
  aggregationKind: AlertPerResult
entityMappings:
  - entityType: CloudApplication
    fieldMappings:
      - identifier: Name
        columnName: CloudApp
alertDetailsOverride:
  alertDisplayNameFormat: 'SAP BTP: No audit logs received from {{SubaccountName}} for {{TimeSinceLastLog}} minutes'
  alertDescriptionFormat: |
    The SAP BTP subaccount '{{SubaccountName}}' has not reported any audit logs since {{LastLogTime}}.
    
    Time without logs: {{TimeSinceLastLog}} minutes
    
    This could indicate:
    - Audit log service has been disabled (potential compromise to hide malicious activity)
    - Data connector authentication or connectivity issues
    - SAP BTP service availability problems
    
    Recommended actions:
    1. Verify the audit log service status in SAP BTP cockpit
    2. Check the data connector health in Microsoft Sentinel
    3. Review any recent administrative changes to the subaccount
    4. Investigate for potential unauthorized access or configuration changes
customDetails:
  SubaccountName: SubaccountName
  Tenant: Tenant
  LastLogTime: LastLogTime
  TimeSinceLastLog: TimeSinceLastLog
version: 1.0.0

Stages and Predicates

Parameters

let detection_threshold_in_minutes = 60;
let lookback = 7d;

The stages below define let last_activity (the rule's main pipeline source).

Stage 1: source

SAPBTPAuditLog_CL

Stage 2: where

| where TimeGenerated > ago(lookback)

Stage 3: summarize

| summarize LastLogTime = max(TimeGenerated) by SubaccountName, Tenant

The stages below run on last_activity (the outer pipeline).

Stage 4: where

last_activity
| where datetime_diff('minute', now(), LastLogTime) > detection_threshold_in_minutes

Stage 5: extend

| extend TimeSinceLastLog = datetime_diff('minute', now(), LastLogTime)

Stage 6: project

| project 
    SubaccountName,
    Tenant,
    LastLogTime,
    TimeSinceLastLog,
    CloudApp = "SAP BTP"

Output fields

Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.

FieldSource
CloudAppproject
LastLogTimeproject
SubaccountNameproject
Tenantproject
TimeSinceLastLogproject