Detection rules › Sublime MQL

Business Email Compromise (BEC) with request for mobile number

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

This rule detects unsolicited messages with a small plain text body, that is attempting to solicit a mobile number.

Threat classification

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

CategoryValues
Attack typesBEC/Fraud
Tactics and techniquesSocial engineering

Event coverage

Rule body MQL

type.inbound
and (
  length(body.current_thread.text) < 500
  or any(map(filter(ml.nlu_classifier(body.current_thread.text).entities,
                    .name == "disclaimer"
             ),
             .text
         ),
         (length(body.current_thread.text) - length(.)) < 500
  )
)
and length(attachments) == 0
and regex.icontains(body.current_thread.text,
                    '(?:mobile|contact|current|reliable).{0,10}(?:phone|number|#|\bno)|whatsapp|\bcell|personalcell|(?:share|what).{0,25}number.{0,15}(?:connect|reach|text|message|contact|call)|(?:\bdrop|which|send.{0,5}your|best).{0,25}(?:number|\bnum\b|#).{0,15}(?:(?:connect|reach|contact|call).{0,5}you|text|message|works?\b|stay connected)|forward.{0,25}(?:\bnum\b|#)|get (?:your.{0,25}(?:number|\bnum\b|#)|in touch.{0,15}(?:via|by|through).{0,10}(?:text|phone|cell|sms|whatsapp))|(?:provide|confirm|reply.{0,15}with).{0,25}(?:direct|preferred).{0,15}(?:text.?enabled.{0,15})?(?:phone.{0,5})?(?:number|\bnum\b|#|line)|(?:share|send).{0,25}(?:direct|preferred).{0,15}(?:text.?enabled.{0,15})?(?:phone.{0,5})(?:number|\bnum\b|#|line)|(?:share|send).{0,25}preferred.{0,15}(?:text.?enabled.{0,15})?(?:number|\bnum\b|#|line)|(?:direct|preferred).{0,15}line.{0,15}(?:for|to|via).{0,10}(?:text|call|reach|contact|sms)|have.{0,15}preferred.{0,10}number'
)
and (
  any(ml.nlu_classifier(body.current_thread.text).intents,
      .name in ("bec", "advance_fee") and .confidence != "low"
  )
  or (
    // confidence can be low on very short bodies
    length(body.current_thread.text) < 550
    and (
      any(ml.nlu_classifier(body.current_thread.text).intents, .name == "bec")
      or any(ml.nlu_classifier(sender.display_name).intents, .name == "bec")
      or any(ml.nlu_classifier(body.current_thread.text).entities,
             strings.icontains(.text, "kindly")
      )
    )
  )
)
and (
  (
    (length(headers.references) > 0 or headers.in_reply_to is null)
    and not (
      (
        strings.istarts_with(subject.subject, "RE:")
        or strings.istarts_with(subject.subject, "RES:")
        or strings.istarts_with(subject.subject, "R:")
        or strings.istarts_with(subject.subject, "ODG:")
        or strings.istarts_with(subject.subject, "答复:")
        or strings.istarts_with(subject.subject, "AW:")
        or strings.istarts_with(subject.subject, "TR:")
        or strings.istarts_with(subject.subject, "FWD:")
        or regex.imatch(subject.subject,
                        '(\[[^\]]+\]\s?){0,3}(re|fwd?|automat.*)\s?:.*'
        )
      )
    )
  )
  or length(headers.references) == 0
)
and (
  not profile.by_sender().solicited
  or profile.by_sender().any_messages_malicious_or_spam
)
and not profile.by_sender().any_messages_benign

Detection logic

Scope: inbound message.

