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 not length(body.previous_threads) > 0
 12  and (
 13    // subject contains document sharing language
 14    regex.icontains(subject.base,
 15                    '\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|new\s+document|document\s+.{0,20}assigned|(complete|review|shared?).{0,20}agreement.{0,20}|document\s+(?:transfer|shared))\b'
 16    )
 17    or strings.icontains(subject.subject, 'document to review')
 18    or strings.icontains(subject.subject, 'file to review')
 19    or strings.icontains(subject.subject, 'sent you')
 20    or strings.icontains(subject.subject, 'eDocuments Notification')
 21    // or recipient's SLD is the subject
 22    or (
 23      subject.base == sender.email.domain.sld
 24      // account for near-matches
 25      or (
 26        length(subject.base) < length(sender.email.domain.sld)
 27        and any([subject.base], strings.icontains(sender.email.domain.sld, .))
 28      )
 29    )
 30  )
 31  and (
 32    // body contains document sharing language
 33    regex.icontains(body.current_thread.text,
 34                    '\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|file.*review|let\s+me\s+know\s+what\s+you\s+think|shared.{0,50}document)\b'
 35    )
 36    or strings.icontains(body.current_thread.text, 'document I sent')
 37    or strings.icontains(body.current_thread.text, 'proposal document')
 38    or strings.icontains(body.current_thread.text, 'let me know what you think')
 39    // account for image-as-content
 40    or (
 41      length(body.current_thread.text) < 10
 42      and (
 43        regex.icontains(beta.ocr(file.message_screenshot()).text,
 44                        '\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'
 45        )
 46        or strings.icontains(beta.ocr(file.message_screenshot()).text,
 47                             'document I sent'
 48        )
 49        or strings.icontains(beta.ocr(file.message_screenshot()).text,
 50                             'proposal document'
 51        )
 52        or strings.icontains(beta.ocr(file.message_screenshot()).text,
 53                             'let me know what you think'
 54        )
 55      )
 56    )
 57  )
 58  // has links that look like file attachments but aren't
 59  and any(filter(body.links,
 60                 // display text looks like a file
 61                 (
 62                   regex.icontains(.display_text,
 63                                   '\.(pdf|doc|docx|goto|xls|xlsx|ppt|pptx)'
 64                   )
 65                   or regex.icontains(.display_text, '\d+kb|\d+mb')
 66                   or strings.icontains(.display_text, 'document')
 67                   or strings.icontains(.display_text, 'proposal')
 68                   or strings.icontains(.display_text, 'review')
 69                   // account for image-as-content
 70                   or (
 71                     length(body.current_thread.text) < 10
 72                     and length(body.links) == 1
 73                   )
 74                 )
 75                 // but the URL doesn't point to legitimate file sharing
 76                 and .href_url.domain.root_domain not in (
 77                   "sharepoint.com",
 78                   "google.com",
 79                   "drive.google.com",
 80                   "dropbox.com",
 81                   "box.com",
 82                   "onedrive.com",
 83                   "1drv.ms",
 84                   "aka.ms",
 85                   "microsoft.com",
 86                   "office.com",
 87                   "docusign.com",
 88                   "adobesign.com",
 89                   "hellosign.com",
 90                   "signable.app"
 91                 )
 92          ),
 93          // and points to suspicious domains
 94          .href_url.domain.tld in $suspicious_tlds
 95          or .href_url.domain.root_domain in $url_shorteners
 96          or .href_url.domain.domain in $url_shorteners
 97          or .href_url.domain.root_domain in $free_file_hosts
 98          or .href_url.domain.domain in $free_file_hosts
 99          // or it's a forms/survey platform being abused in self_service_creation_platform_domains
100          or .href_url.domain.root_domain in $self_service_creation_platform_domains
101          or .href_url.domain.domain in $self_service_creation_platform_domains
102          // bulk mailer abuse has been observed
103          or (
104            .href_url.domain.root_domain in $bulk_mailer_url_root_domains
105            and .href_url.domain.sld not in $org_slds
106          )
107          // or the page redirects to common website, observed when evasion happens
108          or (
109            length(ml.link_analysis(., mode="aggressive").redirect_history) > 0
110            and ml.link_analysis(., mode="aggressive").effective_url.domain.root_domain in $tranco_10k
111          )
112          // or common email marketing/tracking patterns
113          or regex.match(.href_url.url, 'url\d+\..*\.com/ls/click')
114          or regex.match(.href_url.path, '/ls/click|/click|/c/')
115  )
116  // negate highly trusted sender domains unless they fail DMARC authentication
117  and (
118    (
119      sender.email.domain.root_domain in $high_trust_sender_root_domains
120      and not headers.auth_summary.dmarc.pass
121    )
122    or sender.email.domain.root_domain not in $high_trust_sender_root_domains
123  )
124  and (
125    profile.by_sender().solicited == false
126    or profile.by_sender_email().prevalence == "new"
127    or profile.by_sender_email().days_since.last_contact > 30
128    or (
129      profile.by_sender().any_messages_malicious_or_spam
130      and not profile.by_sender().any_messages_benign
131    )
132    // or it's a spoof of the org_domain
133    or (
134      sender.email.domain.domain in $org_domains
135      and not (
136        headers.auth_summary.spf.pass
137        or coalesce(headers.auth_summary.dmarc.pass, false)
138      )
139    )
140  )
141  and not profile.by_sender().any_messages_benign
142    
143attack_types:
144  - "Credential Phishing"
145  - "BEC/Fraud"
146tactics_and_techniques:
147  - "Social engineering"
148  - "Evasion"
149  - "Impersonation: Employee"
150detection_methods:
151  - "Content analysis"
152  - "Natural Language Understanding"
153  - "URL analysis"
154  - "Sender analysis"
155id: "9f0e1d2c-3b4a-5c6d-7e8f-9a0b1c2d3e4f"
to-top