EXPLORE
← Back to Explore
sublimemediumRule

Brand impersonation: Sharepoint fake file share

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

Detection Query

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(ml.nlu_classifier(body.current_thread.text).topics,
             .name == "File Sharing and Cloud Services"
             and .confidence == "high"
      )
      //
      // 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
      //
      or strings.ilike(beta.ocr(file.message_screenshot()).text,
                       "*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*"
      )
      //
      // 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
      //
      or any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).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(file.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*&nbsp;\s*</td>\s*){2}\s*</tr>\s*<tr[^>]*>\s*(<td[^>]*bgcolor="#[0-9A-Fa-f]{6}"[^>]*>\s*&nbsp;\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, 'M\x{00AD}ic\x{00AD}ro\x{00AD}so\x{00AD}ft')
  )
  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)
            )
            or .href_url.domain.domain in $tenant_domains
            or any(.href_url.query_params_decoded["domain"],
                   strings.parse_url(strings.concat("https://", .)).domain.root_domain == "sharepoint.com"
            )
)
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 headers.in_reply_to is not null)
      // ensure that there are actual threads
      and (
        length(body.previous_threads) > 0
        or (length(body.html.display_text) - length(body.current_thread.text)) > 200
      )
    )
  )
)

// 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

Data Sources

Email MessagesEmail HeadersEmail Attachments

Platforms

email
Raw Content
name: "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.
type: "rule"
severity: "medium"
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(ml.nlu_classifier(body.current_thread.text).topics,
               .name == "File Sharing and Cloud Services"
               and .confidence == "high"
        )
        //
        // 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
        //
        or strings.ilike(beta.ocr(file.message_screenshot()).text,
                         "*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*"
        )
        //
        // 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
        //
        or any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).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(file.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*&nbsp;\s*</td>\s*){2}\s*</tr>\s*<tr[^>]*>\s*(<td[^>]*bgcolor="#[0-9A-Fa-f]{6}"[^>]*>\s*&nbsp;\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, 'M\x{00AD}ic\x{00AD}ro\x{00AD}so\x{00AD}ft')
    )
    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)
              )
              or .href_url.domain.domain in $tenant_domains
              or any(.href_url.query_params_decoded["domain"],
                     strings.parse_url(strings.concat("https://", .)).domain.root_domain == "sharepoint.com"
              )
  )
  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 headers.in_reply_to is not null)
        // ensure that there are actual threads
        and (
          length(body.previous_threads) > 0
          or (length(body.html.display_text) - length(body.current_thread.text)) > 200
        )
      )
    )
  )
  
  // 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
attack_types:
  - "Credential Phishing"
  - "Malware/Ransomware"
detection_methods:
  - "Content analysis"
  - "Header analysis"
  - "URL analysis"
  - "Computer Vision"
tactics_and_techniques:
  - "Impersonation: Brand"
  - "Social engineering"
id: "ff8b296b-aa0d-5df0-b4d2-0e599b688f6a"