Medium Severity
Brand impersonation: Sharepoint fake file share
Description
This rule detects messages impersonating a Sharepoint file sharing email where no links point to known Microsoft domains.
References
No references.
Sublime Security
Created Nov 18th, 2023 • Last updated Jul 16th, 2025
Feed Source
Sublime Core Feed
Source
type.inbound
// Sharepoint body content looks like this
and (
(
(
any([body.current_thread.text, body.plain.raw],
strings.ilike(.,
"*shared a file with you*",
"*shared with you*",
"*invited you to access a file*",
"*received a document*",
"*shared a document*",
"*shared a new document*",
"*shared this document*"
)
)
or any(beta.ml_topic(body.current_thread.text).topics,
.name == "File Sharing and Cloud Services"
and .confidence == "high"
)
or any(file.explode(beta.message_screenshot()),
strings.ilike(.scan.ocr.raw,
"*shared a file with you*",
"*shared with you*",
"*invited you to access a file*",
"*received a document*",
"*shared a document*",
"*shared a new document*",
"*shared this document*"
)
or any(beta.ml_topic(.scan.ocr.raw).topics,
.name == "File Sharing and Cloud Services"
and .confidence == "high"
)
)
)
and (
strings.ilike(subject.subject,
"*shared*",
"*updated*",
"*sign*",
"*review*",
"*scanned*"
)
or strings.ilike(subject.subject,
"*Excel*",
"*SharePoint*",
"*PowerPoint*",
"*OneNote*"
)
or strings.ilike(sender.display_name,
"*Excel*",
"*SharePoint*",
"*PowerPoint*",
"*OneNote*"
)
or any(body.links, strings.icontains(.display_text, "OPEN DOCUMENT"))
or subject.subject is null
or subject.subject == ""
// the org as determined by NLU is in the subject
or any(ml.nlu_classifier(body.current_thread.text).entities,
.name == "org" and strings.icontains(subject.subject, .text)
)
)
)
or any([
"Contigo", // Spanish
"Avec vous", // French
"Mit Ihnen", // German
"Con te", // Italian
"Com você", // Portuguese
"Met u", // Dutch
"С вами", // Russian
"与你", // Chinese (Simplified)
"與您", // Chinese (Traditional)
"あなたと", // Japanese
"당신과", // Korean
"معك", // Arabic
"آپ کے ساتھ", // Urdu
"আপনার সাথে", // Bengali
"आपके साथ", // Hindi
"Sizinle", // Turkish // Azerbaijani
"Med dig", // Swedish
"Z tobą", // Polish
"З вами", // Ukrainian
"Önnel", // Hungarian
"Μαζί σας", // Greek
"איתך", // Hebrew
"กับคุณ", // Thai
"Với bạn", // Vietnamese
"Dengan Anda", // Indonesian // Malay
"Nawe", // Swahili
"Cu dumneavoastră", // Romanian
"S vámi", // Czech
"Med deg", // Norwegian
"S vami", // Slovak
"Med dig", // Danish
"Amb vostè", // Catalan
"Teiega", // Estonian
"S vama", // Serbian
],
strings.icontains(subject.subject, .)
)
)
// contains logic that impersonates Microsoft
and (
any(ml.logo_detect(beta.message_screenshot()).brands,
strings.starts_with(.name, "Microsoft")
)
or any(attachments,
.file_type in $file_types_images
and any(ml.logo_detect(.).brands,
strings.starts_with(.name, "Microsoft")
)
)
or regex.icontains(body.html.raw,
'<table[^>]*>\s*<tbody[^>]*>\s*<tr[^>]*>\s*(<td[^>]*bgcolor="#[0-9A-Fa-f]{6}"[^>]*>\s* \s*</td>\s*){2}\s*</tr>\s*<tr[^>]*>\s*(<td[^>]*bgcolor="#[0-9A-Fa-f]{6}"[^>]*>\s* \s*</td>\s*){2}'
)
or 3 of (
regex.icontains(body.html.raw, '.password-expiration'),
regex.icontains(body.html.raw, 'color: #2672ec;'),
regex.icontains(body.html.raw, 'Microsoft')
)
or 4 of (
regex.icontains(body.html.raw, 'rgb\(246,\s?93,\s?53\)'),
regex.icontains(body.html.raw, 'rgb\(129,\s?187,\s?5\)'),
regex.icontains(body.html.raw, 'rgb\(4,\s?165,\s?240\)'),
regex.icontains(body.html.raw, 'rgb\(255,\s?186,\s?7\)'),
)
or 4 of (
regex.icontains(body.html.raw,
'(background-color:|background:|bgcolor=)(.)red'
),
regex.icontains(body.html.raw, 'rgb\(19,\s?186,\s?132\)'),
regex.icontains(body.html.raw, 'rgb\(4,\s?166,\s?240\)'),
regex.icontains(body.html.raw, 'rgb\(255,\s?186,\s?8\)'),
)
or 4 of (
regex.icontains(body.html.raw, 'rgb\(245,\s?189,\s?67\)'),
regex.icontains(body.html.raw, 'rgb\(137,\s?184,\s?57\)'),
regex.icontains(body.html.raw, 'rgb\(217,\s?83,\s?51\)'),
regex.icontains(body.html.raw, 'rgb\(71,\s?160,\s?218\)')
)
or 4 of (
regex.icontains(body.html.raw, 'rgb\(73,\s?161,\s?232\)'),
regex.icontains(body.html.raw, 'rgb\(224,\s?92,\s?53\)'),
regex.icontains(body.html.raw, 'rgb\(139,\s?183,\s?55\)'),
regex.icontains(body.html.raw, 'rgb\(244,\s?188,\s?65\)')
)
or 4 of (
regex.icontains(body.html.raw, 'rgb\(213,\s?56,\s?62\)'),
regex.icontains(body.html.raw, 'rgb\(0,\s?114,\s?30\)'),
regex.icontains(body.html.raw, 'rgb\(0,\s?110,\s?173\)'),
regex.icontains(body.html.raw, 'rgb\(227,\s?209,\s?43\)'),
)
or 4 of (
regex.icontains(body.html.raw, 'rgb\(246,\s?93,\s?53\)'),
regex.icontains(body.html.raw, 'rgb\(129,\s?187,\s?5\)'),
regex.icontains(body.html.raw, 'rgb\(4,\s?165,\s?240\)'),
regex.icontains(body.html.raw, 'rgb\(255,\s?186,\s?7\)')
)
or 4 of (
regex.icontains(body.html.raw, 'rgb\(242,\s?80,\s?34\)'),
regex.icontains(body.html.raw, 'rgb\(127,\s?186,\s?0\)'),
regex.icontains(body.html.raw, 'rgb\(0,\s?164,\s?239\)'),
regex.icontains(body.html.raw, 'rgb\(255,\s?185,\s?0\)'),
)
or 4 of (
regex.icontains(body.html.raw, 'rgb\(243,\s?83,\s?37\)'),
regex.icontains(body.html.raw, 'rgb\(129,\s?188,\s?6\)'),
regex.icontains(body.html.raw, 'rgb\(5,\s?166,\s?240\)'),
regex.icontains(body.html.raw, 'rgb\(255,\s?186,\s?8\)')
)
or 4 of (
regex.icontains(body.html.raw, 'rgb\(243,\s?80,\s?34\)'),
regex.icontains(body.html.raw, 'rgb\(128,\s?187,\s?3\)'),
regex.icontains(body.html.raw, 'rgb\(3,\s?165,\s?240\)'),
regex.icontains(body.html.raw, 'rgb\(255,\s?185,\s?3\)')
)
or 4 of (
regex.icontains(body.html.raw,
'(background-color:|background:|bgcolor=)(.)?(#)?(FF1940|eb5024|F25022|FF1941|red)'
),
regex.icontains(body.html.raw,
'(background-color:|background:|bgcolor=)(.)?(#)?(36ba57|3eb55d|7db606|7FBA00|36ba58|green)'
),
regex.icontains(body.html.raw,
'(background-color:|background:|bgcolor=)(.)?#(04a1d6|04B5F0|05a1e8|00A4EF|01a4ef|04a5f0)'
),
regex.icontains(body.html.raw,
'(background-color:|background:|bgcolor=)(.)?#(FFCA07|f7b408|FFB900|FFCA08|ffb901|ffba07)'
),
)
or 4 of (
regex.icontains(body.html.raw,
'(background-color:|background:|bgcolor=)(.)?#(f65314|f65d35|49a1e8|E74F23|F35325)'
),
regex.icontains(body.html.raw,
'(background-color:|background:|bgcolor=)(.)?#(7cbf42|81bb05|e05c35|7AB206|81BC06)'
),
regex.icontains(body.html.raw,
'(background-color:|background:|bgcolor=)(.)?#(00a4ef|0078d7|8bb737|04a5f0|059EE4|05A6F0)'
),
regex.icontains(body.html.raw,
'(background-color:|background:|bgcolor=)(.)?#(ffb900|ffba07|f4bc41|F2B108|FFBA08)'
),
)
// fuzzy approach
or 4 of (
regex.icontains(body.html.raw,
'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])\)'
),
regex.icontains(body.html.raw,
'rgb\((12[0-9]|13[0-9]),\s?(18[0-9]|190),\s?([0-9]|10)\)'
),
regex.icontains(body.html.raw,
'rgb\(([0-9]|1[0-5]),\s?(16[0-5]|166),\s?(23[0-9]|240)\)'
),
regex.icontains(body.html.raw,
'rgb\((25[0-5]),\s?(18[5-9]|19[0-9]),\s?([0-9]|10)\)'
)
)
or 4 of (
regex.icontains(body.html.raw, 'rgb\((25[0-5]),\s?(2[0-5]),\s?(6[0-4])\)'),
regex.icontains(body.html.raw, 'rgb\((6[0-2]),\s?(18[0-1]),\s?(9[0-3])\)'),
regex.icontains(body.html.raw, 'rgb\(([0-4]),\s?(18[0-1]),\s?(24[0])\)'),
regex.icontains(body.html.raw, 'rgb\((25[0-5]),\s?(20[0-2]),\s?([0-7])\)')
)
or (
any(recipients.to,
strings.icontains(body.current_thread.text,
strings.concat(.email.domain.sld,
" shared a file with you"
)
)
)
)
or (
any(recipients.to,
strings.icontains(body.current_thread.text,
strings.concat("This link will work for ",
.email.email
)
)
)
)
// contains HTML and wording from the sharepoint template
or (
(
//
// This rule makes use of a beta feature and is subject to change without notice
// using the beta feature in custom rules is not suggested until it has been formally released
//
// alt text for the global icon
length(html.xpath(body.html, '//img[@alt="permission globe icon"]').nodes) > 0
// reference to the global icon id
or length(html.xpath(body.html, '//img[@id="Picture_x0020_1"]').nodes) > 0
// a comment reference the globe icon
or strings.icontains(body.html.raw,
' <!-- Permission globe icon placeholder -->'
)
)
// the wording from the sharepoint share
and strings.contains(body.current_thread.text,
'This invite will only work for you and people with existing access'
)
)
or any(html.xpath(body.html,
"//*[contains(translate(@style, 'ABCDEF', 'abcdef'), 'color:#605e5c')]"
).nodes,
.display_text =~ "Privacy Statement"
)
or 2 of (
strings.icontains(body.current_thread.text,
'Microsoft respects your privacy'
),
strings.icontains(body.current_thread.text,
'please read our Privacy Statement'
),
strings.icontains(body.current_thread.text,
'Microsoft Corporation, One Microsoft Way, Redmond, WA 98052'
),
)
)
// Negate messages when the message-id indciates the message is from MS actual. DKIM/SPF domains can be custom and therefore are unpredictable.
and not (
strings.starts_with(headers.message_id, '<Share-')
and strings.ends_with(headers.message_id, '@odspnotify>')
)
// fake Sharepoint shares are easy to identify if there are any links
// that don't point to microsoft[.]com or *.sharepoint[.]com
and not all(body.links,
.href_url.domain.root_domain in (
"1drv.ms",
"aka.ms",
"microsoft.com",
"sharepoint.com"
)
)
// if there is a Sharepoint link, ensure the link doesn't match any org SLDs
and not any(body.links,
.href_url.domain.root_domain == "sharepoint.com"
and any($org_slds, . == ..href_url.domain.subdomain)
)
and sender.email.domain.root_domain not in $org_domains
and sender.email.domain.root_domain not in (
"bing.com",
"microsoft.com",
"microsoftonline.com",
"microsoftsupport.com",
"microsoft365.com",
"office.com",
"onedrive.com",
"sharepointonline.com",
"yammer.com",
// ignore microsoft privacy statement links
"aka.ms"
)
and (
not (
(
strings.istarts_with(subject.subject, "RE:")
or strings.istarts_with(subject.subject, "R:")
or strings.istarts_with(subject.subject, "ODG:")
or strings.istarts_with(subject.subject, "答复:")
or strings.istarts_with(subject.subject, "AW:")
or strings.istarts_with(subject.subject, "TR:")
or strings.istarts_with(subject.subject, "FWD:")
or regex.imatch(subject.subject, '(\[[^\]]+\]\s?){0,3}(re|fwd?)\s?:')
or regex.imatch(subject.subject,
'^\[?(EXT|EXTERNAL)\]?[: ]\s*(RE|FWD?|FW|AW|TR|ODG|答复):.*'
)
)
and (
(
length(headers.references) > 0
or any(headers.hops, any(.fields, strings.ilike(.name, "In-Reply-To")))
)
// ensure that there are actual threads
and (length(body.html.display_text) - length(body.current_thread.text)) > 200
)
)
or length(body.current_thread.text) == 0
)
// negate highly trusted sender domains unless they fail DMARC authentication
and (
(
sender.email.domain.root_domain in $high_trust_sender_root_domains
and not headers.auth_summary.dmarc.pass
)
or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)
and (
profile.by_sender().solicited == false
or profile.by_sender_email().prevalence == "new"
or profile.by_sender_email().days_since.last_contact > 30
or (
profile.by_sender().any_messages_malicious_or_spam
and not profile.by_sender().any_messages_benign
)
// or it's a spoof of the org_domain
or (
sender.email.domain.domain in $org_domains
and not (
headers.auth_summary.spf.pass
or coalesce(headers.auth_summary.dmarc.pass, false)
)
)
)
and not profile.by_sender().any_messages_benign
Playground
Test against your own EMLs or sample data.