Detection rules › Sublime MQL

Impersonation: Internal corporate services

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

Detects phishing attempts that impersonate corporate services such as HR, helpdesk, and benefits, using specific language in the subject or sender's name and containing suspicious links from low-reputation or mass-mailing domains.

Threat classification

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

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesImpersonation: Employee, Social engineering

Event coverage

Rule body MQL

type.inbound
// use distinct "urls" (without query params) to determine number of links
and 0 < length(distinct(body.links,
                        // strip out query params to determine
                        // the unique number of links
                        strings.concat(.href_url.scheme,
                                       .href_url.domain.domain,
                                       .href_url.path
                        )
               )
) <= 8

// HR language found in subject
and (
  (
    length(subject.subject) > 20
    and regex.icontains(subject.subject,
                        '(time.{0,4}sheet)|(employ|complete|update(?:d| to| regarding our)|workplace).{0,30}(benefit|handbook|comp\b|compensation|salary|\bpay(?:roll)?\b|policy|policies|guidelines?|conduct|acknowl|PTO|vacation|assess|eval)|(HR|Human Resources).{0,5}ADM[il]N',
                        // shorten the distance to 3 or less words for the word "review"
                        // special handling of benefits
                        '\breview\b(?:\w+(?:\s\w+)?|[[:punct:]]+|\s+){0,3}(benefits?(?:$|.?(?:statement|enrollment))|handbook|comp\b|compensation|salary|bonus|\bpay(?:roll)?\b)',
                        // handle the year in the subject, and expand the distance to 5 or less words
                        '20\d{2}\b(?:\w+(?:\s\w+)?|[[:punct:]]+|\s+){0,5}(benefits?(?:$|.?(?:statement|enrollment))|handbook|comp\b|compensation|salary|bonus|\bpay(?:roll)?\b)'
    )
  )

  // or HR language found in sender
  or (
    regex.icontains(sender.display_name,
                    '(Employ|Time.{0,3}sheet|\bHR\b|Human R|Handbook|\bIT[- ]|Help.{0,3}Desk)|Internal.?Comm|Enroll?ment Service|Open Enroll?ment|Admin Support'
    )
    and not regex.icontains(sender.display_name,
                            "forum|employee voice|briefs|newsletter|screening"
    )
    and not regex.icontains(sender.display_name,
                            "HR (new|vue|view|tech admin|global)"
    )
    and not strings.icontains(sender.display_name, "get it")
  )

  // or assessment report language found in body
  or (
    regex.icontains(body.current_thread.text,
                    '20\d{2}(?:[[:punct:]](?:20)?\d{2})? (?:\w+ )?assessment report'
    )
  )

  // or HR department language found in body via NLU
  or any(ml.nlu_classifier(body.current_thread.text).entities,
         .name in ("org", "sender")
         and regex.icontains(.text,
                             '\bhr\b',
                             'human resources',
                             'operations department'
         )
  )
)

// suspicious display_text
and (
  any(body.links,
      regex.icontains(.display_text,
                      '(?:verify|view|click|download|goto|keep|Vιew|release|access|open|allow|deny|new).{0,10}(?:request|handbook|here|report|attachment|current|download|fax|file|document|message|same|doc|access|polic(?:y|ie))s?'
      )
      and not strings.ilike(.display_text, "*unsub*")
      and not strings.ilike(.display_text, "*privacy?policy*")
      and not strings.ilike(.href_url.url, "*privacy?policy*")
      and not strings.ilike(.display_text, "*REGISTER*")

      // from a low reputation link
      and (
        not .href_url.domain.root_domain in $org_domains
        and (
          (
            .href_url.domain.root_domain not in $tranco_1m
            or .href_url.domain.domain in $free_file_hosts
            or .href_url.domain.root_domain in $free_file_hosts
            or .href_url.domain.root_domain in $free_subdomain_hosts
            or .href_url.domain.domain in $url_shorteners
            or .href_url.domain.domain in $social_landing_hosts
          )
          or 
          // or mass mailer link, masks the actual URL
          .href_url.domain.root_domain in (
            "hubspotlinks.com",
            "mandrillapp.com",
            "sendgrid.net",
            "rs6.net",
            "mailanyone.net",
            "perspectivefunnel.co"
          )
        )
      )
  )
  // or credential theft confidence high
  or (
    length(body.links) > 0
    and any(ml.nlu_classifier(body.current_thread.text).intents,
            .name == "cred_theft" and .confidence == "high"
    )
    and not sender.email.domain.root_domain in (
      "servicenowservices.com",
      "workplaceextras.com",
      "tempo.io",
      "or.us",
      "proofpoint.com"
    )
  )
  or any(filter(attachments,
                .content_type == "message/rfc822" or .file_extension in ('eml')
         ),
         any(file.parse_eml(.).attachments,
             any(file.explode(.),
                 regex.icontains(.scan.ocr.raw, 'scan|camera')
                 and regex.icontains(.scan.ocr.raw, '\bQR\b|Q\.R\.|barcode')
             )
         )
  )
)
// negate messages where "click here" was found and was a link actually an unsub link
// this method allows for matching on other 'click here' links if they are present
and not (
  length(filter(body.links, strings.icontains(.display_text, 'click here'))) > 0
  and (
    length(filter(body.links, strings.icontains(.display_text, 'click here'))) == strings.icount(body.current_thread.text,
                                                                                                 'click here to unsubscribe'
    )
  )
)

