Brand impersonation: Microsoft with low reputation links

Detects low reputation links with Microsoft specific indicators in the body.

Sublime rule (View on GitHub)

  1name: "Brand impersonation: Microsoft with low reputation links"
  2description: "Detects low reputation links with Microsoft specific indicators in the body."
  3type: "rule"
  4severity: "medium"
  5source: |
  6 type.inbound
  7 and 0 < length(body.links) < 50
  8 // suspicious link 
  9 and any(body.links,
 10         (
 11           .href_url.domain.root_domain not in $tranco_1m
 12           or .href_url.domain.domain in $free_file_hosts
 13           or .href_url.domain.root_domain in $free_file_hosts
 14           or .href_url.domain.root_domain in $free_subdomain_hosts
 15           or .href_url.domain.domain in $url_shorteners
 16           or 
 17 
 18           // mass mailer link, masks the actual URL
 19           .href_url.domain.root_domain in (
 20             "hubspotlinks.com",
 21             "mandrillapp.com",
 22             "sendgrid.net",
 23             "rs6.net"
 24           )
 25 
 26           // Google AMP redirect
 27           or (
 28             .href_url.domain.sld == "google"
 29             and strings.starts_with(.href_url.path, "/amp/")
 30           )
 31 
 32          // Recipient email address in link
 33          or any(body.links,
 34                 any(recipients.to,
 35                     strings.icontains(..href_url.url, .email.email)
 36                     and any(recipients.to, .email.domain.valid)
 37                 )
 38          )
 39          or .href_url.domain.root_domain == "beehiiv.com"
 40         )
 41 
 42         // exclude sources of potential FPs
 43         and (
 44           .href_url.domain.root_domain not in (
 45             "svc.ms",
 46             "sharepoint.com",
 47             "1drv.ms",
 48             "microsoft.com",
 49             "aka.ms",
 50             "msftauthimages.net",
 51             "mimecastprotect.com",
 52             "office.com",
 53             "microsoftproject.com"
 54           )
 55           or any(body.links, .href_url.domain.domain in $free_file_hosts)
 56         )
 57         and .href_url.domain.root_domain not in $org_domains
 58         and .href_url.domain.valid
 59 )
 60 
 61 // not a reply
 62 and (
 63     length(headers.references) == 0
 64     or not any(headers.hops, any(.fields, strings.ilike(.name, "In-Reply-To")))
 65 )
 66 
 67 // Microsoft logo
 68 and (
 69   any(attachments,
 70       .file_type in $file_types_images
 71       and any(ml.logo_detect(.).brands, strings.starts_with(.name, "Microsoft"))
 72   )
 73   or strings.istarts_with(strings.replace_confusables(body.current_thread.text), "Microsoft ")
 74   or regex.imatch(strings.replace_confusables(body.current_thread.text), '[\n\s]*[o0O]ff[il1]ce\b.*')
 75   or any(ml.logo_detect(beta.message_screenshot()).brands,
 76          strings.starts_with(.name, "Microsoft")
 77   )
 78   or (
 79     regex.icontains(body.html.raw,
 80                     '<table[^>]*>\s*<tbody[^>]*>\s*<tr[^>]*>\s*(<td[^>]*bgcolor="#[0-9A-Fa-f]{6}"[^>]*>\s*&nbsp;\s*</td>\s*){2}\s*</tr>\s*<tr[^>]*>\s*(<td[^>]*bgcolor="#[0-9A-Fa-f]{6}"[^>]*>\s*&nbsp;\s*</td>\s*){2}'
 81     )
 82     or regex.icontains(body.html.raw,
 83                        '<td style="background:\s*rgb\(246,\s*93,\s*53\);\s*height:\d+px;">.*?<td style="background:\s*rgb\(129,\s*187,\s*5\);\s*height:\d+px;">.*?<td style="background:\s*rgb\(4,\s*165,\s*240\);\s*height:\d+px;">.*?<td style="background:\s*rgb\(255,\s*186,\s*7\);\s*height:\d+px;">'
 84     )
 85     or 4 of (
 86       regex.icontains(body.html.raw,
 87                       '<td style="width:.\d.px;.height:.\d.px;.background-color:.rgb\(245, 189, 67\);">.{0,10}</td>'
 88       ),
 89       regex.icontains(body.html.raw,
 90                       '<td style="width:.\d.px;.height:.\d.px;.background-color:.rgb\(137, 184, 57\);">.{0,10}</td>'
 91       ),
 92       regex.icontains(body.html.raw,
 93                       '<td style="width:.\d.px;.height:.\d.px;.background-color:.rgb\(217, 83, 51\);">.{0,10}</td>'
 94       ),
 95       regex.icontains(body.html.raw,
 96                       '<td style="width:.\d.px;.height:.\d.px;.background-color:.rgb\(71, 160, 218\);">.{0,10}</td>'
 97       )
 98     )
 99   )
100   or regex.icontains(body.html.raw,
101                      '<table[^>]*>\s*<tbody[^>]*>\s*<tr[^>]*>\s*(<td[^>]*bgcolor="#[0-9A-Fa-f]{6}"[^>]*>\s*&nbsp;\s*</td>\s*){2}\s*</tr>\s*<tr[^>]*>\s*(<td[^>]*bgcolor="#[0-9A-Fa-f]{6}"[^>]*>\s*&nbsp;\s*</td>\s*){2}'
102   )
103   or 3 of (
104     regex.icontains(body.html.raw, '.password-expiration'),
105     regex.icontains(body.html.raw, 'color: #2672ec;'),
106     regex.icontains(body.html.raw, 'M­ic­ro­so­ft')
107   )
108   or 4 of (
109     regex.icontains(body.html.raw, 'rgb\(246,\s?93,\s?53\)'),
110     regex.icontains(body.html.raw, 'rgb\(129,\s?187,\s?5\)'),
111     regex.icontains(body.html.raw, 'rgb\(4,\s?165,\s?240\)'),
112     regex.icontains(body.html.raw, 'rgb\(255,\s?186,\s?7\)'),
113   )
114   or 4 of (
115     regex.icontains(body.html.raw,
116                     '(background-color:|background:|bgcolor=)(.)red'
117     ),
118     regex.icontains(body.html.raw, 'rgb\(19,\s?186,\s?132\)'),
119     regex.icontains(body.html.raw, 'rgb\(4,\s?166,\s?240\)'),
120     regex.icontains(body.html.raw, 'rgb\(255,\s?186,\s?8\)'),
121   )
122   or 4 of (
123     regex.icontains(body.html.raw, 'rgb\(245,\s?189,\s?67\)'),
124     regex.icontains(body.html.raw, 'rgb\(137,\s?184,\s?57\)'),
125     regex.icontains(body.html.raw, 'rgb\(217,\s?83,\s?51\)'),
126     regex.icontains(body.html.raw, 'rgb\(71,\s?160,\s?218\)')
127   )
128   or 4 of (
129     regex.icontains(body.html.raw, 'rgb\(73,\s?161,\s?232\)'),
130     regex.icontains(body.html.raw, 'rgb\(224,\s?92,\s?53\)'),
131     regex.icontains(body.html.raw, 'rgb\(139,\s?183,\s?55\)'),
132     regex.icontains(body.html.raw, 'rgb\(244,\s?188,\s?65\)')
133   )
134   or 4 of (
135     regex.icontains(body.html.raw, 'rgb\(213,\s?56,\s?62\)'),
136     regex.icontains(body.html.raw, 'rgb\(0,\s?114,\s?30\)'),
137     regex.icontains(body.html.raw, 'rgb\(0,\s?110,\s?173\)'),
138     regex.icontains(body.html.raw, 'rgb\(227,\s?209,\s?43\)'),
139   )
140   or 4 of (
141     regex.icontains(body.html.raw, 'rgb\(246,\s?93,\s?53\)'),
142     regex.icontains(body.html.raw, 'rgb\(129,\s?187,\s?5\)'),
143     regex.icontains(body.html.raw, 'rgb\(4,\s?165,\s?240\)'),
144     regex.icontains(body.html.raw, 'rgb\(255,\s?186,\s?7\)')
145   )
146   or 4 of (
147     regex.icontains(body.html.raw, 'rgb\(242,\s?80,\s?34\)'),
148     regex.icontains(body.html.raw, 'rgb\(127,\s?186,\s?0\)'),
149     regex.icontains(body.html.raw, 'rgb\(0,\s?164,\s?239\)'),
150     regex.icontains(body.html.raw, 'rgb\(255,\s?185,\s?0\)'),
151   )
152   or 4 of (
153     regex.icontains(body.html.raw, 'rgb\(243,\s?83,\s?37\)'),
154     regex.icontains(body.html.raw, 'rgb\(129,\s?188,\s?6\)'),
155     regex.icontains(body.html.raw, 'rgb\(5,\s?166,\s?240\)'),
156     regex.icontains(body.html.raw, 'rgb\(255,\s?186,\s?8\)')
157   )
158   or 4 of (
159     regex.icontains(body.html.raw, 'rgb\(243,\s?80,\s?34\)'),
160     regex.icontains(body.html.raw, 'rgb\(128,\s?187,\s?3\)'),
161     regex.icontains(body.html.raw, 'rgb\(3,\s?165,\s?240\)'),
162     regex.icontains(body.html.raw, 'rgb\(255,\s?185,\s?3\)')
163   )
164   or 4 of (
165     regex.icontains(body.html.raw,
166                     '(background-color:|background:|bgcolor=)(.)?(#)?(FF1940|eb5024|F25022|FF1941|red)'
167     ),
168     regex.icontains(body.html.raw,
169                     '(background-color:|background:|bgcolor=)(.)?(#)?(36ba57|3eb55d|7db606|7FBA00|36ba58|green)'
170     ),
171     regex.icontains(body.html.raw,
172                     '(background-color:|background:|bgcolor=)(.)?#(04a1d6|04B5F0|05a1e8|00A4EF|01a4ef|04a5f0)'
173     ),
174     regex.icontains(body.html.raw,
175                     '(background-color:|background:|bgcolor=)(.)?#(FFCA07|f7b408|FFB900|FFCA08|ffb901|ffba07)'
176     ),
177   )
178   or 4 of (
179     regex.icontains(body.html.raw,
180                     '(background-color:|background:|bgcolor=)(.)?#(f65314|f65d35|49a1e8|E74F23|F35325)'
181     ),
182     regex.icontains(body.html.raw,
183                     '(background-color:|background:|bgcolor=)(.)?#(7cbf42|81bb05|e05c35|7AB206|81BC06)'
184     ),
185     regex.icontains(body.html.raw,
186                     '(background-color:|background:|bgcolor=)(.)?#(00a4ef|0078d7|8bb737|04a5f0|059EE4|05A6F0)'
187     ),
188     regex.icontains(body.html.raw,
189                     '(background-color:|background:|bgcolor=)(.)?#(ffb900|ffba07|f4bc41|F2B108|FFBA08)'
190     ),
191   )
192   // fuzzy approach
193   or 4 of (
194     regex.icontains(body.html.raw,
195                     'rgb\((2[1-4][0-9]|250),\s?(7[0-9]|8[0-9]|9[0-3]),\s?(3[0-9]|4[0-9]|5[0-3])\)'
196     ),
197     regex.icontains(body.html.raw,
198                     'rgb\((12[0-9]|13[0-9]),\s?(18[0-9]|190),\s?([0-9]|10)\)'
199     ),
200     regex.icontains(body.html.raw,
201                     'rgb\(([0-9]|1[0-5]),\s?(16[0-5]|166),\s?(23[0-9]|240)\)'
202     ),
203     regex.icontains(body.html.raw,
204                     'rgb\((25[0-5]),\s?(18[5-9]|19[0-9]),\s?([0-9]|10)\)'
205     )
206   )
207 )
208 
209 // suspicious content
210 and (
211   // current thread is empty, but an image attachment is branded as microsoft.
212   // common in image as content
213   (
214     body.current_thread.text == ""
215     and any(attachments,
216             .file_type in $file_types_images
217             and any(ml.logo_detect(.).brands,
218                     strings.starts_with(.name, "Microsoft")
219             )
220     )
221   )
222   or (
223     strings.ilike(body.plain.raw,
224                   "*password*",
225                   "*document*",
226                   "*voicemail*",
227                   "*cache*",
228                   "*fax*",
229                   "*storage*",
230                   "*quota*",
231                   "*message*"
232     )
233     and strings.ilike(body.plain.raw,
234                       "*terminated*",
235                       "*review*",
236                       "*expire*",
237                       "*click*",
238                       "*view*",
239                       "*exceed*",
240                       "*clear*",
241                       "*only works*",
242                       "*failed*",
243                       "*deleted*",
244                       "*revalidated*",
245                       "*renewal*"
246     )
247   )
248  
249   or (
250     any(attachments,
251         .file_type in $file_types_images
252         and any(file.explode(.),
253                 strings.ilike(.scan.ocr.raw,
254                               "*password*",
255                               "*document*",
256                               "*voicemail*",
257                               "*cache*",
258                               "*fax*",
259                               "*storage*",
260                               "*quota*",
261                               "*messages*"
262                 )
263                 and strings.ilike(.scan.ocr.raw,
264                                   "*terminated*",
265                                   "*review*",
266                                   "*expire*",
267                                   "*click*",
268                                   "*view*",
269                                   "*exceed*",
270                                   "*clear*",
271                                   "*only works*",
272                                   "*failed*",
273                                   "*deleted*"
274                 )
275         )
276     )
277   )
278   or (
279     any(file.explode(beta.message_screenshot()),
280         strings.ilike(.scan.ocr.raw,
281                       "*password*",
282                       "*document*",
283                       "*voicemail*",
284                       "*cache*",
285                       "*fax*",
286                       "*storage*",
287                       "*quota*",
288                       "*messages*"
289         )
290         and strings.ilike(.scan.ocr.raw,
291                           "*terminated*",
292                           "*review*",
293                           "*expire*",
294                           "*click*",
295                           "*view*",
296                           "*exceed*",
297                           "*clear*",
298                           "*only works*",
299                           "*failed*",
300                           "*deleted*",
301                           "*revalidated*",
302                           "*renewal*"
303         )
304     )
305   )
306   or (
307     any(ml.nlu_classifier(body.current_thread.text).intents,
308         .name == "cred_theft" and .confidence in~ ("medium", "high")
309     )
310     or any(attachments,
311            .file_type in $file_types_images
312            and any(file.explode(.),
313                    any(ml.nlu_classifier(.scan.ocr.raw).intents,
314                        .name == "cred_theft"
315                        and .confidence in ("medium", "high")
316                    )
317            )
318     )
319   )
320 )
321 and sender.email.domain.root_domain not in (
322   "bing.com",
323   "microsoft.com",
324   "microsoftonline.com",
325   "microsoftproject.com",
326   "microsoftstoreemail.com",
327   "microsoftsupport.com",
328   "microsoft365.com",
329   "office.com",
330   "office365.com",
331   "onedrive.com",
332   "sharepointonline.com",
333   "yammer.com",
334 )
335 
336 // negate legitimate Office 365 bouncebacks
337 and not (
338     length(attachments) > 0
339     and all(attachments,
340         .content_type in ("message/delivery-status", "message/rfc822")
341     )
342     and (sender.email.local_part in ('postmaster', 'mailer-daemon'))
343 )
344 
345 // negate Microsoft "welcome to the X group" notifications
346 and not (
347   headers.auth_summary.dmarc.pass
348   and length(attachments) == 6
349   and length(filter(attachments,
350                     strings.istarts_with(.file_name, "GuestWelcomeEmail")
351              )
352   ) == 5
353   and length(filter(body.links,
354                     (
355                       .href_url.domain.domain not in (
356                         "outlook.office365.com",
357                         "aka.ms",
358                         "go.microsoft.com"
359                       )
360                     )
361                     and not .href_url.domain.domain == sender.email.domain.domain
362              )
363   ) == 0
364   and subject.subject == strings.replace_confusables(subject.subject)
365 )
366 
367 // negate highly trusted sender domains unless they fail DMARC authentication
368 and (
369   (
370     sender.email.domain.root_domain in $high_trust_sender_root_domains
371     and not headers.auth_summary.dmarc.pass
372   )
373   or sender.email.domain.root_domain not in $high_trust_sender_root_domains
374 )
375 and (
376   not profile.by_sender().solicited
377   or (
378     profile.by_sender().any_messages_malicious_or_spam
379     and not profile.by_sender().any_false_positives
380   )
381 )
382 and not profile.by_sender().any_false_positives
383 
384 // exclude marketing jargon from ms partners
385 and not regex.icontains(body.current_thread.text,
386                         '(schedul(e|ing)|set up).{0,20}(call|meeting|demo|zoom|conversation|time|tool|discussion)|book.{0,10}(meeting|demo|call|slot|time)|connect.{0,12}(with me|phone|email)|my.{0,10}(calendar|cal)|reserve.{0,10}s[pl]ot|break the ice|want to know more?|miss your chance|if you no longer wish|if you no longer want|if you wish to opt out|low-code (development|approach|solution|journey|platform)|(?:invite|virtual).{0,30}(webinar|presentation)'
387 )  
388attack_types:
389  - "Credential Phishing"
390tactics_and_techniques:
391  - "Free file host"
392  - "Image as content"
393  - "Impersonation: Brand"
394  - "Social engineering"
395detection_methods:
396  - "Computer Vision"
397  - "Content analysis"
398  - "File analysis"
399  - "Header analysis"
400  - "Natural Language Understanding"
401  - "Optical Character Recognition"
402  - "Sender analysis"
403  - "URL analysis"
404id: "b59201b6-f253-55a6-9c0a-e1500a32a751"
to-top