Detection rules › Sublime MQL

Credential phishing: Generic document sharing

Severity
medium
Type
rule
Source
github.com/sublime-security/sublime-rules

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.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing, BEC/Fraud
Tactics and techniquesSocial engineering, Evasion, Impersonation: Employee

Event coverage

Rule body MQL

type.inbound
// exclude if it's a reply to an existing conversation
and (
  not length(body.previous_threads) > 0
  // still match if self-sender BCC pattern
  or (
    length(recipients.to) == 1
    and length(recipients.cc) == 0
    and sender.email.email == recipients.to[0].email.email
  )
)
and (
  // subject contains document sharing language
  regex.icontains(subject.base,
                  '\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|available)|(complete|review|shared?).{0,20}agreement.{0,20}|document\s+(?:transfer|shared))\b'
  )
  or strings.icontains(subject.subject, 'document to review')
  or strings.icontains(subject.subject, 'file to review')
  or strings.icontains(subject.subject, 'sent you')
  or strings.icontains(subject.subject, 'eDocuments Notification')
  // or recipient's SLD is the subject
  or (
    subject.base == sender.email.domain.sld
    // account for near-matches
    or (
      length(subject.base) < length(sender.email.domain.sld)
      and any([subject.base], strings.icontains(sender.email.domain.sld, .))
    )
  )
  // blank subject with recipient SLD in message body
  or (
    (length(subject.base) == 0 or subject.base is null)
    and any(recipients.to,
            strings.istarts_with(body.current_thread.text, .email.domain.sld)
    )
  )
)
and (
  // body contains document sharing language
  regex.icontains(body.current_thread.text,
                  '\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'
  )
  or strings.icontains(body.current_thread.text, 'document I sent')
  or strings.icontains(body.current_thread.text, 'proposal document')
  or strings.icontains(body.current_thread.text, 'let me know what you think')
  // account for image-as-content
  or (
    length(body.current_thread.text) < 10
    and (
      regex.icontains(beta.ocr(file.message_screenshot()).text,
                      '\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'
      )
      or strings.icontains(beta.ocr(file.message_screenshot()).text,
                           'document I sent'
      )
      or strings.icontains(beta.ocr(file.message_screenshot()).text,
                           'proposal document'
      )
      or strings.icontains(beta.ocr(file.message_screenshot()).text,
                           'let me know what you think'
      )
    )
  )
)
// has links that look like file attachments but aren't
and any(filter(body.links,
               // display text looks like a file
               (
                 regex.icontains(.display_text,
                                 '\.(pdf|doc|docx|goto|xls|xlsx|ppt|pptx)'
                 )
                 or regex.icontains(.display_text, '\d+kb|\d+mb')
                 or strings.icontains(.display_text, 'document')
                 or strings.icontains(.display_text, 'proposal')
                 or strings.icontains(.display_text, 'review')
                 // account for image-as-content
                 or (
                   length(body.current_thread.text) < 10
                   and length(body.links) == 1
                 )
               )
               // but the URL doesn't point to legitimate file sharing
               and .href_url.domain.root_domain not in (
                 "sharepoint.com",
                 "google.com",
                 "dropbox.com",
                 "box.com",
                 "onedrive.com",
                 "1drv.ms",
                 "aka.ms",
                 "microsoft.com",
                 "office.com",
                 "docusign.com",
                 "adobesign.com",
                 "hellosign.com",
                 "signable.app"
               )
               and .href_url.domain.domain not in ("drive.google.com")
        ),
        // and points to suspicious domains
        .href_url.domain.tld in $suspicious_tlds
        or .href_url.domain.root_domain in $url_shorteners
        or .href_url.domain.domain in $url_shorteners
        or .href_url.domain.root_domain in $free_file_hosts
        or .href_url.domain.domain in $free_file_hosts
        // or it's a forms/survey platform being abused in self_service_creation_platform_domains
        or .href_url.domain.root_domain in $self_service_creation_platform_domains
        or .href_url.domain.domain in $self_service_creation_platform_domains
        // bulk mailer abuse has been observed
        or (
          (
            .href_url.domain.root_domain in $bulk_mailer_url_root_domains
            or (
              .href_url.rewrite.original is not null
              and 'mandrill' in .href_url.rewrite.encoders
            )
          )
          and .href_url.domain.sld not in $org_slds
        )
        // or the page redirects to common website, observed when evasion happens
        or (
          length(ml.link_analysis(., mode="aggressive").redirect_history) > 0
          and ml.link_analysis(., mode="aggressive").effective_url.domain.root_domain in $tranco_10k
        )
        // or common email marketing/tracking patterns
        or regex.match(.href_url.url, 'url\d+\..*\.com/ls/click')
        or regex.match(.href_url.path, '/ls/click|/click|/c/')
)
// 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

Detection logic

