Detection rules › Sublime MQL

Attachment: Callback phishing solicitation via pdf file

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

A fraudulent invoice/receipt found in a pdf attachment. Callback Phishing is an attempt by an attacker to solicit the victim (recipient) to call a phone number. The resulting interaction could lead to a multitude of attacks ranging from Financial theft, Remote Access Trojan (RAT) Installation or Ransomware Deployment.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesEvasion, Free email provider, Out of band pivot, PDF, Social engineering

Event coverage

Rule body MQL

type.inbound
and (
  not profile.by_sender().solicited
  or (
    profile.by_sender().any_messages_malicious_or_spam
    and not profile.by_sender().any_messages_benign
  )
)

// single attachment
and length(attachments) == 1

// sender is freemail
and (
  sender.email.domain.root_domain in $free_email_providers
  // the sender is a common service, which has likely been sent through a DL
  or (
    sender.email.domain.root_domain in $tranco_50k
    and all(recipients.to, .email.domain.domain not in $org_domains)
  )
)
// the attachment is a pdf with less than 3 pages, and at least 60 ocr chars
and any(attachments,
        (
          .file_extension == "pdf"
          // get the length of the attached pdf
          and any(file.explode(.),
                  .depth == 0
                  and .scan.exiftool.page_count < 3
                  and (
                    not (
                      strings.istarts_with(.scan.exiftool.producer,
                                           "Aspose.Words for Java"
                      )
                      and (
                        .scan.exiftool.creator == "Anusha T"
                        or any(.scan.exiftool.fields,
                               .key == "Author" and .value == "Anusha T"
                        )
                      )
                    )
                    or .scan.exiftool.producer is null
                    or .scan.exiftool.creator is null
                  )
          )
          // negate ML matches to "Professional and Career Development" - tuning resume FPs
          and not (
            any(beta.ml_topic(coalesce(body.html.display_text, body.plain.raw)).topics,
                .name == "Professional and Career Development"
                and .confidence == "high"
            )
            or (
              (
                any(attachments,
                    .file_type == 'pdf'
                    and any(file.explode(.),
                            any(beta.ml_topic(.scan.ocr.raw).topics,
                                .name == "Professional and Career Development"
                                and .confidence == "high"
                            )
                    )
                )
              )
            )
          )
          // check that any _single_ result in the file.explode matches these conditions
          // a second file.explode is required because the OCR is generated at a different depth within
          // the file.explode results
          and (
            any(file.explode(.),
                length(.scan.ocr.raw) > 60
                // 4 of the following strings are found
                and 4 of (
                  // this section is synced with attachment_callback_phish_with_pdf.yml and body_callback_phishing_no_attachment.yml
                  strings.icontains(.scan.ocr.raw, "purchase"),
                  strings.icontains(.scan.ocr.raw, "payment"),
                  strings.icontains(.scan.ocr.raw, "transaction"),
                  strings.icontains(.scan.ocr.raw, "subscription"),
                  strings.icontains(.scan.ocr.raw, "antivirus"),
                  strings.icontains(.scan.ocr.raw, "order"),
                  strings.icontains(.scan.ocr.raw, "support"),
                  strings.icontains(.scan.ocr.raw, "help line"),
                  strings.icontains(.scan.ocr.raw, "receipt"),
                  strings.icontains(.scan.ocr.raw, "invoice"),
                  strings.icontains(.scan.ocr.raw, "call"),
                  strings.icontains(.scan.ocr.raw, "helpdesk"),
                  strings.icontains(.scan.ocr.raw, "cancel"),
                  strings.icontains(.scan.ocr.raw, "renew"),
                  strings.icontains(.scan.ocr.raw, "refund"),
                  regex.icontains(.scan.ocr.raw, "(?:reach|contact) us at"),
                  strings.icontains(.scan.ocr.raw, "+1"),
                  strings.icontains(.scan.ocr.raw, "amount"),
                  strings.icontains(.scan.ocr.raw, "charged"),
                  strings.icontains(.scan.ocr.raw, "crypto"),
                  strings.icontains(.scan.ocr.raw, "wallet address"),
                  regex.icontains(.scan.ocr.raw, '\$\d{3}\.\d{2}\b'),
                  regex.icontains(.scan.ocr.raw,
                                  '(\+[ilo0-9]|1.(\()?[ilo0-9]{3}(\))?\D[ilo0-9]{3}\D[ilo0-9]{4})',
                                  '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
                  ),
                )
                and (
                  // this section is synced with attachment_callback_phish_with_img.yml and body_callback_phishing_no_attachment.yml
                  regex.icontains(.scan.ocr.raw,
                                  '(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)'
                  )
                  // suspicious attachment name from the attachment object not file.explode() output
                  or regex.icontains(..file_name, 'INV(?:_|\s)?\d+(.pdf)$')
                )
                // Negate bank statements
                and not (
                  2 of (
                    strings.icontains(.scan.ocr.raw, "opening balance"),
                    strings.icontains(.scan.ocr.raw, "closing balance"),
                    strings.icontains(.scan.ocr.raw, "direct debit"),
                    strings.icontains(.scan.ocr.raw, "interest"),
                    strings.icontains(.scan.ocr.raw, "account balance"),
                  )
                )
            )
            // this section is synced with attachment_callback_phish_with_img.yml and body_callback_phishing_no_attachment.yml
            or any(ml.logo_detect(.).brands,
                   .name in (
                     "PayPal",
                     "Norton",
                     "GeekSquad",
                     "Ebay",
                     "McAfee",
                     "AT&T"
                   )
            )
          )
        )
)
and (
  (
    (length(headers.references) > 0 or headers.in_reply_to is null)
    and not (
      (
        strings.istarts_with(subject.subject, "RE:")
        or strings.istarts_with(subject.subject, "RES:")
        or strings.istarts_with(subject.subject, "R:")
        or strings.istarts_with(subject.subject, "ODG:")
        or strings.istarts_with(subject.subject, "答复:")
        or strings.istarts_with(subject.subject, "AW:")
        or strings.istarts_with(subject.subject, "TR:")
        or strings.istarts_with(subject.subject, "FWD:")
        or regex.imatch(subject.subject,
                        '(\[[^\]]+\]\s?){0,3}(re|fwd?|automat.*)\s?:.*'
        )
      )
    )
  )
  or (length(headers.references) == 0 or length(body.current_thread.text) < 10)
)

