Brand impersonation: Sharepoint fake file share

This rule detects messages impersonating a Sharepoint file sharing email where no links point to known Microsoft domains.

Sublime rule (View on GitHub)

  1name: "Brand impersonation: Sharepoint fake file share"
  2description: |
  3    This rule detects messages impersonating a Sharepoint file sharing email where no links point to known Microsoft domains.
  4type: "rule"
  5severity: "medium"
  6source: |
  7  type.inbound
  8  
  9  // Sharepoint body content looks like this
 10  and (
 11    (
 12      (
 13        any([body.current_thread.text, body.plain.raw],
 14            strings.ilike(.,
 15                          "*shared a file with you*",
 16                          "*shared with you*",
 17                          "*invited you to access a file*",
 18                          "*you've received a document*"
 19            )
 20        )
 21        or any(file.explode(beta.message_screenshot()),
 22               strings.ilike(.scan.ocr.raw,
 23                             "*shared a file with you*",
 24                             "*shared with you*",
 25                             "*invited you to access a file*",
 26                             "*you've received a document*"
 27               )
 28        )
 29      )
 30      and (
 31        strings.ilike(subject.subject,
 32                      "*shared*",
 33                      "*updated*",
 34                      "*sign*",
 35                      "*review*"
 36        )
 37        or strings.ilike(subject.subject,
 38                         "*Excel*",
 39                         "*SharePoint*",
 40                         "*PowerPoint*",
 41                         "*OneNote*"
 42        )
 43        or subject.subject is null
 44        or subject.subject == ""
 45      )
 46    )
 47    or any([
 48             "Contigo", // Spanish
 49             "Avec vous", // French
 50             "Mit Ihnen", // German
 51             "Con te", // Italian
 52             "Com você", // Portuguese
 53             "Met u", // Dutch
 54             "С вами", // Russian
 55             "与你", // Chinese (Simplified)
 56             "與您", // Chinese (Traditional)
 57             "あなたと", // Japanese
 58             "당신과", // Korean
 59             "معك", // Arabic
 60             "آپ کے ساتھ", // Urdu
 61             "আপনার সাথে", // Bengali
 62             "आपके साथ", // Hindi
 63             "Sizinle", // Turkish // Azerbaijani
 64             "Med dig", // Swedish
 65             "Z tobą", // Polish
 66             "З вами", // Ukrainian
 67             "Önnel", // Hungarian
 68             "Μαζί σας", // Greek
 69             "איתך", // Hebrew
 70             "กับคุณ", // Thai
 71             "Với bạn", // Vietnamese
 72             "Dengan Anda", // Indonesian // Malay
 73             "Nawe", // Swahili
 74             "Cu dumneavoastră", // Romanian
 75             "S vámi", // Czech
 76             "Med deg", // Norwegian
 77             "S vami", // Slovak
 78             "Med dig", // Danish
 79             "Amb vostè", // Catalan
 80             "Teiega", // Estonian
 81             "S vama", // Serbian
 82           ],
 83           strings.icontains(subject.subject, .)
 84    )
 85  )
 86  
 87  // contains logic that impersonates Microsoft
 88  and (
 89    any(ml.logo_detect(beta.message_screenshot()).brands,
 90        strings.starts_with(.name, "Microsoft")
 91    )
 92    or any(attachments,
 93           .file_type in $file_types_images
 94           and any(ml.logo_detect(.).brands,
 95                   strings.starts_with(.name, "Microsoft")
 96           )
 97    )
 98    or (
 99      regex.icontains(body.html.raw,
100                      '<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}'
101      )
102      or 3 of (
103        regex.icontains(body.html.raw, '.password-expiration'),
104        regex.icontains(body.html.raw, 'color: #2672ec;'),
105        regex.icontains(body.html.raw, 'M­ic­ro­so­ft')
106      )
107      or 4 of (
108        regex.icontains(body.html.raw, 'rgb\(246,\s?93,\s?53\)'),
109        regex.icontains(body.html.raw, 'rgb\(129,\s?187,\s?5\)'),
110        regex.icontains(body.html.raw, 'rgb\(4,\s?165,\s?240\)'),
111        regex.icontains(body.html.raw, 'rgb\(255,\s?186,\s?7\)'),
112      )
113      or 4 of (
114        regex.icontains(body.html.raw,
115                        '(background-color:|background:|bgcolor=)(.)red'
116        ),
117        regex.icontains(body.html.raw, 'rgb\(19,\s?186,\s?132\)'),
118        regex.icontains(body.html.raw, 'rgb\(4,\s?166,\s?240\)'),
119        regex.icontains(body.html.raw, 'rgb\(255,\s?186,\s?8\)'),
120      )
121      or 4 of (
122        regex.icontains(body.html.raw, 'rgb\(245,\s?189,\s?67\)'),
123        regex.icontains(body.html.raw, 'rgb\(137,\s?184,\s?57\)'),
124        regex.icontains(body.html.raw, 'rgb\(217,\s?83,\s?51\)'),
125        regex.icontains(body.html.raw, 'rgb\(71,\s?160,\s?218\)')
126      )
127      or 4 of (
128        regex.icontains(body.html.raw, 'rgb\(73,\s?161,\s?232\)'),
129        regex.icontains(body.html.raw, 'rgb\(224,\s?92,\s?53\)'),
130        regex.icontains(body.html.raw, 'rgb\(139,\s?183,\s?55\)'),
131        regex.icontains(body.html.raw, 'rgb\(244,\s?188,\s?65\)')
132      )
133      or 4 of (
134        regex.icontains(body.html.raw, 'rgb\(213,\s?56,\s?62\)'),
135        regex.icontains(body.html.raw, 'rgb\(0,\s?114,\s?30\)'),
136        regex.icontains(body.html.raw, 'rgb\(0,\s?110,\s?173\)'),
137        regex.icontains(body.html.raw, 'rgb\(227,\s?209,\s?43\)'),
138      )
139      or 4 of (
140        regex.icontains(body.html.raw, 'rgb\(246,\s?93,\s?53\)'),
141        regex.icontains(body.html.raw, 'rgb\(129,\s?187,\s?5\)'),
142        regex.icontains(body.html.raw, 'rgb\(4,\s?165,\s?240\)'),
143        regex.icontains(body.html.raw, 'rgb\(255,\s?186,\s?7\)')
144      )
145      or 4 of (
146        regex.icontains(body.html.raw, 'rgb\(242,\s?80,\s?34\)'),
147        regex.icontains(body.html.raw, 'rgb\(127,\s?186,\s?0\)'),
148        regex.icontains(body.html.raw, 'rgb\(0,\s?164,\s?239\)'),
149        regex.icontains(body.html.raw, 'rgb\(255,\s?185,\s?0\)'),
150      )
151      or 4 of (
152        regex.icontains(body.html.raw, 'rgb\(243,\s?83,\s?37\)'),
153        regex.icontains(body.html.raw, 'rgb\(129,\s?188,\s?6\)'),
154        regex.icontains(body.html.raw, 'rgb\(5,\s?166,\s?240\)'),
155        regex.icontains(body.html.raw, 'rgb\(255,\s?186,\s?8\)')
156      )
157      or 4 of (
158        regex.icontains(body.html.raw, 'rgb\(243,\s?80,\s?34\)'),
159        regex.icontains(body.html.raw, 'rgb\(128,\s?187,\s?3\)'),
160        regex.icontains(body.html.raw, 'rgb\(3,\s?165,\s?240\)'),
161        regex.icontains(body.html.raw, 'rgb\(255,\s?185,\s?3\)')
162      )
163      or 4 of (
164        regex.icontains(body.html.raw,
165                        '(background-color:|background:|bgcolor=)(.)?(#)?(FF1940|eb5024|F25022|FF1941|red)'
166        ),
167        regex.icontains(body.html.raw,
168                        '(background-color:|background:|bgcolor=)(.)?(#)?(36ba57|3eb55d|7db606|7FBA00|36ba58|green)'
169        ),
170        regex.icontains(body.html.raw,
171                        '(background-color:|background:|bgcolor=)(.)?#(04a1d6|04B5F0|05a1e8|00A4EF|01a4ef|04a5f0)'
172        ),
173        regex.icontains(body.html.raw,
174                        '(background-color:|background:|bgcolor=)(.)?#(FFCA07|f7b408|FFB900|FFCA08|ffb901|ffba07)'
175        ),
176      )
177      or 4 of (
178        regex.icontains(body.html.raw,
179                        '(background-color:|background:|bgcolor=)(.)?#(f65314|f65d35|49a1e8|E74F23|F35325)'
180        ),
181        regex.icontains(body.html.raw,
182                        '(background-color:|background:|bgcolor=)(.)?#(7cbf42|81bb05|e05c35|7AB206|81BC06)'
183        ),
184        regex.icontains(body.html.raw,
185                        '(background-color:|background:|bgcolor=)(.)?#(00a4ef|0078d7|8bb737|04a5f0|059EE4|05A6F0)'
186        ),
187        regex.icontains(body.html.raw,
188                        '(background-color:|background:|bgcolor=)(.)?#(ffb900|ffba07|f4bc41|F2B108|FFBA08)'
189        ),
190      )
191      // fuzzy approach
192      or 4 of (
193        regex.icontains(body.html.raw,
194                        '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])\)'
195        ),
196        regex.icontains(body.html.raw,
197                        'rgb\((12[0-9]|13[0-9]),\s?(18[0-9]|190),\s?([0-9]|10)\)'
198        ),
199        regex.icontains(body.html.raw,
200                        'rgb\(([0-9]|1[0-5]),\s?(16[0-5]|166),\s?(23[0-9]|240)\)'
201        ),
202        regex.icontains(body.html.raw,
203                        'rgb\((25[0-5]),\s?(18[5-9]|19[0-9]),\s?([0-9]|10)\)'
204        )
205      )
206      or 4 of (
207        regex.icontains(body.html.raw, 'rgb\((25[0-5]),\s?(2[0-5]),\s?(6[0-4])\)'),
208        regex.icontains(body.html.raw, 'rgb\((6[0-2]),\s?(18[0-1]),\s?(9[0-3])\)'),
209        regex.icontains(body.html.raw, 'rgb\(([0-4]),\s?(18[0-1]),\s?(24[0])\)'),
210        regex.icontains(body.html.raw, 'rgb\((25[0-5]),\s?(20[0-2]),\s?([0-7])\)')
211      )
212      or regex.icontains(body.html.raw,
213                       '<a[^>]+style="[^"]*background-color:\s*#[0-9A-F]{2}[5-9A-F]{2}[0-9A-F]{2}[^"]*"[^>]*>[^<]*(?:open)[^<]*</a>' // blue button containing the word "open"
214      )
215      or (
216        any(recipients.to,
217            strings.icontains(body.current_thread.text,
218                              strings.concat(.email.domain.sld,
219                                             " shared a file with you"
220                              )
221            )
222        )
223      )
224    )
225  )
226  
227  // Negate messages when the message-id indciates the message is from MS actual. DKIM/SPF domains can be custom and therefore are unpredictable.
228  and not (
229    strings.starts_with(headers.message_id, '<Share-')
230    and strings.ends_with(headers.message_id, '@odspnotify>')
231  )
232  
233  // fake Sharepoint shares are easy to identify if there are any links
234  // that don't point to microsoft[.]com or *.sharepoint[.]com
235  and not all(body.links,
236              .href_url.domain.root_domain in (
237                "1drv.ms",
238                "aka.ms",
239                "microsoft.com",
240                "sharepoint.com"
241              )
242  )
243  and sender.email.domain.root_domain not in $org_domains
244  and sender.email.domain.root_domain not in (
245    "bing.com",
246    "microsoft.com",
247    "microsoftonline.com",
248    "microsoftsupport.com",
249    "microsoft365.com",
250    "office.com",
251    "onedrive.com",
252    "sharepointonline.com",
253    "yammer.com",
254    // ignore microsoft privacy statement links
255    "aka.ms"
256  )
257  
258  // negate highly trusted sender domains unless they fail DMARC authentication
259  and (
260    (
261      sender.email.domain.root_domain in $high_trust_sender_root_domains
262      and not headers.auth_summary.dmarc.pass
263    )
264    or sender.email.domain.root_domain not in $high_trust_sender_root_domains
265  )
266  and (
267    (not profile.by_sender().solicited)
268    or (
269      profile.by_sender().any_messages_malicious_or_spam
270      and not profile.by_sender().any_false_positives
271    )
272  )
273  and not profile.by_sender().any_false_positives  
274attack_types:
275  - "Credential Phishing"
276  - "Malware/Ransomware"
277detection_methods:
278  - "Content analysis"
279  - "Header analysis"
280  - "URL analysis"
281  - "Computer Vision"
282tactics_and_techniques:
283  - "Impersonation: Brand"
284  - "Social engineering"
285id: "ff8b296b-aa0d-5df0-b4d2-0e599b688f6a"
to-top