Detection rules › Sublime MQL

Callback phishing via Intuit service abuse

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

Callback phishing campaigns have been observed abusing Intuit Quickbooks services to send fraudulent invoices with callback phishing contents.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesEvasion, Free email provider, Impersonation: Brand, Social engineering

Event coverage

Rule body MQL

type.inbound

// Legitimate Intuit sending infratructure
and (
  sender.email.domain.root_domain in ('intuit.com', 'intuit.co.uk')
  // check for SPF or DMARC passed
  and (headers.auth_summary.spf.pass or headers.auth_summary.dmarc.pass)
)
and (
  // Callback Phishing in body (brand names required)
  (
    length(attachments) == 0

    // brand names are required.
    and regex.icontains(strings.replace_confusables(body.current_thread.text),
                        (
                          "mcafee|norton|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifelock"
                        )
    )
    and 3 of (
      strings.ilike(body.current_thread.text, '*purchase*'),
      strings.ilike(body.current_thread.text, '*payment*'),
      strings.ilike(body.current_thread.text, '*transaction*'),
      strings.ilike(body.current_thread.text, '*subscription*'),
      strings.ilike(body.current_thread.text, '*antivirus*'),
      strings.ilike(body.current_thread.text, '*order*'),
      strings.ilike(body.current_thread.text, '*support*'),
      strings.ilike(body.current_thread.text, '*help line*'),
      strings.ilike(body.current_thread.text, '*receipt*'),
      strings.ilike(body.current_thread.text, '*invoice*'),
      strings.ilike(body.current_thread.text, '*call*'),
      strings.ilike(body.current_thread.text, '*cancel*'),
      strings.ilike(body.current_thread.text, '*renew*'),
      strings.ilike(body.current_thread.text, '*refund*')
    )
    // phone number regex
    and any([body.current_thread.text, subject.subject],
            regex.icontains(., '\b\+?(\d{1}.)?\(?\d{3}?\)?.\d{3}.?\d{4}\b')
    )
  )
  // Callback Phishing in the "billtoContent"
  or 
  // icontains a phone number
  (
    regex.icontains(strings.replace_confusables(body.html.inner_text),
                    '(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+\+?(\d{1}.)?\(?\d{3}?\)?.\d{3}.?\d{4}.*\n'
    )
    or regex.icontains(strings.replace_confusables(body.html.inner_text),
                       '(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+\+\d{1,3}[ilo0-9]{10}.*\n'
    )
    // +12028001238
    or regex.icontains(strings.replace_confusables(body.html.inner_text),
                       '(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+[ilo0-9]{3}\.[ilo0-9]{3}\.[ilo0-9]{4}.*\n'
    )
    // 202-800-1238
    or regex.icontains(strings.replace_confusables(body.html.inner_text),
                       '(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\n'
    )
    // (202) 800-1238
    or regex.icontains(strings.replace_confusables(body.html.inner_text),
                       '(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+\([ilo0-9]{3}\)[\s-]+[ilo0-9]{3}[\s-]+[ilo0-9]{4}.*\n'
    )
    // (202)-800-1238
    or regex.icontains(strings.replace_confusables(body.html.inner_text),
                       '(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+\([ilo0-9]{3}\)-[ilo0-9]{3}-[ilo0-9]{4}.*\n'
    )
    // 202 800 1238
    or regex.icontains(strings.replace_confusables(body.html.inner_text),
                       '(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+1\s?[ilo0-9]{3} [ilo0-9]{3} [ilo0-9]{4}.*\n'
    ) // 8123456789
    or (
      regex.icontains(strings.replace_confusables(body.html.inner_text),
                      '(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+8\d{9}.*\n'
      )
      and regex.icontains(strings.replace_confusables(body.html.inner_text),
                          '\+1'
      )
    )
  )
  // all attachments are PDFs with callback phishing indicators Brands Required
  or (
    length(attachments) < 3
    and all(attachments, .file_extension == "pdf")
    // the attachment is a pdf with 1 page, and at least 60 ocr chars
    and any(attachments,
            (
              .file_extension == "pdf"
              and any(file.explode(.), .scan.exiftool.page_count < 3)
              and any(file.explode(.), length(.scan.ocr.raw) > 60)

              // 4 of the following strings are found
              and (
                any(file.explode(.),
                    4 of (
                      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"),
                      strings.icontains(.scan.ocr.raw, "amount"),
                      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,
                                      '(\+\d|1.(\()?\d{3}(\))?\D\d{3}\D\d{4})'
                      ),
                      regex.icontains(.scan.ocr.raw,
                                      '\+?(\d{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}\d{3}[\s\.\-⋅]{0,5}\d{4}'
                      )
                    )

                    // 1 of the following strings is found, representing common Callback brands
                    and (
                      1 of (
                        strings.icontains(.scan.ocr.raw, "geek squad"),
                        strings.icontains(.scan.ocr.raw, "lifelock"),
                        strings.icontains(.scan.ocr.raw, "best buy"),
                        strings.icontains(.scan.ocr.raw, "mcafee"),
                        strings.icontains(.scan.ocr.raw, "norton"),
                        strings.icontains(.scan.ocr.raw, "ebay"),
                        strings.icontains(.scan.ocr.raw, "paypal"),
                      )
                      // add additional logic for common language for paypal, which is a valid payment method
                      and not regex.icontains(.scan.ocr.raw,
                                              "paypal[^\n]+accepted"
                      )
                      and not regex.icontains(.scan.ocr.raw,
                                              "pay(ment)?.{0,30}(via|by) paypal"
                      )
                      and not regex.icontains(.scan.ocr.raw,
                                              '\d{2,4} norton'
                      ) // an address, example: 1234 Norton Road
                      and not regex.icontains(.scan.ocr.raw,
                                              'sold on.{0,20}ebay'
                      ) // "cannot be sold on Amazon and EBay", from a legit vendor
                    )
                )
                or any(ml.logo_detect(.).brands,
                       .name in ("PayPal", "Norton", "GeekSquad", "Ebay")
                )
              )
            )
    )
  )
)

