Detection rules › Kusto

Exchange AuditLog Disabled

Status
available
Severity
medium
Time window
1d
Group by
AdminAuditLogEnabledValue, ClientIP, Operation, Parameters, ResultStatus, UserId, UserType
Source
github.com/Azure/Azure-Sentinel

Identifies when the exchange audit logging has been disabled which may be an adversary attempt to evade detection or avoid other defenses.

MITRE ATT&CK coverage

TacticTechniques
Defense Impairment

Telemetry coverage

Rule body

id: 194dd92e-d6e7-4249-85a5-273350a7f5ce
name: Exchange AuditLog Disabled
description: |
  'Identifies when the exchange audit logging has been disabled which may be an adversary attempt to evade detection or avoid other defenses.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: Office365
    dataTypes:
      - OfficeActivity (Exchange)
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - DefenseEvasion
relevantTechniques:
  - T1562
query: |
  OfficeActivity
  | where OfficeWorkload =~ "Exchange" 
  | where UserType in~ ("Admin","DcAdmin")
  // Only admin or global-admin can disable audit logging
  | where Operation =~ "Set-AdminAuditLogConfig"
  | extend AdminAuditLogEnabledValue = tostring(parse_json(tostring(parse_json(tostring(array_slice(parse_json(Parameters),3,3)))[0])).Value)
  | where AdminAuditLogEnabledValue =~ "False"
  | summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), OperationCount = count() by Operation, UserType, UserId, ClientIP, ResultStatus, Parameters, AdminAuditLogEnabledValue
  | extend AccountName = iff(UserId contains '@', tostring(split(UserId, '@')[0]), UserId)
  | extend AccountUPNSuffix = iff(UserId contains '@', tostring(split(UserId, '@')[1]), '')
  | extend AccountName = iff(UserId contains '\\', tostring(split(UserId, '\\')[1]), AccountName)
  | extend AccountNTDomain = iff(UserId contains '\\', tostring(split(UserId, '\\')[0]), '')
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: UserId
      - identifier: Name
        columnName: AccountName
      - identifier: UPNSuffix
        columnName: AccountUPNSuffix
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: AccountNTDomain
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: ClientIP
version: 2.0.6
kind: Scheduled

Stages and Predicates

Stage 1: source

OfficeActivity

Stage 2: where

| where OfficeWorkload =~ "Exchange"

Stage 3: where

| where UserType in~ ("Admin","DcAdmin")

Stage 4: where

| where Operation =~ "Set-AdminAuditLogConfig"

Stage 5: extend

| extend AdminAuditLogEnabledValue = tostring(parse_json(tostring(parse_json(tostring(array_slice(parse_json(Parameters),3,3)))[0])).Value)

Stage 6: where

| where AdminAuditLogEnabledValue =~ "False"

Stage 7: summarize

| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), OperationCount = count() by Operation, UserType, UserId, ClientIP, ResultStatus, Parameters, AdminAuditLogEnabledValue

Stage 8: extend (4 consecutive steps)

| extend AccountName = iff(UserId contains '@', tostring(split(UserId, '@')[0]), UserId)
| extend AccountUPNSuffix = iff(UserId contains '@', tostring(split(UserId, '@')[1]), '')
| extend AccountName = iff(UserId contains '\\', tostring(split(UserId, '\\')[1]), AccountName)
| extend AccountNTDomain = iff(UserId contains '\\', tostring(split(UserId, '\\')[0]), '')
AccountName =
ifUserId contains "@"tostring(split(UserId, '@')[0])
elseUserId

Indicators

These rows show field, operator, and value matches.

Output fields

These fields are emitted when the rule matches.

FieldSource
AdminAuditLogEnabledValuesummarize
ClientIPsummarize
EndTimeUtcsummarize
Operationsummarize
OperationCountsummarize
Parameterssummarize
ResultStatussummarize
StartTimeUtcsummarize
UserIdsummarize
UserTypesummarize
AccountNameextend
AccountUPNSuffixextend
AccountNTDomainextend