// negate highly trusted sender domains unless they fail DMARC authentication
and (
  (
    (
      sender.email.domain.root_domain in $high_trust_sender_root_domains
      or sender.email.domain.root_domain in $org_domains
    )
    and not headers.auth_summary.dmarc.pass
  )
  or (
    sender.email.domain.root_domain not in $high_trust_sender_root_domains
    and sender.email.domain.root_domain not in $org_domains
  )
)
// not from sharepointonline actual
and not (
  sender.email.domain.root_domain == "sharepointonline.com"
  and strings.ends_with(headers.message_id, '@odspnotify>')
  and strings.starts_with(headers.message_id, "<Spo")
)
// netate common FP topics
and not any(beta.ml_topic(body.current_thread.text).topics,
            .name in (
              "Events and Webinars",
              "Advertising and Promotions",
              "Newsletters and Digests"
            )
            and .confidence == "high"
)
// negate common helpdesk/HR platforms
and not any(headers.domains,
            .root_domain in (
              "freshemail.io",
              "zendesk.com",
              "employeenavigator.com",
              "saashr.com" // Kronos owned Saas HR offering
            )
)
// negate observed HR newsletters
and not (
  any(headers.hops,
      strings.icontains(.authentication_results.spf_details.designator,
                        "constantcontact.com"
      )
  )
  and strings.starts_with(sender.email.local_part, 'newsletters-hr')
  and sender.email.domain.root_domain == "ccsend.com"
)
// the message is unsolicited and no false positives
and (
  not profile.by_sender_email().solicited
  or (
    profile.by_sender().any_messages_malicious_or_spam
    and not profile.by_sender().any_messages_benign
  )
  or (
    profile.by_sender().any_messages_malicious_or_spam
    and profile.by_sender().any_messages_benign
    and not (headers.auth_summary.dmarc.pass and headers.auth_summary.spf.pass)
  )
)
// negate instances where proofpoint sends a review of a reported message via analyzer
and not (
  sender.email.email == "analyzer@analyzer.securityeducation.com"
  and any(headers.domains, .root_domain == "pphosted.com")
  and headers.auth_summary.spf.pass
  and headers.auth_summary.dmarc.pass
)

Detection logic

Scope: inbound message.

