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 // suspicious link 
  8 and any(body.links,
  9         (
 10           .href_url.domain.root_domain not in $tranco_1m
 11           or .href_url.domain.domain in $free_file_hosts
 12           or .href_url.domain.root_domain in $free_file_hosts
 13           or .href_url.domain.root_domain in $free_subdomain_hosts
 14           or .href_url.domain.domain in $url_shorteners
 15           or 
 16 
 17           // mass mailer link, masks the actual URL
 18           .href_url.domain.root_domain in (
 19             "hubspotlinks.com",
 20             "mandrillapp.com",
 21             "sendgrid.net",
 22             "rs6.net"
 23           )
 24 
 25           // Google AMP redirect
 26           or (
 27             .href_url.domain.sld == "google"
 28             and strings.starts_with(.href_url.path, "/amp/")
 29           )
 30         )
 31 
 32         // exclude sources of potential FPs
 33         and (
 34           .href_url.domain.root_domain not in (
 35             "svc.ms",
 36             "sharepoint.com",
 37             "1drv.ms",
 38             "microsoft.com",
 39             "aka.ms",
 40             "msftauthimages.net",
 41             "mimecastprotect.com",
 42             "office.com",
 43             "microsoftproject.com"
 44           )
 45           or any(body.links, .href_url.domain.domain in $free_file_hosts)
 46         )
 47         and .href_url.domain.root_domain not in $org_domains
 48         and .href_url.domain.valid 
 49 )
 50 
 51 // not a reply
 52 and (
 53   length(headers.references) == 0
 54   or not any(headers.hops, any(.fields, strings.ilike(.name, "In-Reply-To")))
 55 )
 56 
 57 // Microsoft logo
 58 and (
 59   any(attachments,
 60       .file_type in $file_types_images
 61       and any(ml.logo_detect(.).brands, strings.starts_with(.name, "Microsoft"))
 62   )
 63   or any(ml.logo_detect(beta.message_screenshot()).brands,
 64          strings.starts_with(.name, "Microsoft")
 65   )
 66   or (
 67     regex.icontains(body.html.raw,
 68                     '<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}'
 69     )
 70     or regex.icontains(body.html.raw,
 71                        '<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;">'
 72     )
 73     or 4 of (
 74       regex.icontains(body.html.raw,
 75                       '<td style="width:.\d.px;.height:.\d.px;.background-color:.rgb\(245, 189, 67\);">.{0,10}</td>'
 76       ),
 77       regex.icontains(body.html.raw,
 78                       '<td style="width:.\d.px;.height:.\d.px;.background-color:.rgb\(137, 184, 57\);">.{0,10}</td>'
 79       ),
 80       regex.icontains(body.html.raw,
 81                       '<td style="width:.\d.px;.height:.\d.px;.background-color:.rgb\(217, 83, 51\);">.{0,10}</td>'
 82       ),
 83       regex.icontains(body.html.raw,
 84                       '<td style="width:.\d.px;.height:.\d.px;.background-color:.rgb\(71, 160, 218\);">.{0,10}</td>'
 85       )
 86     )
 87   )
 88 )
 89 
 90 // suspicious content
 91 and (
 92   (
 93     strings.ilike(body.plain.raw,
 94                   "*password*",
 95                   "*document*",
 96                   "*voicemail*",
 97                   "*cache*",
 98                   "*fax*",
 99                   "*storage*",
100                   "*quota*",
101                   "*message*"
102     )
103     and strings.ilike(body.plain.raw,
104                       "*terminated*",
105                       "*review*",
106                       "*expire*",
107                       "*click*",
108                       "*view*",
109                       "*exceed*",
110                       "*clear*",
111                       "*only works*",
112                       "*failed*",
113                       "*deleted*",
114                       "*revalidated*",
115                       "*renewal*"
116     )
117   )
118   or (
119     any(attachments,
120         .file_type in $file_types_images
121         and any(file.explode(.),
122                 strings.ilike(.scan.ocr.raw,
123                               "*password*",
124                               "*document*",
125                               "*voicemail*",
126                               "*cache*",
127                               "*fax*",
128                               "*storage*",
129                               "*quota*",
130                               "*messages*"
131                 )
132                 and strings.ilike(.scan.ocr.raw,
133                                   "*terminated*",
134                                   "*review*",
135                                   "*expire*",
136                                   "*click*",
137                                   "*view*",
138                                   "*exceed*",
139                                   "*clear*",
140                                   "*only works*",
141                                   "*failed*",
142                                   "*deleted*"
143                 )
144         )
145     )
146   )
147   or (
148     any(file.explode(beta.message_screenshot()),
149         strings.ilike(.scan.ocr.raw,
150                       "*password*",
151                       "*document*",
152                       "*voicemail*",
153                       "*cache*",
154                       "*fax*",
155                       "*storage*",
156                       "*quota*",
157                       "*messages*"
158         )
159         and strings.ilike(.scan.ocr.raw,
160                           "*terminated*",
161                           "*review*",
162                           "*expire*",
163                           "*click*",
164                           "*view*",
165                           "*exceed*",
166                           "*clear*",
167                           "*only works*",
168                           "*failed*",
169                           "*deleted*",
170                           "*revalidated*",
171                           "*renewal*"
172         )
173     )
174   )
175   or (
176     any(ml.nlu_classifier(body.current_thread.text).intents,
177         .name == "cred_theft" and .confidence in~ ("medium", "high")
178     )
179     or any(attachments,
180            .file_type in $file_types_images
181            and any(file.explode(.),
182                    any(ml.nlu_classifier(.scan.ocr.raw).intents,
183                        .name == "cred_theft"
184                        and .confidence in ("medium", "high")
185                    )
186            )
187     )
188   )
189 )
190 and sender.email.domain.root_domain not in (
191   "bing.com",
192   "microsoft.com",
193   "microsoftonline.com",
194   "microsoftproject.com",
195   "microsoftstoreemail.com",
196   "microsoftsupport.com",
197   "microsoft365.com",
198   "office.com",
199   "office365.com",
200   "onedrive.com",
201   "sharepointonline.com",
202   "yammer.com",
203 )
204 
205  // negate highly trusted sender domains unless they fail DMARC authentication
206  and (
207    (
208      sender.email.domain.root_domain in $high_trust_sender_root_domains
209      and not headers.auth_summary.dmarc.pass
210    )
211    or sender.email.domain.root_domain not in $high_trust_sender_root_domains
212  )
213 and (
214   not profile.by_sender().solicited
215   or (
216     profile.by_sender().any_messages_malicious_or_spam
217     and not profile.by_sender().any_false_positives
218   )
219 )
220 and not profile.by_sender().any_false_positives
221 
222 // exclude marketing jargen from ms partners
223 and not regex.icontains(body.current_thread.text,
224                         'schedul(e|ing).{0,10}(call|meeting|demo|zoom|conversation|time|tool)|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|low-code (development|approach|solution|journey|platform)'
225 )
226  
227attack_types:
228  - "Credential Phishing"
229tactics_and_techniques:
230  - "Free file host"
231  - "Image as content"
232  - "Impersonation: Brand"
233  - "Social engineering"
234detection_methods:
235  - "Computer Vision"
236  - "Content analysis"
237  - "File analysis"
238  - "Header analysis"
239  - "Natural Language Understanding"
240  - "Optical Character Recognition"
241  - "Sender analysis"
242  - "URL analysis"
243id: "b59201b6-f253-55a6-9c0a-e1500a32a751"
to-top