Detection rules › Kusto

Malicious BEC Inbox Rule

Severity
medium
Time window
1d
Group by
ClientIPAddress, Keyword, OfficeObjectId, Operation, OriginatingServer, ResultStatus, RuleDetail, UserId
Source
github.com/Azure/Azure-Sentinel

'Often times after the initial compromise in a BEC attack the attackers create inbox rules to delete emails that contain certain keywords related to their BEC attack. This is done so as to limit ability to warn compromised users that they've been compromised.

MITRE ATT&CK coverage

Telemetry coverage

Rules detecting the same action

These rules filter on the same operation.

Rule body

id: 8ac77493-3cae-4840-8634-15fb23f8fb68
name: Malicious BEC Inbox Rule
description: |
  'Often times after the initial compromise in a BEC attack the attackers create inbox rules to delete emails that contain certain keywords related to their BEC attack.
   This is done so as to limit ability to warn compromised users that they've been compromised. 
severity: Medium
requiredDataConnectors:
  - connectorId: Office365
    dataTypes:
      - OfficeActivity
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Persistence
  - DefenseEvasion
relevantTechniques:
  - T1098
  - T1078
tags:
  - BEC
query: |
 let BEC_Keywords = dynamic([ 'invoice','payment','paycheck','transfer','bank statement','bank details','closing','funds','bank account','account details','remittance','purchase','deposit',"PO#","Zahlung","Rechnung","Paiement", "virement bancaire","Bankuberweisung",'hacked','phishing']);
 OfficeActivity
 | where Operation =~ "New-InboxRule"
 | where Parameters has "Deleted Items" or Parameters has "Junk Email"  or Parameters has "DeleteMessage"
 | extend Events=todynamic(Parameters)
 | parse Events  with * "SubjectContainsWords" SubjectContainsWords '}'*
 | parse Events  with * "BodyContainsWords" BodyContainsWords '}'*
 | parse Events  with * "SubjectOrBodyContainsWords" SubjectOrBodyContainsWords '}'*
 | where SubjectContainsWords has_any (BEC_Keywords)
  or BodyContainsWords has_any (BEC_Keywords)
  or SubjectOrBodyContainsWords has_any (BEC_Keywords)
 | extend ClientIPAddress = case( ClientIP has ".", tostring(split(ClientIP,":")[0]), ClientIP has "[", tostring(trim_start(@'[[]',tostring(split(ClientIP,"]")[0]))), ClientIP )
 | extend Keyword = iff(isnotempty(SubjectContainsWords), SubjectContainsWords, (iff(isnotempty(BodyContainsWords),BodyContainsWords,SubjectOrBodyContainsWords )))
 | extend RuleDetail = case(OfficeObjectId contains '/' , tostring(split(OfficeObjectId, '/')[-1]) , tostring(split(OfficeObjectId, '\\')[-1]))
 | summarize count(), StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated) by  Operation, UserId, ClientIPAddress, ResultStatus, Keyword, OriginatingServer, OfficeObjectId, RuleDetail
 | extend UserName = split(UserId, '@')[0], DomainName = split(UserId, '@')[1]
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: UserId
      - identifier: Name
        columnName: UserName
      - identifier: UPNSuffix
        columnName: DomainName
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: ClientIPAddress
version: 1.0.2
kind: Scheduled

Stages and Predicates

Let binding: BEC_Keywords used in Stage 8

let BEC_Keywords = dynamic([ 'invoice','payment','paycheck','transfer','bank statement','bank details','closing','funds','bank account','account details','remittance','purchase','deposit',"PO#","Zahlung","Rechnung","Paiement", "virement bancaire","Bankuberweisung",'hacked','phishing']);

Stage 1: source

OfficeActivity

Stage 2: where

| where Operation =~ "New-InboxRule"

Stage 3: where

| where Parameters has "Deleted Items" or Parameters has "Junk Email"  or Parameters has "DeleteMessage"

Stage 4: extend

| extend Events=todynamic(Parameters)

Stage 5: parse

| parse Events  with * "SubjectContainsWords" SubjectContainsWords '}'*

Stage 6: parse

| parse Events  with * "BodyContainsWords" BodyContainsWords '}'*

Stage 7: parse