Detection logic

Scope: inbound message.

A fraudulent invoice/receipt found in a pdf attachment. Callback Phishing is an attempt by an attacker to solicit the victim (recipient) to call a phone number. The resulting interaction could lead to a multitude of attacks ranging from Financial theft, Remote Access Trojan (RAT) Installation or Ransomware Deployment.

  1. inbound message
  2. any of:
    • not:
      • profile.by_sender().solicited
    • all of:
      • profile.by_sender().any_messages_malicious_or_spam
      • not:
        • profile.by_sender().any_messages_benign
  3. length(attachments) is 1
  4. any of:
    • sender.email.domain.root_domain in $free_email_providers
    • all of:
      • sender.email.domain.root_domain in $tranco_50k
      • all of recipients.to where:
        • .email.domain.domain not in $org_domains
  5. any of attachments where all hold:
    • .file_extension is 'pdf'
    • any of file.explode(.) where all hold:
      • .depth is 0
      • .scan.exiftool.page_count < 3
      • any of:
        • not:
          • all of:
            • .scan.exiftool.producer starts with 'Aspose.Words for Java'
            • any of:
              • .scan.exiftool.creator is 'Anusha T'
              • any of .scan.exiftool.fields where all hold:
                • .key is 'Author'
                • .value is 'Anusha T'
        • .scan.exiftool.producer is missing
        • .scan.exiftool.creator is missing
    • none of:
      • any of beta.ml_topic(coalesce(body.html.display_text, body.plain.raw)).topics where all hold:
        • .name is 'Professional and Career Development'
        • .confidence is 'high'
      • any of attachments where all hold:
        • .file_type is 'pdf'
        • any of file.explode(.) where:
          • any of beta.ml_topic(.scan.ocr.raw).topics where all hold:
            • .name is 'Professional and Career Development'
            • .confidence is 'high'
    • any of:
      • any of file.explode(.) where all hold:
        • length(.scan.ocr.raw) > 60
        • at least 4 of:
          • .scan.ocr.raw contains 'purchase'
          • .scan.ocr.raw contains 'payment'
          • .scan.ocr.raw contains 'transaction'
          • .scan.ocr.raw contains 'subscription'
          • .scan.ocr.raw contains 'antivirus'
          • .scan.ocr.raw contains 'order'
          • .scan.ocr.raw contains 'support'
          • .scan.ocr.raw contains 'help line'
          • .scan.ocr.raw contains 'receipt'
          • .scan.ocr.raw contains 'invoice'
          • .scan.ocr.raw contains 'call'
          • .scan.ocr.raw contains 'helpdesk'
          • .scan.ocr.raw contains 'cancel'
          • .scan.ocr.raw contains 'renew'
          • .scan.ocr.raw contains 'refund'
          • .scan.ocr.raw matches '(?:reach|contact) us at'
          • .scan.ocr.raw contains '+1'
          • .scan.ocr.raw contains 'amount'
          • .scan.ocr.raw contains 'charged'
          • .scan.ocr.raw contains 'crypto'
          • .scan.ocr.raw contains 'wallet address'
          • .scan.ocr.raw matches '\\$\\d{3}\\.\\d{2}\\b'
          • .scan.ocr.raw matches any of 2 patterns
            • (\+[ilo0-9]|1.(\()?[ilo0-9]{3}(\))?\D[ilo0-9]{3}\D[ilo0-9]{4})
            • \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
        • any of:
          • .scan.ocr.raw matches '(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)'
          • .file_name matches 'INV(?:_|\\s)?\\d+(.pdf)$'
        • not:
          • at least 2 of 5: .scan.ocr.raw contains any of 5 patterns
            • opening balance
            • closing balance
            • direct debit
            • interest
            • account balance
      • any of ml.logo_detect(.).brands where:
        • .name in ('PayPal', 'Norton', 'GeekSquad', 'Ebay', 'McAfee', 'AT&T')
  6. any of:
    • all of:
      • any of:
        • length(headers.references) > 0
        • headers.in_reply_to is missing
      • none of:
        • subject.subject starts with 'RE:'
        • subject.subject starts with 'RES:'
        • subject.subject starts with 'R:'
        • subject.subject starts with 'ODG:'
        • subject.subject starts with '答复:'
        • subject.subject starts with 'AW:'
        • subject.subject starts with 'TR:'
        • subject.subject starts with 'FWD:'
        • subject.subject matches '(\\[[^\\]]+\\]\\s?){0,3}(re|fwd?|automat.*)\\s?:.*'
    • any of:
      • length(headers.references) is 0
      • length(body.current_thread.text) < 10