Detects phishing attempts that impersonate corporate services such as HR, helpdesk, and benefits, using specific language in the subject or sender's name and containing suspicious links from low-reputation or mass-mailing domains.

  1. inbound message
  2. all of:
    • length(distinct(body.links, strings.concat(.href_url.scheme, .href_url.domain.domain, .href_url.path))) > 0
    • length(distinct(body.links, strings.concat(.href_url.scheme, .href_url.domain.domain, .href_url.path))) ≤ 8
  3. any of:
    • all of:
      • length(subject.subject) > 20
      • subject.subject matches any of 3 patterns
        • (time.{0,4}sheet)|(employ|complete|update(?:d| to| regarding our)|workplace).{0,30}(benefit|handbook|comp\b|compensation|salary|\bpay(?:roll)?\b|policy|policies|guidelines?|conduct|acknowl|PTO|vacation|assess|eval)|(HR|Human Resources).{0,5}ADM[il]N
        • \breview\b(?:\w+(?:\s\w+)?|[[:punct:]]+|\s+){0,3}(benefits?(?:$|.?(?:statement|enrollment))|handbook|comp\b|compensation|salary|bonus|\bpay(?:roll)?\b)
        • 20\d{2}\b(?:\w+(?:\s\w+)?|[[:punct:]]+|\s+){0,5}(benefits?(?:$|.?(?:statement|enrollment))|handbook|comp\b|compensation|salary|bonus|\bpay(?:roll)?\b)
    • all of:
      • sender.display_name matches '(Employ|Time.{0,3}sheet|\\bHR\\b|Human R|Handbook|\\bIT[- ]|Help.{0,3}Desk)|Internal.?Comm|Enroll?ment Service|Open Enroll?ment|Admin Support'
      • not:
        • sender.display_name matches 'forum|employee voice|briefs|newsletter|screening'
      • not:
        • sender.display_name matches 'HR (new|vue|view|tech admin|global)'
      • not:
        • sender.display_name contains 'get it'
    • body.current_thread.text matches '20\\d{2}(?:[[:punct:]](?:20)?\\d{2})? (?:\\w+ )?assessment report'
    • any of ml.nlu_classifier(body.current_thread.text).entities where all hold:
      • .name in ('org', 'sender')
      • .text matches any of 3 patterns
        • \bhr\b
        • human resources
        • operations department
  4. any of:
    • any of body.links where all hold:
      • .display_text matches '(?:verify|view|click|download|goto|keep|Vιew|release|access|open|allow|deny|new).{0,10}(?:request|handbook|here|report|attachment|current|download|fax|file|document|message|same|doc|access|polic(?:y|ie))s?'
      • not:
        • .display_text matches '*unsub*'
      • not:
        • .display_text matches '*privacy?policy*'
      • not:
        • .href_url.url matches '*privacy?policy*'
      • not:
        • .display_text matches '*REGISTER*'
      • all of:
        • not:
          • .href_url.domain.root_domain in $org_domains
        • any of:
          • any of:
            • .href_url.domain.root_domain not in $tranco_1m
            • .href_url.domain.domain in $free_file_hosts
            • .href_url.domain.root_domain in $free_file_hosts
            • .href_url.domain.root_domain in $free_subdomain_hosts
            • .href_url.domain.domain in $url_shorteners
            • .href_url.domain.domain in $social_landing_hosts
          • .href_url.domain.root_domain in ('hubspotlinks.com', 'mandrillapp.com', 'sendgrid.net', 'rs6.net', 'mailanyone.net', 'perspectivefunnel.co')
    • all of:
      • length(body.links) > 0
      • any of ml.nlu_classifier(body.current_thread.text).intents where all hold:
        • .name is 'cred_theft'
        • .confidence is 'high'
      • not:
        • sender.email.domain.root_domain in ('servicenowservices.com', 'workplaceextras.com', 'tempo.io', 'or.us', 'proofpoint.com')
    • any of filter(attachments) where:
      • any of file.parse_eml(.).attachments where:
        • any of file.explode(.) where all hold:
          • .scan.ocr.raw matches 'scan|camera'
          • .scan.ocr.raw matches '\\bQR\\b|Q\\.R\\.|barcode'
  5. not:
    • all of:
      • length(filter(body.links, strings.icontains(.display_text, 'click here'))) > 0
      • length(filter(body.links, strings.icontains(.display_text, 'click here'))) is strings.icount(body.current_thread.text, 'click here to unsubscribe')
  6. any of:
    • all of:
      • any of:
        • sender.email.domain.root_domain in $high_trust_sender_root_domains
        • sender.email.domain.root_domain in $org_domains
      • not:
        • headers.auth_summary.dmarc.pass
    • all of:
      • sender.email.domain.root_domain not in $high_trust_sender_root_domains
      • sender.email.domain.root_domain not in $org_domains
  7. not:
    • all of:
      • sender.email.domain.root_domain is 'sharepointonline.com'
      • headers.message_id ends with '@odspnotify>'
      • headers.message_id starts with '<Spo'
  8. not:
    • any of beta.ml_topic(body.current_thread.text).topics where all hold:
      • .name in ('Events and Webinars', 'Advertising and Promotions', 'Newsletters and Digests')
      • .confidence is 'high'
  9. not:
    • any of headers.domains where:
      • .root_domain in ('freshemail.io', 'zendesk.com', 'employeenavigator.com', 'saashr.com')
  10. not:
    • all of:
      • any of headers.hops where:
        • .authentication_results.spf_details.designator contains 'constantcontact.com'
      • sender.email.local_part starts with 'newsletters-hr'
      • sender.email.domain.root_domain is 'ccsend.com'
  11. any of:
    • not:
      • profile.by_sender_email().solicited
    • all of:
      • profile.by_sender().any_messages_malicious_or_spam
      • not:
        • profile.by_sender().any_messages_benign
    • all of:
      • profile.by_sender().any_messages_malicious_or_spam
      • profile.by_sender().any_messages_benign
      • not:
        • all of:
          • headers.auth_summary.dmarc.pass
          • headers.auth_summary.spf.pass
  12. not:
    • all of:
      • sender.email.email is 'analyzer@analyzer.securityeducation.com'
      • any of headers.domains where:
        • .root_domain is 'pphosted.com'
      • headers.auth_summary.spf.pass
      • headers.auth_summary.dmarc.pass

