Impersonation: Internal corporate services

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.

Sublime rule (View on GitHub)

  1name: "Impersonation: Internal corporate services"
  2description: "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."
  3type: "rule"
  4severity: "high"
  5source: |
  6  type.inbound
  7  // use distinct "urls" (without query params) to determine number of links
  8  and 0 < length(distinct(body.links,
  9                          // strip out query params to determine 
 10                          // the unique number of links
 11                          strings.concat(.href_url.scheme,
 12                                         .href_url.domain.domain,
 13                                         .href_url.path
 14                          )
 15                 )
 16  ) <= 8
 17  
 18  // HR language found in subject
 19  and (
 20    (
 21      length(subject.subject) > 20
 22      and regex.icontains(subject.subject,
 23                          '(time.{0,4}sheet)|(employ|complete|update(?:d| to)).{0,30}(benefit|handbook|comp\b|compensation|salary|\bpay(?:roll)?\b|policy|conduct|acknowl|PTO|vacation|assess|eval)|(HR|Human Resources).{0,5}ADM[il]N',
 24                          // shorten the distance to 3 or less words for the word "review"
 25                          // special handling of benefits
 26                          '\breview\b(?:\w+(?:\s\w+)?|[[:punct:]]+|\s+){0,3}(benefits?(?:$|.?(?:statement|enrollment))|handbook|comp\b|compensation|salary|bonus|\bpay(?:roll)?\b)',
 27                          // handle the year in the subject, and expand the distance to 5 or less words
 28                          '20\d{2}\b(?:\w+(?:\s\w+)?|[[:punct:]]+|\s+){0,5}(benefits?(?:$|.?(?:statement|enrollment))|handbook|comp\b|compensation|salary|bonus|\bpay(?:roll)?\b)'
 29      )
 30    )
 31  
 32    // or HR language found in sender
 33    or (
 34      regex.icontains(sender.display_name,
 35                      '(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'
 36      )
 37      and not regex.icontains(sender.display_name,
 38                              "forum|employee voice|briefs|newsletter|screening"
 39      )
 40      and not regex.icontains(sender.display_name,
 41                              "HR (new|vue|view|tech admin|global)"
 42      )
 43      and not strings.icontains(sender.display_name, "get it")
 44    )
 45  
 46    // or assessment report language found in body
 47    or (
 48      regex.icontains(body.current_thread.text,
 49                      '20\d{2}(?:[[:punct:]](?:20)?\d{2})? (?:\w+ )?assessment report'
 50      )
 51    )
 52  
 53    // or HR department language found in body via NLU
 54    or any(ml.nlu_classifier(body.current_thread.text).entities,
 55           .name in ("org", "sender")
 56           and regex.icontains(.text, '\bhr\b', 'human resources')
 57    )
 58  )
 59  
 60  // suspicious display_text
 61  and (
 62    any(body.links,
 63        regex.icontains(.display_text,
 64                        '((verify|view|click|download|goto|keep|Vιew|release|access|open|allow|deny).{0,10}(request|here|report|attachment|current|download|fax|file|document|message|same|doc|access)s?)'
 65        )
 66        and not strings.ilike(.display_text, "*unsub*")
 67        and not strings.ilike(.href_url.url, "*privacy-policy*")
 68        and not strings.ilike(.display_text, "*REGISTER*")
 69  
 70        // from a low reputation link
 71        and (
 72          not .href_url.domain.root_domain in $org_domains
 73          and (
 74            (
 75              .href_url.domain.root_domain not in $tranco_1m
 76              or .href_url.domain.domain in $free_file_hosts
 77              or .href_url.domain.root_domain in $free_file_hosts
 78              or .href_url.domain.root_domain in $free_subdomain_hosts
 79              or .href_url.domain.domain in $url_shorteners
 80              or .href_url.domain.domain in $social_landing_hosts
 81            )
 82            or 
 83            // or mass mailer link, masks the actual URL
 84            .href_url.domain.root_domain in (
 85              "hubspotlinks.com",
 86              "mandrillapp.com",
 87              "sendgrid.net",
 88              "rs6.net",
 89              "mailanyone.net",
 90              "perspectivefunnel.co"
 91            )
 92          )
 93        )
 94    )
 95    // or credential theft confidence high
 96    or (
 97      length(body.links) > 0
 98      and any(ml.nlu_classifier(body.current_thread.text).intents,
 99              .name == "cred_theft" and .confidence == "high"
100      )
101      and not sender.email.domain.root_domain in (
102        "servicenowservices.com",
103        "workplaceextras.com",
104        "tempo.io",
105        "or.us",
106        "proofpoint.com"
107      )
108    )
109    or any(filter(attachments, .content_type == "message/rfc822"),
110           any(file.parse_eml(.).attachments,
111               any(file.explode(.),
112                   regex.icontains(.scan.ocr.raw, 'scan|camera')
113                   and regex.icontains(.scan.ocr.raw, '\bQR\b|Q\.R\.|barcode')
114               )
115           )
116    )
117  )
118  // negate messages where "click here" was found and was a link actually an unsub link
119  // this method allows for matching on other 'click here' links if they are present
120  and not (
121    length(filter(body.links, strings.icontains(.display_text, 'click here'))) > 0
122    and (
123      length(filter(body.links, strings.icontains(.display_text, 'click here'))) == strings.icount(body.current_thread.text,
124                                                                                                   'click here to unsubscribe'
125      )
126    )
127  )
128  
129  // negate highly trusted sender domains unless they fail DMARC authentication
130  and (
131    (
132      (
133        sender.email.domain.root_domain in $high_trust_sender_root_domains
134        or sender.email.domain.root_domain in $org_domains
135      )
136      and not headers.auth_summary.dmarc.pass
137    )
138    or (
139      sender.email.domain.root_domain not in $high_trust_sender_root_domains
140      and sender.email.domain.root_domain not in $org_domains
141    )
142  )
143  // not from sharepointonline actual
144  and not (
145    sender.email.domain.root_domain == "sharepointonline.com"
146    and strings.ends_with(headers.message_id, '@odspnotify>')
147    and strings.starts_with(headers.message_id, "<Spo")
148  )
149  // netate common FP topics
150  and not any(beta.ml_topic(body.current_thread.text).topics,
151              .name in (
152                "Events and Webinars",
153                "Advertising and Promotions",
154                "Newsletters and Digests"
155              )
156              and .confidence == "high"
157  )
158  // negate common helpdesk/HR platforms
159  and not any(headers.domains,
160              .root_domain in (
161                "freshemail.io",
162                "zendesk.com",
163                "employeenavigator.com",
164                "saashr.com" // Kronos owned Saas HR offering
165              )
166  )
167  // negate observed HR newsletters
168  and not (
169    any(headers.hops,
170        strings.icontains(.authentication_results.spf_details.designator,
171                          "constantcontact.com"
172        )
173    )
174    and strings.starts_with(sender.email.local_part, 'newsletters-hr')
175    and sender.email.domain.root_domain == "ccsend.com"
176  )
177  and (
178    not profile.by_sender_email().solicited
179    or (
180      profile.by_sender().any_messages_malicious_or_spam
181      and not profile.by_sender().any_messages_benign
182    )
183  )
184  and not profile.by_sender().any_messages_benign  
185attack_types:
186  - "Credential Phishing"
187tactics_and_techniques:
188  - "Impersonation: Employee"
189  - "Social engineering"
190detection_methods:
191  - "Content analysis"
192  - "Header analysis"
193  - "Natural Language Understanding"
194  - "Sender analysis"
195id: "3cd04f33-5519-5cc1-8740-e8ce6cddf8a0"
to-top