| parse Events  with * "SubjectOrBodyContainsWords" SubjectOrBodyContainsWords '}'*

Stage 8: where

| where SubjectContainsWords has_any (BEC_Keywords)
 or BodyContainsWords has_any (BEC_Keywords)
 or SubjectOrBodyContainsWords has_any (BEC_Keywords)

Stage 9: extend (3 consecutive steps)

| extend ClientIPAddress = case( ClientIP has ".", tostring(split(ClientIP,":")[0]), ClientIP has "[", tostring(trim_start(@'[[]',tostring(split(ClientIP,"]")[0]))), ClientIP )
| extend Keyword = iff(isnotempty(SubjectContainsWords), SubjectContainsWords, (iff(isnotempty(BodyContainsWords),BodyContainsWords,SubjectOrBodyContainsWords )))
| extend RuleDetail = case(OfficeObjectId contains '/' , tostring(split(OfficeObjectId, '/')[-1]) , tostring(split(OfficeObjectId, '\\')[-1]))
ClientIPAddress =
ifClientIP has "."tostring(split(ClientIP, ":")[0])
elifClientIP has "["tostring(trim_start(@'[[]', tostring(split(ClientIP, "]")[0])))
elseClientIP

Stage 10: summarize

| summarize count(), StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated) by  Operation, UserId, ClientIPAddress, ResultStatus, Keyword, OriginatingServer, OfficeObjectId, RuleDetail

Stage 11: extend

| extend UserName = split(UserId, '@')[0], DomainName = split(UserId, '@')[1]

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
BodyContainsWordsmatch
  • Bankuberweisung transforms: term
  • PO# transforms: term
  • Paiement transforms: term
  • Rechnung transforms: term
  • Zahlung transforms: term
  • account details transforms: term
  • bank account transforms: term
  • bank details transforms: term
  • bank statement transforms: term
  • closing transforms: term
  • deposit transforms: term
  • funds transforms: term
  • hacked transforms: term
  • invoice transforms: term
  • paycheck transforms: term
  • payment transforms: term
  • phishing transforms: term
  • purchase transforms: term
  • remittance transforms: term
  • transfer transforms: term
  • virement bancaire transforms: term
field:"BodyContainsWords" kind:match
Operationeq
  • New-InboxRule
field:"Operation" kind:eq value:"New-InboxRule"
Parametersmatch
  • DeleteMessage transforms: term
  • Deleted Items transforms: term
  • Junk Email transforms: term
field:"m365::Parameters" kind:match
SubjectContainsWordsmatch
  • Bankuberweisung transforms: term
  • PO# transforms: term
  • Paiement transforms: term
  • Rechnung transforms: term
  • Zahlung transforms: term
  • account details transforms: term
  • bank account transforms: term
  • bank details transforms: term
  • bank statement transforms: term
  • closing transforms: term
  • deposit transforms: term
  • funds transforms: term
  • hacked transforms: term
  • invoice transforms: term
  • paycheck transforms: term
  • payment transforms: term
  • phishing transforms: term
  • purchase transforms: term
  • remittance transforms: term
  • transfer transforms: term
  • virement bancaire transforms: term
field:"SubjectContainsWords" kind:match
SubjectOrBodyContainsWordsmatch
  • Bankuberweisung transforms: term
  • PO# transforms: term
  • Paiement transforms: term
  • Rechnung transforms: term
  • Zahlung transforms: term
  • account details transforms: term
  • bank account transforms: term
  • bank details transforms: term
  • bank statement transforms: term
  • closing transforms: term
  • deposit transforms: term
  • funds transforms: term
  • hacked transforms: term
  • invoice transforms: term
  • paycheck transforms: term
  • payment transforms: term
  • phishing transforms: term
  • purchase transforms: term
  • remittance transforms: term
  • transfer transforms: term
  • virement bancaire transforms: term
field:"SubjectOrBodyContainsWords" kind:match

Output fields

These fields are emitted when the rule matches.

FieldSource
ClientIPAddresssummarize
EndTimeUtcsummarize
Keywordsummarize
OfficeObjectIdsummarize
Operationsummarize
OriginatingServersummarize
ResultStatussummarize
RuleDetailsummarize
StartTimeUtcsummarize
UserIdsummarize
DomainNameextend
UserNameextend