Detection rules › Kusto

F&O - Reverted bank account number modifications

Status
available
Severity
low
Time window
1d
Group by
OldAccountNum, UpdatedAccount
Source
github.com/Azure/Azure-Sentinel

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

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.

FieldKindValues
CurrentAccountNumne
  • OldAccountNum transforms: cased
LogTypeeq
  • Update transforms: cased
TableNameeq
  • BankAccountTable transforms: cased

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
AccountIdproject
CurrentAccountNumproject
FinOpsAppIdproject
LogCreatedDateTimeproject
LogTypeproject
OldAccountNumproject
TableNameproject
TimeGeneratedproject
Usernameproject