Detection rules › Sublime MQL

Sublime MQL rules: fictitious

Attachment: Fictitious invoice using LinkedIn's address

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

Detects PDF attachments created with wkhtmltopdf or Qt that contain LinkedIn's headquarters address (1000 W Maude Ave) in financial communications context, but do not mention LinkedIn itself.

Threat classification

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

CategoryValues
Attack typesBEC/Fraud
Tactics and techniquesPDF, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • attachments
  • body
  • body.current_thread
  • type

Rule body

type.inbound
and 0 < length(filter(attachments, .file_type == "pdf")) < 3
and any(filter(attachments,
               .file_type == "pdf"
               // creator and producer of PDF seen in malicious content
               and (
                 strings.starts_with(beta.parse_exif(.).creator, "wkhtmltopdf")
                 or strings.starts_with(beta.parse_exif(.).producer, "Qt ")
               )
        ),
        any(filter(file.explode(.), .scan.ocr.raw is not null),
            // contains LinkedIn HQ address but not from LinkedIn
            (
              strings.icontains(.scan.ocr.raw, "1000 W Maude Ave")
              and not strings.icontains(.scan.ocr.raw, "linkedin")
            )
        )
)
and any(ml.nlu_classifier(body.current_thread.text).topics,
        .name == "Financial Communications" and .confidence != "low"
)

Detection logic

Scope: inbound message.

Detects PDF attachments created with wkhtmltopdf or Qt that contain LinkedIn's headquarters address (1000 W Maude Ave) in financial communications context, but do not mention LinkedIn itself.

  1. inbound message
  2. all of:
    • length(filter(attachments, .file_type == 'pdf')) > 0
    • length(filter(attachments, .file_type == 'pdf')) < 3
  3. any of filter(attachments) where:
    • any of filter(...) where all hold:
      • .scan.ocr.raw contains '1000 W Maude Ave'
      • not:
        • .scan.ocr.raw contains 'linkedin'
  4. any of ml.nlu_classifier(body.current_thread.text).topics where all hold:
    • .name is 'Financial Communications'
    • .confidence is not 'low'

Inspects: attachments[].file_type, body.current_thread.text, type.inbound. Sensors: beta.parse_exif, file.explode, ml.nlu_classifier, strings.icontains, strings.starts_with.

Indicators matched (5)

FieldMatchValue
attachments[].file_typeequalspdf
strings.starts_withprefixwkhtmltopdf
strings.starts_withprefixQt
strings.icontainssubstring1000 W Maude Ave
ml.nlu_classifier(body.current_thread.text).topics[].nameequalsFinancial Communications

Stages and Predicates

Stage 1: mql_rule

and
  any(filter(attachments))
    any(filter(...))
      and
        not
          filter(...).scan.ocr.raw contains "linkedin"
        filter(...).scan.ocr.raw contains "1000 W Maude Ave"
  any(ml.nlu_classifier(body.current_thread.text).topics)
    and
      ml.nlu_classifier(body.current_thread.text).topics.confidence ne "low"
      ml.nlu_classifier(body.current_thread.text).topics.name eq "Financial Communications"
  filter(attachments, .file_type == 'pdf') length_compare "0"
  filter(attachments, .file_type == 'pdf') length_compare "3"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"