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