Detection rules › Kusto
Dataverse - Export activity from terminated or notified employee
This query identifies Dataverse export activity triggered by terminated, or employees about to leave the organization. This analytics rule uses the TerminatedEmployees watchlist template.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Exfiltration | T1048 Exfiltration Over Alternative Protocol, T1567 Exfiltration Over Web Service |
Rule body kusto
id: 0881b209-62c9-4b15-9f9a-e0c1d1b1eb7b
kind: Scheduled
name: Dataverse - Export activity from terminated or notified employee
description: This query identifies Dataverse export activity triggered by terminated,
or employees about to leave the organization. This analytics rule uses the TerminatedEmployees
watchlist template.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: Dataverse
dataTypes:
- DataverseActivity
queryFrequency: 1h
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Exfiltration
relevantTechniques:
- T1567
- T1048
query: |
// Set a time period before employee terminatation date to search for export events
let termination_watch_period = 7d;
let query_frequency = 1h;
let exportEvents = dynamic(['ExportToExcel', 'ExportPdfDocument', 'ExportWordDocument', 'ExecutePowerBISql']);
MSBizAppsTerminatedEmployees
| where (UserState =~ "Terminated") or (UserState =~ "Notified" and TerminationDate <= startofday(now()) + termination_watch_period)
| join kind=inner (DataverseActivity
| where TimeGenerated >= ago(query_frequency)
| where Message in (exportEvents))
on $left.UserPrincipalName == $right.UserId
| summarize
FirstEvent = min(TimeGenerated),
LastEvent = max(TimeGenerated),
Event = make_set(Message, 4)
by UserId, InstanceUrl, ClientIp, UserState
| extend
CloudAppId = int(32780),
AccountName = tostring(split(UserId, '@')[0]),
UPNSuffix = tostring(split(UserId, '@')[1])
| project
FirstEvent,
LastEvent,
UserId,
ClientIp,
UserState,
InstanceUrl,
CloudAppId,
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
alertDetailsOverride:
alertDisplayNameFormat: 'Dataverse - Export events detected from a terminated employee
in {{InstanceUrl}} '
alertDescriptionFormat: Export events where employee state found matching {{UserState}}
found in {{InstanceUrl}}.
version: 3.2.0
Stages and Predicates
Parameters
let termination_watch_period = 7d;
let query_frequency = 1h;
let exportEvents = dynamic(['ExportToExcel', 'ExportPdfDocument', 'ExportWordDocument', 'ExecutePowerBISql']);
Stage 1: source
MSBizAppsTerminatedEmployees
Stage 2: where
| where (UserState =~ "Terminated") or (UserState =~ "Notified" and TerminationDate <= startofday(now()) + termination_watch_period)
Stage 3: join
| join kind=inner (DataverseActivity
| where TimeGenerated >= ago(query_frequency)
| where Message in (exportEvents))
on $left.UserPrincipalName == $right.UserId
Stage 4: summarize
| summarize
FirstEvent = min(TimeGenerated),
LastEvent = max(TimeGenerated),
Event = make_set(Message, 4)
by UserId, InstanceUrl, ClientIp, UserState
Stage 5: extend
| extend
CloudAppId = int(32780),
AccountName = tostring(split(UserId, '@')[0]),
UPNSuffix = tostring(split(UserId, '@')[1])
Stage 6: project
| project
FirstEvent,
LastEvent,
UserId,
ClientIp,
UserState,
InstanceUrl,
CloudAppId,
AccountName,
UPNSuffix
Indicators
Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.
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.
| Field | Source |
|---|---|
AccountName | project |
ClientIp | project |
CloudAppId | project |
FirstEvent | project |
InstanceUrl | project |
LastEvent | project |
UPNSuffix | project |
UserId | project |
UserState | project |