Attachment: EML with Sharepoint link likely unrelated to sender

Detects EML attachments containing SharePoint links where the subdomain differs significantly from the sender's domain, potentially indicating SharePoint impersonation or domain spoofing tactics.

Sublime rule (View on GitHub)

  1name: "Attachment: EML with Sharepoint link likely unrelated to sender"
  2description: "Detects EML attachments containing SharePoint links where the subdomain differs significantly from the sender's domain, potentially indicating SharePoint impersonation or domain spoofing tactics."
  3type: "rule"
  4severity: "medium"
  5source: |
  6  type.inbound
  7  and length(filter(attachments,
  8                    .file_extension == "eml" or .content_type == "message/rfc822"
  9             )
 10  ) == 1
 11  and any(attachments,
 12          any(filter(file.parse_eml(.).body.links,
 13                     .href_url.domain.root_domain == 'sharepoint.com'
 14              ),
 15              // Normalize Levenshtein distance by string length (0 = identical, 0.7+ = different)
 16              // Working with what we have in MQL, considering we dont have max() or any other forms of string distancing
 17              (
 18                (
 19                  strings.iends_with(.href_url.domain.subdomain,
 20                                     '-my'
 21                  ) // common Sharepoint subdomain suffix
 22                  and (
 23                    (
 24                      strings.ilevenshtein(.href_url.domain.subdomain,
 25                                           sender.email.domain.sld
 26                      ) - 3 // subtract aforementioned suffix for more accurate calculation
 27                    ) / (
 28                      (
 29                        (length(.href_url.domain.subdomain) - 3) + length(sender.email.domain.sld
 30                        )
 31   + (
 32                          (
 33                            (length(.href_url.domain.subdomain) - 3) - length(sender.email.domain.sld
 34                            )
 35                          ) + (
 36                            length(sender.email.domain.sld) - (
 37                              length(.href_url.domain.subdomain) - 3
 38                            )
 39                          )
 40                        )
 41                      ) / 2.0 // to ensure we keep the result as a float
 42                    )
 43                  ) > 0.7 // customizable threshold
 44                )
 45                or (
 46                  not strings.iends_with(.href_url.domain.subdomain,
 47                                         '-my'
 48                  ) // no suffix, continue with original calculation
 49                  and (
 50                    strings.ilevenshtein(.href_url.domain.subdomain,
 51                                         sender.email.domain.sld
 52                    ) / (
 53                      (
 54                        length(.href_url.domain.subdomain) + length(sender.email.domain.sld
 55                        )
 56   + (
 57                          (
 58                            length(.href_url.domain.subdomain) - length(sender.email.domain.sld
 59                            )
 60                          ) + (
 61                            length(sender.email.domain.sld) - length(.href_url.domain.subdomain
 62                            )
 63                          )
 64                        )
 65                      ) / 2.0 // to ensure we keep the result as a float
 66                    )
 67                  ) > 0.7 // customizable threshold
 68                )
 69              )
 70              and not strings.icontains(.href_url.path, sender.email.local_part)
 71              and not any($org_slds,
 72                          strings.icontains(..href_url.domain.subdomain, .)
 73              )
 74  
 75              // it is either a OneNote or PDF file, or unknown
 76              and regex.icontains(.href_url.path, '\/:[obu]:\/(?:p|g\/personal)')
 77          )
 78  )
 79  // a way to negate long threads
 80  // the full thread must be less than 6 times the length of the current thread
 81  and length(body.html.inner_text) < 6 * length(body.current_thread.text)
 82  and sender.email.domain.root_domain not in (
 83    "sharepoint.com",
 84    "sharepointonline.com"
 85  )
 86  
 87  // negate highly trusted sender domains unless they fail DMARC authentication
 88  and (
 89    (
 90      sender.email.domain.root_domain in $high_trust_sender_root_domains
 91      and not headers.auth_summary.dmarc.pass
 92    )
 93    or sender.email.domain.root_domain not in $high_trust_sender_root_domains
 94  )
 95  // negate instances where proofpoint sends a review of a reported message via analyzer 
 96  and not (
 97    any(headers.domains, .root_domain == "pphosted.com")
 98    and headers.auth_summary.spf.pass
 99    and headers.auth_summary.dmarc.pass
100  )   
101
102attack_types:
103  - "BEC/Fraud"
104  - "Credential Phishing"
105tactics_and_techniques:
106  - "Impersonation: Brand"
107  - "Social engineering"
108  - "Evasion"
109detection_methods:
110  - "File analysis"
111  - "URL analysis"
112  - "Header analysis"
113  - "Sender analysis"
114id: "0a4fd31b-3b85-5f84-959c-10d313cc8a4a"
to-top