Detection rules › Sublime MQL
Attachment: QR code with userinfo portion
Detects inbound messages that contain image or document attachments with QR codes containing embedded usernames, passwords, or excessively padded URLs. This technique is used to bypass traditional text-based detection methods.
Threat classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Credential Phishing, Malware/Ransomware |
| Tactics and techniques | Evasion, Image as content, PDF, QR code |
Event coverage
Rule body MQL
type.inbound
and any(attachments,
(
.file_type in $file_types_images
or .file_extension in $file_extensions_macros
or .file_type == "pdf"
)
and any(file.explode(.),
(
.scan.qr.url.username is not null
or .scan.qr.url.password is not null
// keep in sync with https://github.com/sublime-security/sublime-rules/blob/main/detection-rules/link_userinfo_excessive_padding.yml
or regex.icontains(coalesce(.scan.qr.url.rewrite.original,
.scan.qr.url.url
),
'https?(?:(?:%3a|\:)?(?:\/|%2f){2})[^\/]+(?:\s+|%(?:25)?[a-f0-9]{2}|0x[a-f0-9]+){30,}(?:@|%(?:25)?40)[^\/]+(?:\/|%(?:25)?2f)'
)
)
and .scan.qr.url.domain.root_domain != sender.email.domain.root_domain
and not any(recipients.to,
.email.domain.root_domain == ..scan.qr.url.domain.root_domain
)
and not any(recipients.cc,
.email.domain.root_domain == ..scan.qr.url.domain.root_domain
)
// an error to strings.parse_email returns null for the full object
// this cehck ensures that the url is not a valid email address
and strings.parse_email(.scan.qr.url.url).email is null
)
)
Detection logic
Scope: inbound message.
Detects inbound messages that contain image or document attachments with QR codes containing embedded usernames, passwords, or excessively padded URLs. This technique is used to bypass traditional text-based detection methods.
- inbound message
any of
attachmentswhere all hold:any of:
- .file_type in $file_types_images
- .file_extension in $file_extensions_macros
- .file_type is 'pdf'
any of
file.explode(.)where all hold:any of:
- .scan.qr.url.username is set
- .scan.qr.url.password is set
- coalesce(.scan.qr.url.rewrite.original, .scan.qr.url.url) matches 'https?(?:(?:%3a|\\:)?(?:\\/|%2f){2})[^\\/]+(?:\\s+|%(?:25)?[a-f0-9]{2}|0x[a-f0-9]+){30,}(?:@|%(?:25)?40)[^\\/]+(?:\\/|%(?:25)?2f)'
- .scan.qr.url.domain.root_domain is not sender.email.domain.root_domain
not:
any of
recipients.towhere:- .email.domain.root_domain is .scan.qr.url.domain.root_domain
not:
any of
recipients.ccwhere:- .email.domain.root_domain is .scan.qr.url.domain.root_domain
- strings.parse_email(.scan.qr.url.url).email is missing
Inspects: attachments[].file_extension, attachments[].file_type, recipients.cc, recipients.cc[].email.domain.root_domain, recipients.to, recipients.to[].email.domain.root_domain, sender.email.domain.root_domain, type.inbound. Sensors: file.explode, regex.icontains, strings.parse_email. Reference lists: $file_extensions_macros, $file_types_images.
Indicators matched (2)
| Field | Match | Value |
|---|---|---|
attachments[].file_type | equals | pdf |
regex.icontains | regex | https?(?:(?:%3a|\:)?(?:\/|%2f){2})[^\/]+(?:\s+|%(?:25)?[a-f0-9]{2}|0x[a-f0-9]+){30,}(?:@|%(?:25)?40)[^\/]+(?:\/|%(?:25)?2f) |