Detection rules › Kusto
Office Policy Tampering
Identifies if any tampering is done to either auditlog, ATP Safelink, SafeAttachment, AntiPhish or Dlp policy. An adversary may use this technique to evade detection or avoid other policy based defenses. References: https://docs.microsoft.com/powershell/module/exchange/advanced-threat-protection/remove-antiphishrule?view=exchange-ps.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Persistence | |
| Defense Impairment |
Telemetry coverage
Rule body
id: fbd72eb8-087e-466b-bd54-1ca6ea08c6d3
name: Office Policy Tampering
description: |
'Identifies if any tampering is done to either auditlog, ATP Safelink, SafeAttachment, AntiPhish or Dlp policy.
An adversary may use this technique to evade detection or avoid other policy based defenses.
References: https://docs.microsoft.com/powershell/module/exchange/advanced-threat-protection/remove-antiphishrule?view=exchange-ps.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: Office365
dataTypes:
- OfficeActivity (Exchange)
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
- DefenseEvasion
relevantTechniques:
- T1098
- T1562
query: |
let opList = OfficeActivity
| summarize by Operation
//| where Operation startswith "Remove-" or Operation startswith "Disable-"
| where Operation has_any ("Remove", "Disable")
| where Operation contains "AntiPhish" or Operation contains "SafeAttachment" or Operation contains "SafeLinks" or Operation contains "Dlp" or Operation contains "Audit"
| summarize make_set(Operation, 500);
OfficeActivity
// Only admin or global-admin can disable/remove policy
| where RecordType =~ "ExchangeAdmin"
| where UserType in~ ("Admin","DcAdmin")
// Pass in interesting Operation list
| where Operation in~ (opList)
| extend ClientIPOnly = case(
ClientIP has ".", tostring(split(ClientIP,":")[0]),
ClientIP has "[", tostring(trim_start(@'[[]',tostring(split(ClientIP,"]")[0]))),
ClientIP
)
| extend Port = case(
ClientIP has ".", (split(ClientIP,":")[1]),
ClientIP has "[", tostring(split(ClientIP,"]:")[1]),
ClientIP
)
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), OperationCount = count() by Operation, UserType, UserId, ClientIP = ClientIPOnly, Port, ResultStatus, Parameters
| extend AccountName = tostring(split(UserId, "@")[0]), AccountUPNSuffix = tostring(split(UserId, "@")[1])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: UserId
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: AccountUPNSuffix
- entityType: IP
fieldMappings:
- identifier: Address
columnName: ClientIP
version: 2.0.3
kind: Scheduled
Stages and Predicates
Let binding: opList
let opList = OfficeActivity
| summarize by Operation
| where Operation has_any ("Remove", "Disable")
| where Operation contains "AntiPhish" or Operation contains "SafeAttachment" or Operation contains "SafeLinks" or Operation contains "Dlp" or Operation contains "Audit"
| summarize make_set(Operation, 500);
Stage 1: source
OfficeActivity
Stage 2: where
| where RecordType =~ "ExchangeAdmin"
Stage 3: where
| where UserType in~ ("Admin","DcAdmin")
Stage 4: where
| where Operation in~ (opList)
Stage 5: extend
| extend ClientIPOnly = case(
ClientIP has ".", tostring(split(ClientIP,":")[0]),
ClientIP has "[", tostring(trim_start(@'[[]',tostring(split(ClientIP,"]")[0]))),
ClientIP
)
ClientIPOnly =if
ClientIP has "."tostring(split(ClientIP, ":")[0])elif
ClientIP has "["tostring(trim_start(@'[[]', tostring(split(ClientIP, "]")[0])))else
ClientIPStage 6: extend
| extend Port = case(
ClientIP has ".", (split(ClientIP,":")[1]),
ClientIP has "[", tostring(split(ClientIP,"]:")[1]),
ClientIP
)
Port =if
ClientIP has "."split(ClientIP, ":")[1]elif
ClientIP has "["tostring(split(ClientIP, "]:")[1])else
ClientIPStage 7: summarize
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), OperationCount = count() by Operation, UserType, UserId, ClientIP = ClientIPOnly, Port, ResultStatus, Parameters
Stage 8: extend
| extend AccountName = tostring(split(UserId, "@")[0]), AccountUPNSuffix = tostring(split(UserId, "@")[1])
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Operation | in |
| field:"Operation" kind:in value:"opList" |
RecordType | eq |
| field:"RecordType" kind:eq value:"ExchangeAdmin" |
UserType | in |
| field:"UserType" kind:in |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ClientIP | summarize |
EndTimeUtc | summarize |
Operation | summarize |
OperationCount | summarize |
Parameters | summarize |
Port | summarize |
ResultStatus | summarize |
StartTimeUtc | summarize |
UserId | summarize |
UserType | summarize |
AccountName | extend |
AccountUPNSuffix | extend |