Callback Phishing via Signable E-Signature Request

This rule inspects messages originating from legitimate Signable infrastructure, with content matching Callback Phishing criteria, in the body, requiring at least one brand name, as well as 3 matching Callback Phishing terms and a phone number.

Sublime rule (View on GitHub)

  1name: "Callback Phishing via Signable E-Signature Request"
  2description: "This rule inspects messages originating from legitimate Signable infrastructure, with content matching Callback Phishing criteria, in the body, requiring at least one brand name, as well as 3 matching Callback Phishing terms and a phone number."
  3type: "rule"
  4severity: "high"
  5source: |
  6  type.inbound
  7  and length(attachments) == 0
  8  and (
  9    not beta.profile.by_reply_to().solicited
 10    or (
 11      beta.profile.by_reply_to().any_messages_malicious_or_spam
 12      and not beta.profile.by_reply_to().any_messages_benign
 13    )
 14  )
 15  // Legitimate Signable sending infratructure
 16  and sender.email.domain.root_domain == 'signable.app'
 17  and (headers.auth_summary.spf.pass or headers.auth_summary.dmarc.pass)
 18  and (
 19    // this section is synced with attachment_callback_phish_with_pdf.yml and attachment_callback_phish_with_img.yml
 20    regex.icontains(strings.replace_confusables(body.current_thread.text),
 21                    '(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)'
 22    )
 23    or any(ml.logo_detect(beta.message_screenshot()).brands,
 24           .name in (
 25             "PayPal",
 26             "Norton",
 27             "GeekSquad",
 28             "Ebay",
 29             "McAfee",
 30             "AT&T",
 31             "Microsoft"
 32           )
 33    )
 34  )
 35  and length(body.current_thread.text) < 1750
 36  and (
 37    (
 38      // this seciton is synced with attachment_callback_phish_with_img.yml and attachment_callback_phish_with_pdf.yml
 39      // however, the 3 of logic and requiring a phone number is specific to this rule in order to reduce FPs
 40      // caused by messages which mention cancelling or otherwise managing a subscription
 41      // it is also synced and below for message_screenshot OCR output
 42      3 of (
 43        strings.icontains(body.current_thread.text, 'purchase'),
 44        strings.icontains(body.current_thread.text, 'payment'),
 45        strings.icontains(body.current_thread.text, 'transaction'),
 46        strings.icontains(body.current_thread.text, 'subscription'),
 47        strings.icontains(body.current_thread.text, 'antivirus'),
 48        strings.icontains(body.current_thread.text, 'order'),
 49        strings.icontains(body.current_thread.text, 'support'),
 50        strings.icontains(body.current_thread.text, 'help line'),
 51        strings.icontains(body.current_thread.text, 'receipt'),
 52        strings.icontains(body.current_thread.text, 'invoice'),
 53        strings.icontains(body.current_thread.text, 'call'),
 54        strings.icontains(body.current_thread.text, 'cancel'),
 55        strings.icontains(body.current_thread.text, 'renew'),
 56        strings.icontains(body.current_thread.text, 'refund'),
 57        regex.icontains(body.current_thread.text, "(?:reach|contact) us at"),
 58        strings.icontains(body.current_thread.text, "+1"),
 59        strings.icontains(body.current_thread.text, "amount"),
 60        strings.icontains(body.current_thread.text, "charged"),
 61        strings.icontains(body.current_thread.text, "crypto"),
 62        strings.icontains(body.current_thread.text, "wallet address"),
 63        regex.icontains(body.current_thread.text, '\$\d{3}\.\d{2}\b'),
 64      )
 65      // phone number regex
 66      and regex.icontains(body.current_thread.text,
 67                          '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
 68                          '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
 69      )
 70    )
 71    or (
 72      any(file.explode(beta.message_screenshot()),
 73          // this seciton is synced with attachment_callback_phish_with_img.yml and attachment_callback_phish_with_pdf.yml
 74          // and above for current_thread.text
 75          3 of (
 76            strings.icontains(.scan.ocr.raw, 'purchase'),
 77            strings.icontains(.scan.ocr.raw, 'payment'),
 78            strings.icontains(.scan.ocr.raw, 'transaction'),
 79            strings.icontains(.scan.ocr.raw, 'subscription'),
 80            strings.icontains(.scan.ocr.raw, 'antivirus'),
 81            strings.icontains(.scan.ocr.raw, 'order'),
 82            strings.icontains(.scan.ocr.raw, 'support'),
 83            strings.icontains(.scan.ocr.raw, 'help line'),
 84            strings.icontains(.scan.ocr.raw, 'receipt'),
 85            strings.icontains(.scan.ocr.raw, 'invoice'),
 86            strings.icontains(.scan.ocr.raw, 'call'),
 87            strings.icontains(.scan.ocr.raw, 'helpdesk'),
 88            strings.icontains(.scan.ocr.raw, 'cancel'),
 89            strings.icontains(.scan.ocr.raw, 'renew'),
 90            strings.icontains(.scan.ocr.raw, 'refund'),
 91            regex.icontains(.scan.ocr.raw, "(?:reach|contact) us at"),
 92            strings.icontains(.scan.ocr.raw, '+1'),
 93            strings.icontains(.scan.ocr.raw, 'amount'),
 94            strings.icontains(.scan.ocr.raw, 'charged'),
 95            strings.icontains(.scan.ocr.raw, 'crypto'),
 96            strings.icontains(.scan.ocr.raw, 'wallet address'),
 97            regex.icontains(.scan.ocr.raw, '\$\d{3}\.\d{2}\b'),
 98          )
 99          // phone number regex
100          and regex.icontains(.scan.ocr.raw,
101                              '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
102                              '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
103          )
104  
105          // negate messages with previous threads.  While callback phishing with thread hijacking or with current_thread 
106          // padded with whitespace and previous threads in the message has been observed, the intetion of using OCR is for image embedded callbacks
107          and not regex.icount(.scan.ocr.raw, '(?:from|to|sent|date|cc|subject):') > 3
108          // this notation of previous threads often only occurs once
109          and not regex.icontains(.scan.ocr.raw, 'wrote:[\r\n]')
110      )
111    )
112  )  
113
114attack_types:
115  - "Callback Phishing"
116tactics_and_techniques:
117  - "Exploit"
118  - "Impersonation: Brand"
119  - "Out of band pivot"
120  - "Social engineering"
121detection_methods:
122  - "Computer Vision"
123  - "Content analysis"
124  - "Header analysis"
125  - "Sender analysis"
126  - "URL analysis"
127id: "4599575d-6dd7-5785-bad9-4902eeff4e1b"
to-top