Detection rules › Sublime MQL
Sublime MQL rules: fictitious
| Rule | Severity |
|---|---|
| Attachment: Fictitious invoice using LinkedIn's address | medium |
Attachment: Fictitious invoice using LinkedIn's address
#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).
| Category | Values |
|---|---|
| Attack types | BEC/Fraud |
| Tactics and techniques | PDF, Social engineering |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message Attributes
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.
- inbound message
all of:
- (0) < (length(filter(attachments, .file_type == "pdf")))
- (length(filter(attachments, .file_type == "pdf"))) < (3)
- 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") ) ) )
- any(ml.nlu_classifier(body.current_thread.text).topics, .name == "Financial Communications" and .confidence != "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)
| Field | Match | Value |
|---|---|---|
attachments[].file_type | equals | pdf |
strings.starts_with | prefix | wkhtmltopdf |
strings.starts_with | prefix | Qt |
strings.icontains | substring | 1000 W Maude Ave |
ml.nlu_classifier(body.current_thread.text).topics[].name | equals | Financial Communications |
Stages and Predicates
Stage 1: mql_rule
and
length func_call "(0) < (length(filter(attachments, .file_type == \"pdf\")))"
length func_call "(length(filter(attachments, .file_type == \"pdf\"))) < (3)"
type.inbound eq "true"
macro "any(filter(attachments,\n .file_type == \"pdf\"\n // creator and producer of PDF seen in malicious content\n and (\n strings.starts_with(beta.parse_exif(.).creator, \"wkhtmltopdf\")\n or strings.starts_with(beta.parse_exif(.).producer, \"Qt \")\n )\n ),\n any(filter(file.explode(.), .scan.ocr.raw is not null),\n // contains LinkedIn HQ address but not from LinkedIn\n (\n strings.icontains(.scan.ocr.raw, \"1000 W Maude Ave\")\n and not strings.icontains(.scan.ocr.raw, \"linkedin\")\n )\n )\n)"
macro "any(ml.nlu_classifier(body.current_thread.text).topics,\n .name == \"Financial Communications\" and .confidence != \"low\"\n)"Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |