Detection rules › Kusto

ProofpointPOD - Multiple protected emails to unknown recipient

Status
available
Severity
medium
Time window
30m
Group by
SrcUserUpn
Source
github.com/Azure/Azure-Sentinel

'Detects when multiple protected messages where sent to early not seen recipient.'

MITRE ATT&CK coverage

TacticTechniques
ExfiltrationT1567 Exfiltration Over Web Service

Rule body kusto

id: f8127962-7739-4211-a4a9-390a7a00e91f
name: ProofpointPOD - Multiple protected emails to unknown recipient
description: |
  'Detects when multiple protected messages where sent to early not seen recipient.'
severity: Medium
status: Available 
requiredDataConnectors:
  - connectorId: ProofpointPOD
    dataTypes:
      - ProofpointPOD_message_CL
queryFrequency: 30m
queryPeriod: 30m
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Exfiltration
relevantTechniques:
- T1567
query: |
  let lbtime = 30m;
  let lbperiod = 14d;
  let knownrecipients = ProofpointPOD
  | where TimeGenerated > ago(lbperiod)
  | where EventType == 'message'
  | where NetworkDirection == 'outbound'
  | where SrcUserUpn != ''
  | where array_length(todynamic(DstUserUpn)) == 1
  | summarize recipients = make_set(tostring(todynamic(DstUserUpn)[0])) by SrcUserUpn
  | extend commcol = SrcUserUpn;
  ProofpointPOD
  | where TimeGenerated between (ago(lbtime) .. now())
  | where EventType == 'message'
  | where NetworkDirection == 'outbound'
  | extend isProtected = todynamic(MsgParts)[0]['isProtected']
  | extend mimePgp = todynamic(MsgParts)[0]['detectedMime']
  | where isProtected == 'true' or mimePgp == 'application/pgp-encrypted'
  | extend DstUserMail = tostring(todynamic(DstUserUpn)[0])
  | extend commcol = tostring(todynamic(DstUserUpn)[0])
  | join knownrecipients on commcol
  | where recipients !contains DstUserMail
  | project SrcUserUpn, DstUserMail
  | extend AccountCustomEntity = SrcUserUpn
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: AccountCustomEntity
version: 1.1.1
kind: Scheduled

Stages and Predicates

Parameters

let lbtime = 30m;
let lbperiod = 14d;

Let binding: knownrecipients

let knownrecipients = ProofpointPOD
| where TimeGenerated > ago(lbperiod)
| where EventType == 'message'
| where NetworkDirection == 'outbound'
| where SrcUserUpn != ''
| where array_length(todynamic(DstUserUpn)) == 1
| summarize recipients = make_set(tostring(todynamic(DstUserUpn)[0])) by SrcUserUpn
| extend commcol = SrcUserUpn;

Derived from lbperiod.

Stage 1: source

ProofpointPOD

Stage 2: where

| where TimeGenerated between (ago(lbtime) .. now())

Stage 3: where

| where EventType == 'message'

Stage 4: where

| where NetworkDirection == 'outbound'

Stage 5: extend

| extend isProtected = todynamic(MsgParts)[0]['isProtected']

Stage 6: extend

| extend mimePgp = todynamic(MsgParts)[0]['detectedMime']

Stage 7: where

| where isProtected == 'true' or mimePgp == 'application/pgp-encrypted'

Stage 8: extend

| extend DstUserMail = tostring(todynamic(DstUserUpn)[0])

Stage 9: extend

| extend commcol = tostring(todynamic(DstUserUpn)[0])

Stage 10: join

| join knownrecipients on commcol

Stage 11: where

| where recipients !contains DstUserMail

Stage 12: project

| project SrcUserUpn, DstUserMail

Stage 13: extend

| extend AccountCustomEntity = SrcUserUpn

Stage 14: summarize

summarize by SrcUserUpn

Exclusions

Top-level NOT(...) conjuncts: predicates this rule actively suppresses.

FieldKindExcluded values
recipientscontainsDstUserMail

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
DstUserUpneq
  • 1 transforms: array_length
EventTypeeq
  • message transforms: cased
NetworkDirectioneq
  • outbound transforms: cased
isProtectedeq
  • true transforms: cased
mimePgpeq
  • application/pgp-encrypted 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
SrcUserUpnsummarize