//
// This rule makes use of a beta feature and is subject to change without notice
// using the beta feature in custom rules is not suggested until it has been formally released
//
and (
  not beta.profile.by_reply_to().any_messages_benign
  or length(headers.reply_to) == 0
)

Detection logic

Scope: inbound message.

Callback phishing campaigns have been observed abusing Intuit Quickbooks services to send fraudulent invoices with callback phishing contents.

  1. inbound message
  2. all of:
    • sender.email.domain.root_domain in ('intuit.com', 'intuit.co.uk')
    • any of:
      • headers.auth_summary.spf.pass
      • headers.auth_summary.dmarc.pass
  3. any of:
    • all of:
      • length(attachments) is 0
      • strings.replace_confusables(body.current_thread.text) matches 'mcafee|norton|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifelock'
      • at least 3 of 14: body.current_thread.text matches any of 14 patterns
        • *purchase*
        • *payment*
        • *transaction*
        • *subscription*
        • *antivirus*
        • *order*
        • *support*
        • *help line*
        • *receipt*
        • *invoice*
        • *call*
        • *cancel*
        • *renew*
        • *refund*
      • any of [body.current_thread.text, subject.subject] where:
        • . matches '\\b\\+?(\\d{1}.)?\\(?\\d{3}?\\)?.\\d{3}.?\\d{4}\\b'
    • any of:
      • strings.replace_confusables(body.html.inner_text) matches '(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+\\+?(\\d{1}.)?\\(?\\d{3}?\\)?.\\d{3}.?\\d{4}.*\\n'
      • strings.replace_confusables(body.html.inner_text) matches '(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+\\+\\d{1,3}[ilo0-9]{10}.*\\n'
      • strings.replace_confusables(body.html.inner_text) matches '(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+[ilo0-9]{3}\\.[ilo0-9]{3}\\.[ilo0-9]{4}.*\\n'
      • strings.replace_confusables(body.html.inner_text) matches '(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\\n'
      • strings.replace_confusables(body.html.inner_text) matches '(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+\\([ilo0-9]{3}\\)[\\s-]+[ilo0-9]{3}[\\s-]+[ilo0-9]{4}.*\\n'
      • strings.replace_confusables(body.html.inner_text) matches '(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+\\([ilo0-9]{3}\\)-[ilo0-9]{3}-[ilo0-9]{4}.*\\n'
      • strings.replace_confusables(body.html.inner_text) matches '(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+1\\s?[ilo0-9]{3} [ilo0-9]{3} [ilo0-9]{4}.*\\n'
      • all of:
        • strings.replace_confusables(body.html.inner_text) matches '(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+8\\d{9}.*\\n'
        • strings.replace_confusables(body.html.inner_text) matches '\\+1'
    • all of:
      • length(attachments) < 3
      • all of attachments where:
        • .file_extension is 'pdf'
      • any of attachments where all hold:
        • .file_extension is 'pdf'
        • any of file.explode(.) where:
          • .scan.exiftool.page_count < 3
        • any of file.explode(.) where:
          • length(.scan.ocr.raw) > 60
        • any of:
          • any of file.explode(.) where all hold:
            • 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 contains 'amount'
              • .scan.ocr.raw contains 'crypto'
              • .scan.ocr.raw contains 'wallet address'
              • .scan.ocr.raw matches '\\$\\d{3}\\.\\d{2}\\b'
              • .scan.ocr.raw matches '(\\+\\d|1.(\\()?\\d{3}(\\))?\\D\\d{3}\\D\\d{4})'
              • .scan.ocr.raw matches '\\+?(\\d{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}\\d{3}[\\s\\.\\-⋅]{0,5}\\d{4}'
            • all of:
              • at least 1 of 7: .scan.ocr.raw contains any of 7 patterns
                • geek squad
                • lifelock
                • best buy
                • mcafee
                • norton
                • ebay
                • paypal
              • not:
                • .scan.ocr.raw matches 'paypal[^\\n]+accepted'
              • not:
                • .scan.ocr.raw matches 'pay(ment)?.{0,30}(via|by) paypal'
              • not:
                • .scan.ocr.raw matches '\\d{2,4} norton'
              • not:
                • .scan.ocr.raw matches 'sold on.{0,20}ebay'
          • any of ml.logo_detect(.).brands where:
            • .name in ('PayPal', 'Norton', 'GeekSquad', 'Ebay')
  4. any of:
    • not:
      • beta.profile.by_reply_to().any_messages_benign
    • length(headers.reply_to) is 0

