EXPLORE
← Back to Explore
sublimehighRule

Employee impersonation: Payroll fraud

This rule detects messages impersonating employees, from unsolicited senders attempting to reroute payroll or alter payment details.

MITRE ATT&CK

initial-access

Detection Query

type.inbound
// ensure the display name contains a space to avoid single named process accounts eg. 'billing, payment'
and strings.contains(sender.display_name, " ")
and (
  sender.display_name in~ $org_display_names
  or subject.base in~ $org_display_names
)
and length(attachments) == 0
and length(body.links) < 10
and (
  length(body.current_thread.text) < 800
  or (
    any(map(filter(ml.nlu_classifier(body.current_thread.text).entities,
                   .name == "disclaimer"
            ),
            .text
        ),
        (length(body.current_thread.text) - length(.)) < 800
    )
  )
)
and (
  sender.email.domain.root_domain not in $org_domains
  or sender.email.domain.root_domain in $free_email_providers
)
and 1 of (
  regex.icontains(body.current_thread.text,
                  '(?:pay\s?(?:roll|check|date|day)|direct deposit|(?:acct|account) rephrase|paid.{0,50}problems|\bACH\b|\bdd\b|gehalt|salario|salary|employee self[-\s]?service|\bESS\b.{0,30}(?:portal|access|log[-\s]?in)|access.{0,30}(?:HR|employee).{0,30}portal)'
  ),
  regex.icontains(subject.subject,
                  '(?:pay\s?(?:roll|check|date|day)|direct deposit|(?:acct|account) rephrase|paid.{0,50}problems|\bACH\b|\bdd\b|gehalt|salario|salary|employee self[-\s]?service|\bESS\b.{0,15}portal)'
  )
)

// sender profile negations
and (
  not profile.by_sender_email().solicited
  or profile.by_sender().any_messages_malicious_or_spam
)
and not profile.by_sender().any_messages_benign

// negate highly trusted sender domains unless they fail DMARC authentication
and (
  (
    sender.email.domain.root_domain in $high_trust_sender_root_domains
    and (
      any(distinct(headers.hops, .authentication_results.dmarc is not null),
          strings.ilike(.authentication_results.dmarc, "*fail")
      )
    )
  )
  or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)

// negate legitimate conversations
and not (
  (
    length(headers.references) > 0
    or headers.in_reply_to is not null
    or (
      any(headers.hops,
          any(.fields,
              strings.ilike(.name, "x-autoreply")
              and strings.ilike(.value, "yes")
          )
      )
    )
  )
  // previous thread present
  and (
    (
      (subject.is_forward or subject.is_reply)
      and length(body.previous_threads) >= 1
    )
    // automatic reply structure
    or (
      strings.istarts_with(subject.base, "automatic reply")
      or strings.istarts_with(subject.base, "out of office")
    )
  )
)

// ignore personal <> work emails
and not (
  length(recipients.to) == 1
  and sender.email.domain.valid
  and all(headers.reply_to, .email.email == sender.email.email)
  and sender.display_name == mailbox.display_name
)

// topic negations
and not any(ml.nlu_classifier(body.current_thread.text).topics,
            .name == "Advertising and Promotions"
)

Data Sources

Email MessagesEmail HeadersEmail Attachments

Platforms

email
Raw Content
name: "Employee impersonation: Payroll fraud"
description: |
  This rule detects messages impersonating employees, from unsolicited senders attempting to reroute payroll
  or alter payment details.
type: "rule"
severity: "high"
source: |
  type.inbound
  // ensure the display name contains a space to avoid single named process accounts eg. 'billing, payment'
  and strings.contains(sender.display_name, " ")
  and (
    sender.display_name in~ $org_display_names
    or subject.base in~ $org_display_names
  )
  and length(attachments) == 0
  and length(body.links) < 10
  and (
    length(body.current_thread.text) < 800
    or (
      any(map(filter(ml.nlu_classifier(body.current_thread.text).entities,
                     .name == "disclaimer"
              ),
              .text
          ),
          (length(body.current_thread.text) - length(.)) < 800
      )
    )
  )
  and (
    sender.email.domain.root_domain not in $org_domains
    or sender.email.domain.root_domain in $free_email_providers
  )
  and 1 of (
    regex.icontains(body.current_thread.text,
                    '(?:pay\s?(?:roll|check|date|day)|direct deposit|(?:acct|account) rephrase|paid.{0,50}problems|\bACH\b|\bdd\b|gehalt|salario|salary|employee self[-\s]?service|\bESS\b.{0,30}(?:portal|access|log[-\s]?in)|access.{0,30}(?:HR|employee).{0,30}portal)'
    ),
    regex.icontains(subject.subject,
                    '(?:pay\s?(?:roll|check|date|day)|direct deposit|(?:acct|account) rephrase|paid.{0,50}problems|\bACH\b|\bdd\b|gehalt|salario|salary|employee self[-\s]?service|\bESS\b.{0,15}portal)'
    )
  )
  
  // sender profile negations
  and (
    not profile.by_sender_email().solicited
    or profile.by_sender().any_messages_malicious_or_spam
  )
  and not profile.by_sender().any_messages_benign
  
  // negate highly trusted sender domains unless they fail DMARC authentication
  and (
    (
      sender.email.domain.root_domain in $high_trust_sender_root_domains
      and (
        any(distinct(headers.hops, .authentication_results.dmarc is not null),
            strings.ilike(.authentication_results.dmarc, "*fail")
        )
      )
    )
    or sender.email.domain.root_domain not in $high_trust_sender_root_domains
  )
  
  // negate legitimate conversations
  and not (
    (
      length(headers.references) > 0
      or headers.in_reply_to is not null
      or (
        any(headers.hops,
            any(.fields,
                strings.ilike(.name, "x-autoreply")
                and strings.ilike(.value, "yes")
            )
        )
      )
    )
    // previous thread present
    and (
      (
        (subject.is_forward or subject.is_reply)
        and length(body.previous_threads) >= 1
      )
      // automatic reply structure
      or (
        strings.istarts_with(subject.base, "automatic reply")
        or strings.istarts_with(subject.base, "out of office")
      )
    )
  )
  
  // ignore personal <> work emails
  and not (
    length(recipients.to) == 1
    and sender.email.domain.valid
    and all(headers.reply_to, .email.email == sender.email.email)
    and sender.display_name == mailbox.display_name
  )
  
  // topic negations
  and not any(ml.nlu_classifier(body.current_thread.text).topics,
              .name == "Advertising and Promotions"
  )

attack_types:
  - "BEC/Fraud"
tactics_and_techniques:
  - "Impersonation: Employee"
  - "Free email provider"
  - "Social engineering"
detection_methods:
  - "Content analysis"
  - "Sender analysis"
id: "2beb7d85-dfe3-5ecc-9b2a-d7416a3ef992"