Inspects: attachments[].content_type, attachments[].file_extension, body.current_thread.text, body.links, body.links[].display_text, body.links[].href_url.domain.domain, body.links[].href_url.domain.root_domain, body.links[].href_url.path, body.links[].href_url.scheme, body.links[].href_url.url, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, headers.domains, headers.domains[].root_domain, headers.hops, headers.hops[].authentication_results.spf_details.designator, headers.message_id, sender.display_name, sender.email.domain.root_domain, sender.email.email, sender.email.local_part, subject.subject, type.inbound. Sensors: beta.ml_topic, file.explode, file.parse_eml, ml.nlu_classifier, profile.by_sender, profile.by_sender_email, regex.icontains, strings.concat, strings.ends_with, strings.icontains, strings.icount, strings.ilike, strings.starts_with. Reference lists: $free_file_hosts, $free_subdomain_hosts, $high_trust_sender_root_domains, $org_domains, $social_landing_hosts, $tranco_1m, $url_shorteners.

Indicators matched (51)

FieldMatchValue
regex.icontainsregex(time.{0,4}sheet)|(employ|complete|update(?:d| to| regarding our)|workplace).{0,30}(benefit|handbook|comp\b|compensation|salary|\bpay(?:roll)?\b|policy|policies|guidelines?|conduct|acknowl|PTO|vacation|assess|eval)|(HR|Human Resources).{0,5}ADM[il]N
regex.icontainsregex\breview\b(?:\w+(?:\s\w+)?|[[:punct:]]+|\s+){0,3}(benefits?(?:$|.?(?:statement|enrollment))|handbook|comp\b|compensation|salary|bonus|\bpay(?:roll)?\b)
regex.icontainsregex20\d{2}\b(?:\w+(?:\s\w+)?|[[:punct:]]+|\s+){0,5}(benefits?(?:$|.?(?:statement|enrollment))|handbook|comp\b|compensation|salary|bonus|\bpay(?:roll)?\b)
regex.icontainsregex(Employ|Time.{0,3}sheet|\bHR\b|Human R|Handbook|\bIT[- ]|Help.{0,3}Desk)|Internal.?Comm|Enroll?ment Service|Open Enroll?ment|Admin Support
regex.icontainsregexforum|employee voice|briefs|newsletter|screening
regex.icontainsregexHR (new|vue|view|tech admin|global)
strings.icontainssubstringget it
regex.icontainsregex20\d{2}(?:[[:punct:]](?:20)?\d{2})? (?:\w+ )?assessment report
ml.nlu_classifier(body.current_thread.text).entities[].namememberorg
ml.nlu_classifier(body.current_thread.text).entities[].namemembersender
regex.icontainsregex\bhr\b
regex.icontainsregexhuman resources
39 more
regex.icontainsregexoperations department
regex.icontainsregex(?:verify|view|click|download|goto|keep|Vιew|release|access|open|allow|deny|new).{0,10}(?:request|handbook|here|report|attachment|current|download|fax|file|document|message|same|doc|access|polic(?:y|ie))s?
strings.ilikesubstring*unsub*
strings.ilikesubstring*privacy?policy*
strings.ilikesubstring*REGISTER*
body.links[].href_url.domain.root_domainmemberhubspotlinks.com
body.links[].href_url.domain.root_domainmembermandrillapp.com
body.links[].href_url.domain.root_domainmembersendgrid.net
body.links[].href_url.domain.root_domainmemberrs6.net
body.links[].href_url.domain.root_domainmembermailanyone.net
body.links[].href_url.domain.root_domainmemberperspectivefunnel.co
ml.nlu_classifier(body.current_thread.text).intents[].nameequalscred_theft
ml.nlu_classifier(body.current_thread.text).intents[].confidenceequalshigh
sender.email.domain.root_domainmemberservicenowservices.com
sender.email.domain.root_domainmemberworkplaceextras.com
sender.email.domain.root_domainmembertempo.io
sender.email.domain.root_domainmemberor.us
sender.email.domain.root_domainmemberproofpoint.com
attachments[].content_typeequalsmessage/rfc822
attachments[].file_extensionmembereml
regex.icontainsregexscan|camera
regex.icontainsregex\bQR\b|Q\.R\.|barcode
strings.icontainssubstringclick here
sender.email.domain.root_domainequalssharepointonline.com
strings.ends_withsuffix@odspnotify>
strings.starts_withprefix<Spo
beta.ml_topic(body.current_thread.text).topics[].namememberEvents and Webinars
beta.ml_topic(body.current_thread.text).topics[].namememberAdvertising and Promotions
beta.ml_topic(body.current_thread.text).topics[].namememberNewsletters and Digests
beta.ml_topic(body.current_thread.text).topics[].confidenceequalshigh
headers.domains[].root_domainmemberfreshemail.io
headers.domains[].root_domainmemberzendesk.com
headers.domains[].root_domainmemberemployeenavigator.com
headers.domains[].root_domainmembersaashr.com
strings.icontainssubstringconstantcontact.com
strings.starts_withprefixnewsletters-hr
sender.email.domain.root_domainequalsccsend.com
sender.email.emailequalsanalyzer@analyzer.securityeducation.com
headers.domains[].root_domainequalspphosted.com