Brand impersonation: Sharepoint

Body, attached images or pdf contains a Sharepoint logo. The message contains a link and credential theft language.

Sublime rule (View on GitHub)

  1name: "Brand impersonation: Sharepoint"
  2description: |
  3    Body, attached images or pdf contains a Sharepoint logo. The message contains a link and credential theft language.
  4type: "rule"
  5severity: "high"
  6source: |
  7  type.inbound
  8  and length(body.links) > 0
  9  and (
 10    any(attachments,
 11        (.file_type in $file_types_images or .file_type == "pdf")
 12        and any(ml.logo_detect(.).brands, .name == "Microsoft SharePoint")
 13    )
 14    or any(ml.logo_detect(file.message_screenshot()).brands,
 15           .name == "Microsoft SharePoint"
 16    )
 17    or strings.istarts_with(strings.replace_confusables(body.current_thread.text),
 18                            "Sharepoint"
 19    )
 20    or regex.icontains(body.html.raw,
 21                       '<img.*(title=|alt=).share.*src=""'
 22    ) // broken Sharepoint logo
 23    or (
 24      strings.icontains(strings.replace_confusables(body.plain.raw), "SharePoint")
 25      // message body references file deletion
 26      and regex.icontains(body.plain.raw,
 27                          '(expired )?file\s(was|has been|will be|scheduled (for|to be))\s?delet(ed|ion)'
 28      )
 29    )
 30    or (
 31      strings.icontains(body.current_thread.text, 'Sharepoint')
 32      and (
 33        regex.icontains(body.html.raw, '{(?:domain|randomNumber\d?)}')
 34        or any(body.links,
 35               regex.icontains(.href_url.url, 'mailto:[^@]+@{domain}')
 36        )
 37        or regex.icontains(body.html.raw, '<title>[^<]*Easearch[^<]*</title>')
 38      )
 39    )
 40  )
 41  and (
 42    (
 43      any(ml.nlu_classifier(body.current_thread.text).intents,
 44          .name == "cred_theft" and .confidence == "high"
 45      )
 46      //
 47      // This rule makes use of a beta feature and is subject to change without notice
 48      // using the beta feature in custom rules is not suggested until it has been formally released
 49      //
 50      or any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents,
 51             .name == "cred_theft" and .confidence == "high"
 52      )
 53      or any(attachments,
 54             .file_type == "pdf"
 55             and beta.parse_exif(.).page_count == 1
 56             and any(file.explode(.),
 57                     any(ml.nlu_classifier(.scan.ocr.raw).intents,
 58                         .name == "cred_theft" and .confidence == "high"
 59                     )
 60             )
 61      )
 62    )
 63    or any(ml.nlu_classifier(body.current_thread.text).entities,
 64           .name == "urgency" and strings.ilike(.text, "*encrypted*")
 65    )
 66    or any(body.links,
 67           regex.imatch(.display_text,
 68                        '(?:re)?view (?:(?:&|and) (?:e([[:punct:]]|\s)?)?sign )?(?:complete )?(?:document|file)'
 69           )
 70    )
 71  )
 72  and not (
 73    (
 74      (
 75        strings.istarts_with(subject.subject, "RE:")
 76        or strings.istarts_with(subject.subject, "R:")
 77        or strings.istarts_with(subject.subject, "ODG:")
 78        or strings.istarts_with(subject.subject, "答复:")
 79        or strings.istarts_with(subject.subject, "AW:")
 80        or strings.istarts_with(subject.subject, "TR:")
 81        or strings.istarts_with(subject.subject, "FWD:")
 82        or regex.imatch(subject.subject, '(\[[^\]]+\]\s?){0,3}(re|fwd?)\s?:')
 83        or regex.imatch(subject.subject,
 84                        '^\[?(EXT|EXTERNAL)\]?[: ]\s*(RE|FWD?|FW|AW|TR|ODG|答复):.*'
 85        )
 86      )
 87      and (
 88        (length(headers.references) > 0 or headers.in_reply_to is not null)
 89        // ensure that there are actual threads
 90        and (
 91          length(body.previous_threads) > 0
 92          or (length(body.html.display_text) - length(body.current_thread.text)) > 200
 93        )
 94      )
 95    )
 96  )
 97  and (
 98    profile.by_sender_email().prevalence != 'common'
 99    or not profile.by_sender_email().solicited
100    or profile.by_sender().any_messages_malicious_or_spam
101  )
102  and not profile.by_sender().any_messages_benign
103  
104  // negate highly trusted sender domains unless they fail DMARC authentication
105  and (
106    (
107      sender.email.domain.root_domain in $high_trust_sender_root_domains
108      and not headers.auth_summary.dmarc.pass
109    )
110    or sender.email.domain.root_domain not in $high_trust_sender_root_domains
111  )
112  
113  // negate sharepoint file share
114  and not (
115    // based on the message id format
116    (
117      (
118        strings.starts_with(headers.message_id, '<Share-')
119        and strings.ends_with(headers.message_id, '@odspnotify>')
120      )
121      // negate legitimate access request to file
122      or (
123        strings.starts_with(headers.message_id, '<Sharing')
124        and strings.ends_with(headers.message_id, '@odspnotify>')
125      )
126      // deal with Google thinking the message ID is "broke"
127      or (
128        strings.icontains(headers.message_id, 'SMTPIN_ADDED_BROKEN')
129        and any(headers.hops,
130                any(.fields,
131                    .name == "X-Google-Original-Message-ID"
132                    and strings.starts_with(.value, '<Share-')
133                    and strings.ends_with(.value, '@odspnotify>')
134                )
135        )
136      )
137    )
138    // all of the "action" links are sharepoint/ms
139    and all(filter(body.links,
140                   strings.icontains(subject.subject, .display_text)
141                   or .display_text == "Open"
142            ),
143            .href_url.domain.root_domain in ("sharepoint.com", "1drv.ms")
144            or (
145              .href_url.domain.tld == "ms"
146              // Microsoft does not own the .ms TLD, this checks to ensure it is one of their domains
147              and (
148                network.whois(.href_url.domain).registrant_company == "Microsoft Corporation"
149                or strings.ilike(network.whois(.href_url.domain).registrar_name,
150                                 "*MarkMonitor*",
151                                 "*CSC Corporate*",
152                                 "*com laude*"
153                )
154              )
155            )
156    )
157  )
158  // negate sharepoint file shares with mimecast rewrites
159  and not (
160    // rewritten message ID
161    strings.iends_with(headers.message_id, 'mimecast.lan>')
162    and all(filter(body.links,
163                   strings.icontains(subject.subject, .display_text)
164                   or .display_text == "Open"
165            ),
166            .href_url.domain.root_domain in (
167              "mimecastprotect.com",
168              "mimecast.com"
169            )
170            and any(.href_url.query_params_decoded["domain"],
171                    strings.parse_domain(.).tld == "ms"
172                    or strings.parse_domain(.).root_domain == "sharepoint.com"
173            )
174    )
175  )  
176attack_types:
177  - "Credential Phishing"
178tactics_and_techniques:
179  - "Impersonation: Brand"
180  - "Social engineering"
181detection_methods:
182  - "Computer Vision"
183  - "Content analysis"
184  - "File analysis"
185  - "Natural Language Understanding"
186  - "Sender analysis"
187id: "284b1b70-8daa-5adf-9df8-15d4c6b5ead9"
to-top