Detection rules › Sublime MQL

Sublime MQL rules: francais

Business Email Compromise (BEC) attempt from untrusted sender (French/Français)

#
Severity
medium
Type
rule
Source
github.com/sublime-security/sublime-rules

Detects potential Business Email Compromise (BEC) attacks by searching for common French BEC language within the email body from first-time senders.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesBEC/Fraud
Tactics and techniquesSocial engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • headers
  • headers.auth_summary
  • sender.email
  • subject
  • type

Rule body

type.inbound
and length(body.links) == 0
and ml.nlu_classifier(body.current_thread.text).language == "french"
and 1 of (
  regex.icontains(subject.subject,
                  '(mise (a|à) jour|changé|changement).{0,20}(bancaire|de banque)'
  ),
  regex.icontains(body.current_thread.text,
                  '(changement|changé) de (banque)|changement bancaire|coordonnées.{0,20}(compte|banque|bancaire|salaire)',
  ),
  (regex.icontains(body.current_thread.text, 'parler.{0,20}confiance'))
)
// negating legit replies
and not (
  (
    strings.istarts_with(subject.subject, "RE:")
    // out of office auto-reply
    // the NLU model will handle these better natively soon
    or strings.istarts_with(subject.subject, "Automatic reply:")
    or regex.imatch(subject.subject,
                    '(\[[^\]]+\]\s?){0,3}(re|fwd?|automat.*)\s?:.*'
    )
  )
  and (length(headers.references) > 0 or headers.in_reply_to is not null)
)
and (
  not profile.by_sender().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 not headers.auth_summary.dmarc.pass
  )
  or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)

Detection logic

Scope: inbound message.

Detects potential Business Email Compromise (BEC) attacks by searching for common French BEC language within the email body from first-time senders.

  1. inbound message
  2. length(body.links) is 0
  3. ml.nlu_classifier(body.current_thread.text).language is 'french'
  4. at least 1 of:
    • subject.subject matches '(mise (a|à) jour|changé|changement).{0,20}(bancaire|de banque)'
    • body.current_thread.text matches '(changement|changé) de (banque)|changement bancaire|coordonnées.{0,20}(compte|banque|bancaire|salaire)'
    • body.current_thread.text matches 'parler.{0,20}confiance'
  5. not:
    • all of:
      • any of:
        • subject.subject starts with 'RE:'
        • subject.subject starts with 'Automatic reply:'
        • subject.subject matches '(\\[[^\\]]+\\]\\s?){0,3}(re|fwd?|automat.*)\\s?:.*'
      • any of:
        • length(headers.references) > 0
        • headers.in_reply_to is set
  6. any of:
    • not:
      • profile.by_sender().solicited
    • all of:
      • profile.by_sender().any_messages_malicious_or_spam
      • not:
        • profile.by_sender().any_messages_benign
  7. any of:
    • all of:
      • sender.email.domain.root_domain in $high_trust_sender_root_domains
      • not:
        • headers.auth_summary.dmarc.pass
    • sender.email.domain.root_domain not in $high_trust_sender_root_domains

Inspects: body.current_thread.text, body.links, headers.auth_summary.dmarc.pass, headers.in_reply_to, headers.references, sender.email.domain.root_domain, subject.subject, type.inbound. Sensors: ml.nlu_classifier, profile.by_sender, regex.icontains, regex.imatch, strings.istarts_with. Reference lists: $high_trust_sender_root_domains.

Indicators matched (3)

FieldMatchValue
regex.icontainsregex(mise (a|à) jour|changé|changement).{0,20}(bancaire|de banque)
regex.icontainsregex(changement|changé) de (banque)|changement bancaire|coordonnées.{0,20}(compte|banque|bancaire|salaire)
regex.icontainsregexparler.{0,20}confiance

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      not
        headers.auth_summary.dmarc.pass eq "true"
       macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
     macro "sender.email.domain.root_domain not in high_trust_sender_root_domains"
  not
    and
      or
        headers.in_reply_to is_not_null
        headers.references length_compare "0"
      or
        subject.subject regex_match "(\\[[^\\]]+\\]\\s?){0,3}(re|fwd?|automat.*)\\s?:.*"
        subject.subject starts_with "Automatic reply:"
        subject.subject starts_with "RE:"
  or
    and
      not
        profile.by_sender func_call "profile.by_sender().any_messages_benign"
      profile.by_sender func_call "profile.by_sender().any_messages_malicious_or_spam"
    not
      profile.by_sender func_call "profile.by_sender().solicited"
  or
    body.current_thread.text regex_match "(changement|changé) de (banque)|changement bancaire|coordonnées.{0,20}(compte|banque|bancaire|salaire)"
    body.current_thread.text regex_match "parler.{0,20}confiance"
    subject.subject regex_match "(mise (a|à) jour|changé|changement).{0,20}(bancaire|de banque)"
  body.links length_compare "0"
  ml.nlu_classifier func_call "ml.nlu_classifier(body.current_thread.text).language == french"
  type.inbound eq "true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
headers.in_reply_tois_not_null(no value, null check)excludes:headers.in_reply_to
headers.referenceslength_compare0excludes:headers.references field:"headers.references" value:"0"
subject.subjectregex_match([[^]]+]\s?){0,3}(re|fwd?|automat.*)\s?:.*excludes:subject.subject field:"subject.subject" value:"([[^]]+]\s?){0,3}(re|fwd?|automat.*)\s?:.*"
subject.subjectstarts_withAutomatic reply:excludes:subject.subject field:"subject.subject" value:"Automatic reply:"
subject.subjectstarts_withRE:excludes:subject.subject field:"subject.subject" value:"RE:"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textregex_match
    • (changement|changé) de (banque)
    • changement bancaire
    • coordonnées.{0,20}(compte|banque|bancaire|salaire)
  • parler.{0,20}confiance
field:"body.current_thread.text" kind:regex_match
subject.subjectregex_match
  • (mise (a|à) jour|changé|changement).{0,20}(bancaire|de banque)
field:"subject.subject" kind:regex_match value:"(mise (a|à) jour|changé|changement).{0,20}(bancaire|de banque)"
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"