Inspects: attachments[].file_extension, body.current_thread.text, body.html.inner_text, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, headers.reply_to, sender.email.domain.root_domain, subject.subject, type.inbound. Sensors: beta.profile.by_reply_to, file.explode, ml.logo_detect, regex.icontains, strings.icontains, strings.ilike, strings.replace_confusables.

Indicators matched (64)

FieldMatchValue
sender.email.domain.root_domainmemberintuit.com
sender.email.domain.root_domainmemberintuit.co.uk
regex.icontainsregexmcafee|norton|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifelock
strings.ilikesubstring*purchase*
strings.ilikesubstring*payment*
strings.ilikesubstring*transaction*
strings.ilikesubstring*subscription*
strings.ilikesubstring*antivirus*
strings.ilikesubstring*order*
strings.ilikesubstring*support*
strings.ilikesubstring*help line*
strings.ilikesubstring*receipt*
52 more
strings.ilikesubstring*invoice*
strings.ilikesubstring*call*
strings.ilikesubstring*cancel*
strings.ilikesubstring*renew*
strings.ilikesubstring*refund*
regex.icontainsregex\b\+?(\d{1}.)?\(?\d{3}?\)?.\d{3}.?\d{4}\b
regex.icontainsregex(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+\+?(\d{1}.)?\(?\d{3}?\)?.\d{3}.?\d{4}.*\n
regex.icontainsregex(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+\+\d{1,3}[ilo0-9]{10}.*\n
regex.icontainsregex(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+[ilo0-9]{3}\.[ilo0-9]{3}\.[ilo0-9]{4}.*\n
regex.icontainsregex(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\n
regex.icontainsregex(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+\([ilo0-9]{3}\)[\s-]+[ilo0-9]{3}[\s-]+[ilo0-9]{4}.*\n
regex.icontainsregex(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+\([ilo0-9]{3}\)-[ilo0-9]{3}-[ilo0-9]{4}.*\n
regex.icontainsregex(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+1\s?[ilo0-9]{3} [ilo0-9]{3} [ilo0-9]{4}.*\n
regex.icontainsregex(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+8\d{9}.*\n
regex.icontainsregex\+1
attachments[].file_extensionequalspdf
strings.icontainssubstringpurchase
strings.icontainssubstringpayment
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
strings.icontainssubstringamount
strings.icontainssubstringcrypto
strings.icontainssubstringwallet address
regex.icontainsregex\$\d{3}\.\d{2}\b
regex.icontainsregex(\+\d|1.(\()?\d{3}(\))?\D\d{3}\D\d{4})
regex.icontainsregex\+?(\d{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}\d{3}[\s\.\-⋅]{0,5}\d{4}
strings.icontainssubstringgeek squad
strings.icontainssubstringlifelock
strings.icontainssubstringbest buy
strings.icontainssubstringmcafee
strings.icontainssubstringnorton
strings.icontainssubstringebay
strings.icontainssubstringpaypal
regex.icontainsregexpaypal[^\n]+accepted
regex.icontainsregexpay(ment)?.{0,30}(via|by) paypal
regex.icontainsregex\d{2,4} norton
regex.icontainsregexsold on.{0,20}ebay
ml.logo_detect(attachments[]).brands[].namememberPayPal
ml.logo_detect(attachments[]).brands[].namememberNorton
ml.logo_detect(attachments[]).brands[].namememberGeekSquad
ml.logo_detect(attachments[]).brands[].namememberEbay