Credential phishing: Generic document sharing

Detects credential phishing attempts using generic document sharing language where the sender claims to have sent a document for review, but the link doesn't point to legitimate file sharing services.

Sublime rule (View on GitHub)

  1name: "Credential phishing: Generic document sharing"
  2description: |
  3  Detects credential phishing attempts using generic document sharing language
  4  where the sender claims to have sent a document for review, but the link
  5  doesn't point to legitimate file sharing services.  
  6type: "rule"
  7severity: "medium"
  8source: |
  9  type.inbound
 10  // exclude if it's a reply to an existing conversation
 11  and (
 12    not length(body.previous_threads) > 0
 13    // still match if self-sender BCC pattern
 14    or (
 15      length(recipients.to) == 1
 16      and length(recipients.cc) == 0
 17      and sender.email.email == recipients.to[0].email.email
 18    )
 19  )
 20  and (
 21    // subject contains document sharing language
 22    regex.icontains(subject.base,
 23                    '\b(has\s+sent\s+you|sent\s+you|shared\s+with\s+you|document\s+to\s+review|document\s*(number|num|#)|file\s+to\s+review|proposal\s+(?:document|submission)|new\s+document|document\s+.{0,20}(assigned|available)|(complete|review|shared?).{0,20}agreement.{0,20}|document\s+(?:transfer|shared))\b'
 24    )
 25    or strings.icontains(subject.subject,
 26                         'document to review',
 27                         'file to review',
 28                         'sent you',
 29                         'eDocuments Notification'
 30    )
 31    or regex.icontains(subject.subject,
 32                       'proposal.{1,18}opportunit(?:ies|y)',
 33                       'ticket id:\s*[a-f0-9]{32}\b'
 34    )
 35    // or recipient's SLD is the subject
 36    or (
 37      subject.base == sender.email.domain.sld
 38      // account for near-matches
 39      or (
 40        length(subject.base) < length(sender.email.domain.sld)
 41        and any([subject.base], strings.icontains(sender.email.domain.sld, .))
 42      )
 43    )
 44    // blank subject with recipient SLD in message body
 45    or (
 46      (length(subject.base) == 0 or subject.base is null)
 47      and any(recipients.to,
 48              strings.istarts_with(body.current_thread.text, .email.domain.sld)
 49      )
 50    )
 51  )
 52  and (
 53    // body contains document sharing language
 54    regex.icontains(body.current_thread.text,
 55                    '\b(?:document\s+I\s+sent|proposal\s+document|(?:proposal|documents?)\s+for\s+your\s+(?:approval|consideration|review|signature)|see\s+the\s+below|document.*(?:review|posted)|file.*review|let\s+me\s+know\s+what\s+you\s+think|shared.{0,50}document|(?:review\s+and\s+)?sign\s+your\s+document|electronic\s+signature\s+required)\b'
 56    )
 57    or strings.icontains(body.current_thread.text,
 58                         'document I sent',
 59                         'kindly review',
 60                         'proposal document',
 61                         'let me know what you think',
 62                         'tasks assigned to you'
 63    )
 64    // account for image-as-content
 65    or (
 66      length(body.current_thread.text) < 10
 67      and (
 68        regex.icontains(beta.ocr(file.message_screenshot()).text,
 69                        '\b(document\s+I\s+sent|proposal\s+document|see\s+the\s+below|document.*review|file.*review|let\s+me\s+know\s+what\s+you\s+think|shared.{0,50}document)\b'
 70        )
 71        or strings.icontains(beta.ocr(file.message_screenshot()).text,
 72                             'document I sent',
 73                             'kindly review',
 74                             'proposal document',
 75                             'let me know what you think'
 76        )
 77      )
 78    )
 79  )
 80  // has links that look like file attachments but aren't
 81  and any(filter(body.links,
 82                 // display text looks like a file
 83                 (
 84                   regex.icontains(.display_text,
 85                                   '\.(pdf|doc|docx|goto|xls|xlsx|ppt|pptx)',
 86                                   '\d+kb|\d+mb'
 87                   )
 88                   or strings.icontains(.display_text,
 89                                        'document',
 90                                        'proposal',
 91                                        'review',
 92                                        'ticket'
 93                   )
 94  
 95                   // account for image-as-content
 96                   or (
 97                     length(body.current_thread.text) < 10
 98                     and length(body.links) == 1
 99                   )
100                 )
101                 // but the URL doesn't point to legitimate file sharing
102                 and .href_url.domain.root_domain not in (
103                   "sharepoint.com",
104                   "google.com",
105                   "dropbox.com",
106                   "box.com",
107                   "onedrive.com",
108                   "1drv.ms",
109                   "aka.ms",
110                   "microsoft.com",
111                   "office.com",
112                   "docusign.com",
113                   "adobesign.com",
114                   "hellosign.com",
115                   "signable.app"
116                 )
117                 and .href_url.domain.domain not in ("drive.google.com")
118          ),
119          // and points to suspicious domains
120          .href_url.domain.tld in $suspicious_tlds
121          or .href_url.domain.root_domain in $url_shorteners
122          or .href_url.domain.domain in $url_shorteners
123          or .href_url.domain.root_domain in $free_file_hosts
124          or .href_url.domain.domain in $free_file_hosts
125          // or it's a forms/survey platform being abused in self_service_creation_platform_domains
126          or .href_url.domain.root_domain in $self_service_creation_platform_domains
127          or .href_url.domain.domain in $self_service_creation_platform_domains
128          // bulk mailer abuse has been observed
129          or (
130            (
131              .href_url.domain.root_domain in $bulk_mailer_url_root_domains
132              or (
133                .href_url.rewrite.original is not null
134                and 'mandrill' in .href_url.rewrite.encoders
135              )
136            )
137            and .href_url.domain.sld not in $org_slds
138          )
139          // or the page redirects to common website, observed when evasion happens
140          or (
141            length(ml.link_analysis(., mode="aggressive").redirect_history) > 0
142            and ml.link_analysis(., mode="aggressive").effective_url.domain.root_domain in $tranco_10k
143          )
144          // or common email marketing/tracking patterns
145          or regex.match(.href_url.url, 'url\d+\..*\.com/ls/click')
146          or regex.match(.href_url.path, '/ls/click|/click|/c/')
147  )
148  // negate highly trusted sender domains unless they fail DMARC authentication
149  and not (
150    sender.email.domain.root_domain in $high_trust_sender_root_domains
151    and coalesce(headers.auth_summary.dmarc.pass, false)
152  )
153  and (
154    profile.by_sender().solicited == false
155    or profile.by_sender_email().prevalence == "new"
156    or profile.by_sender_email().days_since.last_contact > 30
157    or (
158      profile.by_sender().any_messages_malicious_or_spam
159      and not profile.by_sender().any_messages_benign
160    )
161    // or it's a spoof of the org_domain
162    or (
163      sender.email.domain.domain in $org_domains
164      and not (
165        headers.auth_summary.spf.pass
166        or coalesce(headers.auth_summary.dmarc.pass, false)
167      )
168    )
169  )
170  and not profile.by_sender().any_messages_benign
171    
172attack_types:
173  - "Credential Phishing"
174  - "BEC/Fraud"
175tactics_and_techniques:
176  - "Social engineering"
177  - "Evasion"
178  - "Impersonation: Employee"
179detection_methods:
180  - "Content analysis"
181  - "Natural Language Understanding"
182  - "URL analysis"
183  - "Sender analysis"
184id: "9f0e1d2c-3b4a-5c6d-7e8f-9a0b1c2d3e4f"
to-top