Scope: inbound message.

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.

  1. inbound message
  2. any of:
    • not:
      • length(body.previous_threads) > 0
    • all of:
      • length(recipients.to) is 1
      • length(recipients.cc) is 0
      • sender.email.email is recipients.to[0].email.email
  3. any of:
    • subject.base matches '\\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|available)|(complete|review|shared?).{0,20}agreement.{0,20}|document\\s+(?:transfer|shared))\\b'
    • subject.subject contains 'document to review'
    • subject.subject contains 'file to review'
    • subject.subject contains 'sent you'
    • subject.subject contains 'eDocuments Notification'
    • any of:
      • subject.base is sender.email.domain.sld
      • all of:
        • length(subject.base) < length(sender.email.domain.sld)
        • any of [subject.base] where:
          • strings.icontains(sender.email.domain.sld)
    • all of:
      • any of:
        • length(subject.base) is 0
        • subject.base is missing
      • any of recipients.to where:
        • strings.istarts_with(body.current_thread.text)
  4. any of:
    • body.current_thread.text matches '\\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'
    • body.current_thread.text contains 'document I sent'
    • body.current_thread.text contains 'proposal document'
    • body.current_thread.text contains 'let me know what you think'
    • all of:
      • length(body.current_thread.text) < 10
      • any of:
        • beta.ocr(file.message_screenshot()).text matches '\\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'
        • beta.ocr(file.message_screenshot()).text contains 'document I sent'
        • beta.ocr(file.message_screenshot()).text contains 'proposal document'
        • beta.ocr(file.message_screenshot()).text contains 'let me know what you think'
  5. any of filter(body.links) where any holds:
    • .href_url.domain.tld in $suspicious_tlds
    • .href_url.domain.root_domain in $url_shorteners
    • .href_url.domain.domain in $url_shorteners
    • .href_url.domain.root_domain in $free_file_hosts
    • .href_url.domain.domain in $free_file_hosts
    • .href_url.domain.root_domain in $self_service_creation_platform_domains
    • .href_url.domain.domain in $self_service_creation_platform_domains
    • all of:
      • any of:
        • .href_url.domain.root_domain in $bulk_mailer_url_root_domains
        • all of:
          • .href_url.rewrite.original is set
          • .href_url.rewrite.encoders contains 'mandrill'
      • .href_url.domain.sld not in $org_slds
    • all of:
      • length(ml.link_analysis(., mode='aggressive').redirect_history) > 0
      • ml.link_analysis(.).effective_url.domain.root_domain in $tranco_10k
    • .href_url.url matches 'url\\d+\\..*\\.com/ls/click'
    • .href_url.path matches '/ls/click|/click|/c/'
  6. any of:
    • all of:
      • sender.email.domain.root_domain in $high_trust_sender_root_domains
      • not:
        • headers.auth_summary.dmarc.pass
    • sender.email.domain.root_domain not in $high_trust_sender_root_domains
  7. any of:
    • profile.by_sender().solicited is False
    • profile.by_sender_email().prevalence is 'new'
    • profile.by_sender_email().days_since.last_contact > 30
    • all of:
      • profile.by_sender().any_messages_malicious_or_spam
      • not:
        • profile.by_sender().any_messages_benign
    • all of:
      • sender.email.domain.domain in $org_domains
      • none of:
        • headers.auth_summary.spf.pass
        • coalesce(headers.auth_summary.dmarc.pass)
  8. not:
    • profile.by_sender().any_messages_benign

Inspects: body.current_thread.text, body.links, body.links[].display_text, body.links[].href_url.domain.domain, body.links[].href_url.domain.root_domain, body.previous_threads, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, recipients.cc, recipients.to, recipients.to[0].email.email, recipients.to[].email.domain.sld, sender.email.domain.domain, sender.email.domain.root_domain, sender.email.domain.sld, sender.email.email, subject.base, subject.subject, type.inbound. Sensors: beta.ocr, file.message_screenshot, ml.link_analysis, profile.by_sender, profile.by_sender_email, regex.icontains, regex.match, strings.icontains, strings.istarts_with. Reference lists: $bulk_mailer_url_root_domains, $free_file_hosts, $high_trust_sender_root_domains, $org_domains, $org_slds, $self_service_creation_platform_domains, $suspicious_tlds, $tranco_10k, $url_shorteners.

Indicators matched (32)

FieldMatchValue
regex.icontainsregex\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|available)|(complete|review|shared?).{0,20}agreement.{0,20}|document\s+(?:transfer|shared))\b
strings.icontainssubstringdocument to review
strings.icontainssubstringfile to review
strings.icontainssubstringsent you
strings.icontainssubstringeDocuments Notification
regex.icontainsregex\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
strings.icontainssubstringdocument I sent
strings.icontainssubstringproposal document
strings.icontainssubstringlet me know what you think
regex.icontainsregex\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
regex.icontainsregex\.(pdf|doc|docx|goto|xls|xlsx|ppt|pptx)
regex.icontainsregex\d+kb|\d+mb
20 more
strings.icontainssubstringdocument
strings.icontainssubstringproposal
strings.icontainssubstringreview
body.links[].href_url.domain.root_domainmembersharepoint.com
body.links[].href_url.domain.root_domainmembergoogle.com
body.links[].href_url.domain.root_domainmemberdropbox.com
body.links[].href_url.domain.root_domainmemberbox.com
body.links[].href_url.domain.root_domainmemberonedrive.com
body.links[].href_url.domain.root_domainmember1drv.ms
body.links[].href_url.domain.root_domainmemberaka.ms
body.links[].href_url.domain.root_domainmembermicrosoft.com
body.links[].href_url.domain.root_domainmemberoffice.com
body.links[].href_url.domain.root_domainmemberdocusign.com
body.links[].href_url.domain.root_domainmemberadobesign.com
body.links[].href_url.domain.root_domainmemberhellosign.com
body.links[].href_url.domain.root_domainmembersignable.app
body.links[].href_url.domain.domainmemberdrive.google.com
filter(body.links)[].href_url.rewrite.encoderscontainsmandrill
regex.matchregexurl\d+\..*\.com/ls/click
regex.matchregex/ls/click|/click|/c/