Inspects: attachments[].file_extension, attachments[].file_name, attachments[].file_type, body.current_thread.text, body.html.display_text, body.plain.raw, headers.in_reply_to, headers.references, recipients.to, recipients.to[].email.domain.domain, sender.email.domain.root_domain, subject.subject, type.inbound. Sensors: beta.ml_topic, file.explode, ml.logo_detect, profile.by_sender, regex.icontains, regex.imatch, strings.icontains, strings.istarts_with. Reference lists: $free_email_providers, $org_domains, $tranco_50k.

Indicators matched (56)

FieldMatchValue
attachments[].file_extensionequalspdf
strings.istarts_withprefixAspose.Words for Java
file.explode(attachments[])[].scan.exiftool.creatorequalsAnusha T
file.explode(attachments[])[].scan.exiftool.fields[].keyequalsAuthor
file.explode(attachments[])[].scan.exiftool.fields[].valueequalsAnusha T
beta.ml_topic(coalesce(body.html.display_text, body.plain.raw)).topics[].nameequalsProfessional and Career Development
beta.ml_topic(coalesce(body.html.display_text, body.plain.raw)).topics[].confidenceequalshigh
attachments[].file_typeequalspdf
beta.ml_topic(file.explode(attachments[])[].scan.ocr.raw).topics[].nameequalsProfessional and Career Development
beta.ml_topic(file.explode(attachments[])[].scan.ocr.raw).topics[].confidenceequalshigh
strings.icontainssubstringpurchase
strings.icontainssubstringpayment
44 more
strings.icontainssubstringtransaction
strings.icontainssubstringsubscription
strings.icontainssubstringantivirus
strings.icontainssubstringorder
strings.icontainssubstringsupport
strings.icontainssubstringhelp line
strings.icontainssubstringreceipt
strings.icontainssubstringinvoice
strings.icontainssubstringcall
strings.icontainssubstringhelpdesk
strings.icontainssubstringcancel
strings.icontainssubstringrenew
strings.icontainssubstringrefund
regex.icontainsregex(?:reach|contact) us at
strings.icontainssubstring+1
strings.icontainssubstringamount
strings.icontainssubstringcharged
strings.icontainssubstringcrypto
strings.icontainssubstringwallet address
regex.icontainsregex\$\d{3}\.\d{2}\b
regex.icontainsregex(\+[ilo0-9]|1.(\()?[ilo0-9]{3}(\))?\D[ilo0-9]{3}\D[ilo0-9]{4})
regex.icontainsregex\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
regex.icontainsregex(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)
regex.icontainsregexINV(?:_|\s)?\d+(.pdf)$
strings.icontainssubstringopening balance
strings.icontainssubstringclosing balance
strings.icontainssubstringdirect debit
strings.icontainssubstringinterest
strings.icontainssubstringaccount balance
ml.logo_detect(attachments[]).brands[].namememberPayPal
ml.logo_detect(attachments[]).brands[].namememberNorton
ml.logo_detect(attachments[]).brands[].namememberGeekSquad
ml.logo_detect(attachments[]).brands[].namememberEbay
ml.logo_detect(attachments[]).brands[].namememberMcAfee
ml.logo_detect(attachments[]).brands[].namememberAT&T
strings.istarts_withprefixRE:
strings.istarts_withprefixRES:
strings.istarts_withprefixR:
strings.istarts_withprefixODG:
strings.istarts_withprefix答复:
strings.istarts_withprefixAW:
strings.istarts_withprefixTR:
strings.istarts_withprefixFWD:
regex.imatchregex(\[[^\]]+\]\s?){0,3}(re|fwd?|automat.*)\s?:.*