Detection rules › Sublime MQL

Request for Quote or Purchase (RFQ|RFP) with HTML smuggling attachment

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

RFQ/RFP scams involve fraudulent emails posing as legitimate requests for quotations or purchases, often sent by scammers impersonating reputable organizations. These scams aim to deceive recipients into providing sensitive information or conducting unauthorized transactions, often leading to financial loss, or data leakage.

Threat classification

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

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesEvasion

Event coverage

Rule body MQL

type.inbound

// RFP/RFQ language
and 1 of (
  regex.icontains(body.current_thread.text, '(discuss.{0,15}purchas(e|ing))'),
  regex.icontains(body.current_thread.text,
                  '(sign(ed?)|view).{0,10}(purchase order)|Request for a Quot(e|ation)'
  ),
  regex.icontains(body.current_thread.text, '(please|kindly).{0,30}quote'),
  regex.icontains(subject.subject,
                  '(request for (purchase|quot(e|ation))|\bRFQ\b|\bRFP\b)'
  ),
  any(attachments,
      regex.icontains(.file_name, "(purchase.?order|Quot(e|ation))")
  ),
  any(ml.nlu_classifier(body.current_thread.text).entities, .name == "request")
  and any(ml.nlu_classifier(body.current_thread.text).entities,
          .name == "urgency"
  ),
  any(ml.nlu_classifier(body.current_thread.text).tags,
      .name == "purchase_order" and .confidence == "high"
  )
)

// HTML smuggling
and any(attachments,
        (
          .file_extension in~ ("html", "htm", "shtml", "dhtml")
          or .file_extension in~ $file_extensions_common_archives
          or .file_type == "html"
        )
        and any(file.explode(.),
                (
                  length(filter(.scan.javascript.identifiers,
                                strings.like(., "document", "write", "atob")
                         )
                  ) == 3
                  // usage: document['write'](atob)
                  or any(.scan.strings.strings,
                         strings.ilike(., "*document*write*atob*")
                  )
                  // usage: some_var = atob();
                  or any(.scan.strings.strings, strings.ilike(., "*=*atob*;"))
                  // usage: obfuscating "atob"
                  or any(.scan.javascript.identifiers,
                         strings.ilike(., '*ato\u0062*')
                  )
                  // usage: document.head.insertAdjacentHTML("beforeend", atob(...
                  or any(.scan.strings.strings,
                         strings.ilike(.,
                                       "*document*write*atob*",
                                       "*document*insertAdjacentHTML*atob*"
                         )
                  )
                )
        )
)

Detection logic

Scope: inbound message.

RFQ/RFP scams involve fraudulent emails posing as legitimate requests for quotations or purchases, often sent by scammers impersonating reputable organizations. These scams aim to deceive recipients into providing sensitive information or conducting unauthorized transactions, often leading to financial loss, or data leakage.

  1. inbound message
  2. at least 1 of:
    • body.current_thread.text matches '(discuss.{0,15}purchas(e|ing))'
    • body.current_thread.text matches '(sign(ed?)|view).{0,10}(purchase order)|Request for a Quot(e|ation)'
    • body.current_thread.text matches '(please|kindly).{0,30}quote'
    • subject.subject matches '(request for (purchase|quot(e|ation))|\\bRFQ\\b|\\bRFP\\b)'
    • any of attachments where:
      • .file_name matches '(purchase.?order|Quot(e|ation))'
    • all of:
      • any of ml.nlu_classifier(body.current_thread.text).entities where:
        • .name is 'request'
      • any of ml.nlu_classifier(body.current_thread.text).entities where:
        • .name is 'urgency'
    • any of ml.nlu_classifier(body.current_thread.text).tags where all hold:
      • .name is 'purchase_order'
      • .confidence is 'high'
  3. any of attachments where all hold:
    • any of:
      • .file_extension in ('html', 'htm', 'shtml', 'dhtml')
      • .file_extension in $file_extensions_common_archives
      • .file_type is 'html'
    • any of file.explode(.) where any holds:
      • length(filter(.scan.javascript.identifiers, strings.like(., 'document', 'write', 'atob'))) is 3
      • any of .scan.strings.strings where:
        • . matches '*document*write*atob*'
      • any of .scan.strings.strings where:
        • . matches '*=*atob*;'
      • any of .scan.javascript.identifiers where:
        • . matches '*ato\\u0062*'
      • any of .scan.strings.strings where:
        • . matches any of 2 patterns
          • *document*write*atob*
          • *document*insertAdjacentHTML*atob*

Inspects: attachments[].file_extension, attachments[].file_name, attachments[].file_type, body.current_thread.text, subject.subject, type.inbound. Sensors: file.explode, ml.nlu_classifier, regex.icontains, strings.ilike, strings.like. Reference lists: $file_extensions_common_archives.

Indicators matched (21)

FieldMatchValue
regex.icontainsregex(discuss.{0,15}purchas(e|ing))
regex.icontainsregex(sign(ed?)|view).{0,10}(purchase order)|Request for a Quot(e|ation)
regex.icontainsregex(please|kindly).{0,30}quote
regex.icontainsregex(request for (purchase|quot(e|ation))|\bRFQ\b|\bRFP\b)
regex.icontainsregex(purchase.?order|Quot(e|ation))
ml.nlu_classifier(body.current_thread.text).entities[].nameequalsrequest
ml.nlu_classifier(body.current_thread.text).entities[].nameequalsurgency
ml.nlu_classifier(body.current_thread.text).tags[].nameequalspurchase_order
ml.nlu_classifier(body.current_thread.text).tags[].confidenceequalshigh
attachments[].file_extensionmemberhtml
attachments[].file_extensionmemberhtm
attachments[].file_extensionmembershtml
9 more
attachments[].file_extensionmemberdhtml
attachments[].file_typeequalshtml
strings.likesubstringdocument
strings.likesubstringwrite
strings.likesubstringatob
strings.ilikesubstring*document*write*atob*
strings.ilikesubstring*=*atob*;
strings.ilikesubstring*ato\u0062*
strings.ilikesubstring*document*insertAdjacentHTML*atob*