This rule detects unsolicited messages with a small plain text body, that is attempting to solicit a mobile number.

  1. inbound message
  2. any of:
    • length(body.current_thread.text) < 500
    • any of map(...) where:
      • length(body.current_thread.text) - length(.) < 500
  3. length(attachments) is 0
  4. body.current_thread.text matches '(?:mobile|contact|current|reliable).{0,10}(?:phone|number|#|\\bno)|whatsapp|\\bcell|personalcell|(?:share|what).{0,25}number.{0,15}(?:connect|reach|text|message|contact|call)|(?:\\bdrop|which|send.{0,5}your|best).{0,25}(?:number|\\bnum\\b|#).{0,15}(?:(?:connect|reach|contact|call).{0,5}you|text|message|works?\\b|stay connected)|forward.{0,25}(?:\\bnum\\b|#)|get (?:your.{0,25}(?:number|\\bnum\\b|#)|in touch.{0,15}(?:via|by|through).{0,10}(?:text|phone|cell|sms|whatsapp))|(?:provide|confirm|reply.{0,15}with).{0,25}(?:direct|preferred).{0,15}(?:text.?enabled.{0,15})?(?:phone.{0,5})?(?:number|\\bnum\\b|#|line)|(?:share|send).{0,25}(?:direct|preferred).{0,15}(?:text.?enabled.{0,15})?(?:phone.{0,5})(?:number|\\bnum\\b|#|line)|(?:share|send).{0,25}preferred.{0,15}(?:text.?enabled.{0,15})?(?:number|\\bnum\\b|#|line)|(?:direct|preferred).{0,15}line.{0,15}(?:for|to|via).{0,10}(?:text|call|reach|contact|sms)|have.{0,15}preferred.{0,10}number'
  5. any of:
    • any of ml.nlu_classifier(body.current_thread.text).intents where all hold:
      • .name in ('bec', 'advance_fee')
      • .confidence is not 'low'
    • all of:
      • length(body.current_thread.text) < 550
      • any of:
        • any of ml.nlu_classifier(body.current_thread.text).intents where:
          • .name is 'bec'
        • any of ml.nlu_classifier(sender.display_name).intents where:
          • .name is 'bec'
        • any of ml.nlu_classifier(body.current_thread.text).entities where:
          • .text contains 'kindly'
  6. any of:
    • all of:
      • any of:
        • length(headers.references) > 0
        • headers.in_reply_to is missing
      • none of:
        • subject.subject starts with 'RE:'
        • subject.subject starts with 'RES:'
        • subject.subject starts with 'R:'
        • subject.subject starts with 'ODG:'
        • subject.subject starts with '答复:'
        • subject.subject starts with 'AW:'
        • subject.subject starts with 'TR:'
        • subject.subject starts with 'FWD:'
        • subject.subject matches '(\\[[^\\]]+\\]\\s?){0,3}(re|fwd?|automat.*)\\s?:.*'
    • length(headers.references) is 0
  7. any of:
    • not:
      • profile.by_sender().solicited
    • profile.by_sender().any_messages_malicious_or_spam
  8. not:
    • profile.by_sender().any_messages_benign

Inspects: body.current_thread.text, headers.in_reply_to, headers.references, sender.display_name, subject.subject, type.inbound. Sensors: ml.nlu_classifier, profile.by_sender, regex.icontains, regex.imatch, strings.icontains, strings.istarts_with.

Indicators matched (16)

FieldMatchValue
ml.nlu_classifier(body.current_thread.text).entities[].nameequalsdisclaimer
regex.icontainsregex(?:mobile|contact|current|reliable).{0,10}(?:phone|number|#|\bno)|whatsapp|\bcell|personalcell|(?:share|what).{0,25}number.{0,15}(?:connect|reach|text|message|contact|call)|(?:\bdrop|which|send.{0,5}your|best).{0,25}(?:number|\bnum\b|#).{0,15}(?:(?:connect|reach|contact|call).{0,5}you|text|message|works?\b|stay connected)|forward.{0,25}(?:\bnum\b|#)|get (?:your.{0,25}(?:number|\bnum\b|#)|in touch.{0,15}(?:via|by|through).{0,10}(?:text|phone|cell|sms|whatsapp))|(?:provide|confirm|reply.{0,15}with).{0,25}(?:direct|preferred).{0,15}(?:text.?enabled.{0,15})?(?:phone.{0,5})?(?:number|\bnum\b|#|line)|(?:share|send).{0,25}(?:direct|preferred).{0,15}(?:text.?enabled.{0,15})?(?:phone.{0,5})(?:number|\bnum\b|#|line)|(?:share|send).{0,25}preferred.{0,15}(?:text.?enabled.{0,15})?(?:number|\bnum\b|#|line)|(?:direct|preferred).{0,15}line.{0,15}(?:for|to|via).{0,10}(?:text|call|reach|contact|sms)|have.{0,15}preferred.{0,10}number
ml.nlu_classifier(body.current_thread.text).intents[].namememberbec
ml.nlu_classifier(body.current_thread.text).intents[].namememberadvance_fee
ml.nlu_classifier(body.current_thread.text).intents[].nameequalsbec
ml.nlu_classifier(sender.display_name).intents[].nameequalsbec
strings.icontainssubstringkindly
strings.istarts_withprefixRE:
strings.istarts_withprefixRES:
strings.istarts_withprefixR:
strings.istarts_withprefixODG:
strings.istarts_withprefix答复:
4 more
strings.istarts_withprefixAW:
strings.istarts_withprefixTR:
strings.istarts_withprefixFWD:
regex.imatchregex(\[[^\]]+\]\s?){0,3}(re|fwd?|automat.*)\s?:.*