Detection rules › Sublime MQL

Reconnaissance: Short generic greeting message

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

Detects potential reconnaissance messages with very short, generic content like 'Hi' or 'Hello' from external senders. These messages are often used to validate email addresses and test deliverability before launching larger attacks.

Threat classification

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

CategoryValues
Attack typesBEC/Fraud, Callback Phishing
Tactics and techniquesSocial engineering, Free email provider

Event coverage

Rule body MQL

type.inbound
// detect generic greetings
and length(body.current_thread.text) <= 20
and length(subject.base) <= 15
// exclude messages with previous thread context (forwards/replies)
and length(body.previous_threads) == 0
and (
  any(ml.nlu_classifier(body.current_thread.text).entities, .name == "greeting")
  or strings.ilike(body.current_thread.text, "*hi*", "*hello*", "*hey*")
  or length(body.current_thread.text) <= 5
  or regex.match(body.current_thread.text, '\d+')
)
// external freemail sender
and sender.email.domain.root_domain in $free_email_providers
and sender.email.domain.root_domain not in (
  recipients.to[0].email.domain.root_domain
)
and (
  length(recipients.cc) == 0
  or (
    length(recipients.cc) > 0
    and all(recipients.cc,
            .email.domain.root_domain != sender.email.domain.root_domain
    )
  )
)
and (
  length(recipients.bcc) == 0
  or (
    length(recipients.bcc) > 0
    and all(recipients.bcc,
            .email.domain.root_domain != sender.email.domain.root_domain
    )
  )
)
// no attachments or links
and length(attachments) == 0
and length(body.current_thread.links) == 0

// not where the sender and mailbox display_anames indicate this might be a personal email --> work email
// impersonation is covered by other core feed rules
and not (
  sum([length(recipients.to), length(recipients.bcc), length(recipients.cc)]) == 1
  // use coalesce to deal with either the sender.display_name or the mailbox element being null
  // if either are null, the function returns false, as it cannot be true if either is null
  and coalesce(strings.icontains(sender.display_name, mailbox.first_name),
               false
  )
  and coalesce(strings.icontains(sender.display_name, mailbox.last_name), false)
)
and (
  // auth failed (or absent) - ignore the profile
  coalesce(headers.auth_summary.dmarc.pass, false) == false
  or coalesce(headers.auth_summary.spf.pass, false) == false
  // auth passed - use the profile
  or (
    // no benign messages
    not profile.by_sender_email().any_messages_benign
    and (
      // not soliticed OR common
      not (
        profile.by_sender_email().solicited
        or profile.by_sender_email().prevalence == "common"
      )
      // or HAS been spam_malicious
      or profile.by_sender_email().any_messages_malicious_or_spam
    )
  )
)

Detection logic

Scope: inbound message.

Detects potential reconnaissance messages with very short, generic content like 'Hi' or 'Hello' from external senders. These messages are often used to validate email addresses and test deliverability before launching larger attacks.

  1. inbound message
  2. length(body.current_thread.text) ≤ 20
  3. length(subject.base) ≤ 15
  4. length(body.previous_threads) is 0
  5. any of:
    • any of ml.nlu_classifier(body.current_thread.text).entities where:
      • .name is 'greeting'
    • body.current_thread.text matches any of 3 patterns
      • *hi*
      • *hello*
      • *hey*
    • length(body.current_thread.text) ≤ 5
    • body.current_thread.text matches '\\d+'
  6. sender.email.domain.root_domain in $free_email_providers
  7. sender.email.domain.root_domain not in (recipients.to[0].email.domain.root_domain)
  8. any of:
    • length(recipients.cc) is 0
    • all of:
      • length(recipients.cc) > 0
      • all of recipients.cc where:
        • .email.domain.root_domain is not sender.email.domain.root_domain
  9. any of:
    • length(recipients.bcc) is 0
    • all of:
      • length(recipients.bcc) > 0
      • all of recipients.bcc where:
        • .email.domain.root_domain is not sender.email.domain.root_domain
  10. length(attachments) is 0
  11. length(body.current_thread.links) is 0
  12. not:
    • all of:
      • sum([length(recipients.to), length(recipients.bcc), length(recipients.cc)]) is 1
      • coalesce(strings.icontains(sender.display_name, mailbox.first_name))
      • coalesce(strings.icontains(sender.display_name, mailbox.last_name))
  13. any of:
    • coalesce(headers.auth_summary.dmarc.pass) is False
    • coalesce(headers.auth_summary.spf.pass) is False
    • all of:
      • not:
        • profile.by_sender_email().any_messages_benign
      • any of:
        • none of:
          • profile.by_sender_email().solicited
          • profile.by_sender_email().prevalence is 'common'
        • profile.by_sender_email().any_messages_malicious_or_spam

Inspects: body.current_thread.links, body.current_thread.text, body.previous_threads, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, mailbox.first_name, mailbox.last_name, recipients.bcc, recipients.bcc[].email.domain.root_domain, recipients.cc, recipients.cc[].email.domain.root_domain, recipients.to, recipients.to[0].email.domain.root_domain, sender.display_name, sender.email.domain.root_domain, subject.base, type.inbound. Sensors: ml.nlu_classifier, profile.by_sender_email, regex.match, strings.icontains, strings.ilike. Reference lists: $free_email_providers.

Indicators matched (5)

FieldMatchValue
ml.nlu_classifier(body.current_thread.text).entities[].nameequalsgreeting
strings.ilikesubstring*hi*
strings.ilikesubstring*hello*
strings.ilikesubstring*hey*
regex.matchregex\d+