Detection rules › Kusto
F&O - Reverted bank account number modifications
Identifies changes to bank account numbers in Finance & Operations, whereby a bank account number is modified but then subsequently reverted a short time later.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Impact | T1496 Resource Hijacking, T1565 Data Manipulation |
| Impact | T0828 Loss of Productivity and Revenue, T0831 Manipulation of Control |
Rule body kusto
id: 44b1021c-d517-4b7a-9ba6-a91eab94e632
kind: Scheduled
name: F&O - Reverted bank account number modifications
description: Identifies changes to bank account numbers in Finance & Operations, whereby
a bank account number is modified but then subsequently reverted a short time later.
severity: Low
status: Available
requiredDataConnectors:
- connectorId: Dynamics365Finance
dataTypes:
- FinanceOperationsActivity_CL
queryFrequency: 15m
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Impact
relevantTechniques:
- T1565
- T1496
- T0828
- T0831
query: |
let detection_window = 24h;
let query_frequency = 15m;
let bank_changes = FinanceOperationsActivity_CL
| where LogType == "Update" and TableName == "BankAccountTable"
| extend AccountId = tostring(parse_json(tostring(FormattedData.AccountID)).NewData)
| extend AccountNum = parse_json(tostring(FormattedData.AccountNum))
| extend
CurrentAccountNum = tostring(AccountNum.NewData),
OldAccountNum = tostring(AccountNum.OldData)
| where CurrentAccountNum != OldAccountNum;
bank_changes
| join kind=inner (bank_changes
| where TimeGenerated >= ago(query_frequency)
| project-rename UpdatedTime = LogCreatedDateTime, UpdatedAccount = CurrentAccountNum)
on $left.OldAccountNum == $right.UpdatedAccount
| where UpdatedTime between (LogCreatedDateTime .. (LogCreatedDateTime + detection_window))
| extend FinOpsAppId = 32780
| project
TimeGenerated,
LogCreatedDateTime,
LogType,
TableName,
Username,
AccountId,
CurrentAccountNum,
OldAccountNum,
FinOpsAppId
eventGroupingSettings:
aggregationKind: SingleAlert
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: Username
- entityType: CloudApplication
fieldMappings:
- identifier: AppId
columnName: FinOpsAppId
alertDetailsOverride:
alertDisplayNameFormat: F&O - Suspicious bank account number changes
alertDescriptionFormat: A suspicous bank account change was made in F&O, the bank
account number was updated and then changed back to the orginal number a short
time later. {{AccountId}} was changed by {{Username}}
version: 3.2.0
Stages and Predicates
Parameters
let detection_window = 24h;
let query_frequency = 15m;
The stages below define let bank_changes (the rule's main pipeline source).
Stage 1: source
FinanceOperationsActivity_CL
Stage 2: where
| where LogType == "Update" and TableName == "BankAccountTable"
Stage 3: extend (3 consecutive steps)
| extend AccountId = tostring(parse_json(tostring(FormattedData.AccountID)).NewData)
| extend AccountNum = parse_json(tostring(FormattedData.AccountNum))
| extend
CurrentAccountNum = tostring(AccountNum.NewData),
OldAccountNum = tostring(AccountNum.OldData)
Stage 4: where
| where CurrentAccountNum != OldAccountNum
The stages below run on bank_changes (the outer pipeline).
Stage 5: join
bank_changes
| join kind=inner (bank_changes
| where TimeGenerated >= ago(query_frequency)
| project-rename UpdatedTime = LogCreatedDateTime, UpdatedAccount = CurrentAccountNum)
on $left.OldAccountNum == $right.UpdatedAccount
Stage 6: where
| where UpdatedTime between (LogCreatedDateTime .. (LogCreatedDateTime + detection_window))
Stage 7: extend
| extend FinOpsAppId = 32780
Stage 8: project
| project
TimeGenerated,
LogCreatedDateTime,
LogType,
TableName,
Username,
AccountId,
CurrentAccountNum,
OldAccountNum,
FinOpsAppId
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.
| Field | Kind | Values |
|---|---|---|
CurrentAccountNum | ne |
|
LogType | eq |
|
TableName | eq |
|
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 |
|---|---|
AccountId | project |
CurrentAccountNum | project |
FinOpsAppId | project |
LogCreatedDateTime | project |
LogType | project |
OldAccountNum | project |
TableName | project |
TimeGenerated | project |
Username | project |