Detection rules › Sublime MQL
Attachment: QR code with suspicious URL patterns in EML file
Detects EML attachments containing QR codes that link to URLs with suspicious patterns, including specific alphanumeric combinations in subdomains and paths, or special characters followed by encoded terminators. These patterns are commonly used to evade detection in credential theft attacks.
Threat classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Credential Phishing |
| Tactics and techniques | QR code, Evasion, Social engineering |
Event coverage
| Message attribute |
|---|
| recipients |
| recipients.to (collection) |
| type |
Rule body MQL
type.inbound
and length(recipients.to) == 1
and recipients.to[0].email.domain.valid
and any(attachments,
// Email Attachments
any(file.parse_eml(.).attachments,
(
// looks for office docs in the attached eml
.file_extension in $file_extensions_macros
and any(file.explode(.),
.scan.qr.type == "url"
// QR code URL contains recipient's email (targeting indicator)
and any(recipients.to,
.email.domain.valid
and (
// Plaintext email address in URL
strings.icontains(..scan.qr.url.url,
.email.email
)
// OR base64 encoded email address
or any(strings.scan_base64(..scan.qr.url.url,
format="url",
ignore_padding=true
),
strings.icontains(., ..email.email)
)
)
)
// a single path
and strings.count(.scan.qr.url.path, '/') == 2
and (
(
(
strings.contains(.scan.qr.url.path, '/$')
or strings.contains(.scan.qr.url.path, '/*')
or strings.contains(.scan.qr.url.path, '/#')
)
// subdomain should contain num{3}alpha or alphanum{3}
and regex.icontains(.scan.qr.url.domain.subdomain,
'^(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)(?:$|\.)'
)
// url path should contain num{3}alpha or alphanum{3}
and regex.icontains(.scan.qr.url.path,
'\/(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)\/'
)
)
or (
// special char in the path
(
strings.contains(.scan.qr.url.path, '!')
or strings.contains(.scan.qr.url.path, '@')
)
and (
strings.contains(.scan.qr.url.path, '/$')
or strings.contains(.scan.qr.url.path, '/*')
or strings.contains(.scan.qr.url.path, '/#')
// hex dollar sign
or strings.icontains(.scan.qr.url.path, '%24')
// hex star
or strings.icontains(.scan.qr.url.path, '%2A')
// hex pound
or strings.icontains(.scan.qr.url.path, '%23')
)
// ensure expected ordering
and regex.icontains(.scan.qr.url.url,
'[!@].*(?:[$*]|%2[A43])'
)
)
)
)
)
or (
// looks for pdfs and images in the attached eml
//
// 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
//
any(beta.scan_qr(.).items,
.type is not null
// a single path
and strings.count(.url.path, '/') == 2
and (
(
(
strings.contains(.url.path, '/$')
or strings.contains(.url.path, '/*')
or strings.contains(.url.path, '/#')
)
// subdomain should contain num{3}alpha or alphanum{3}
and regex.icontains(.url.domain.subdomain,
'^(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)(?:$|\.)'
)
// url path should contain num{3}alpha or alphanum{3}
and regex.icontains(.url.path,
'\/(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)\/'
)
)
or (
// special char in the path
(
strings.contains(.url.path, '!')
or strings.contains(.url.path, '@')
)
and (
strings.contains(.url.path, '/$')
or strings.contains(.url.path, '/*')
or strings.contains(.url.path, '/#')
// hex dollar sign
or strings.icontains(.url.path, '%24')
// hex star
or strings.icontains(.url.path, '%2A')
// hex pound
or strings.icontains(.url.path, '%23')
)
// ensure expected ordering
and regex.icontains(.url.url, '[!@].*(?:[$*]|%2[A43])')
)
)
)
)
)
)
Detection logic
Scope: inbound message.
Detects EML attachments containing QR codes that link to URLs with suspicious patterns, including specific alphanumeric combinations in subdomains and paths, or special characters followed by encoded terminators. These patterns are commonly used to evade detection in credential theft attacks.
- inbound message
- length(recipients.to) is 1
- recipients.to[0].email.domain.valid
any of
attachmentswhere:any of
file.parse_eml(.).attachmentswhere any holds:all of:
- .file_extension in $file_extensions_macros
any of
file.explode(.)where all hold:- .scan.qr.type is 'url'
any of
recipients.towhere all hold:- .email.domain.valid
any of:
- strings.icontains(.scan.qr.url.url)
any of
strings.scan_base64(.scan.qr.url.url)where:- strings.icontains(.)
- strings.count(.scan.qr.url.path, '/') is 2
any of:
all of:
any of:
- .scan.qr.url.path contains '/$'
- .scan.qr.url.path contains '/*'
- .scan.qr.url.path contains '/#'
- .scan.qr.url.domain.subdomain matches '^(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)(?:$|\\.)'
- .scan.qr.url.path matches '\\/(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)\\/'
all of:
any of:
- .scan.qr.url.path contains '!'
- .scan.qr.url.path contains '@'
.scan.qr.url.path contains any of 6 patterns
/$/*/#%24%2A%23
- .scan.qr.url.url matches '[!@].*(?:[$*]|%2[A43])'
any of
beta.scan_qr(.).itemswhere all hold:- .type is set
- strings.count(.url.path, '/') is 2
any of:
all of:
any of:
- .url.path contains '/$'
- .url.path contains '/*'
- .url.path contains '/#'
- .url.domain.subdomain matches '^(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)(?:$|\\.)'
- .url.path matches '\\/(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)\\/'
all of:
any of:
- .url.path contains '!'
- .url.path contains '@'
.url.path contains any of 6 patterns
/$/*/#%24%2A%23
- .url.url matches '[!@].*(?:[$*]|%2[A43])'
Inspects: recipients.to, recipients.to[0].email.domain.valid, recipients.to[].email.domain.valid, recipients.to[].email.email, type.inbound. Sensors: beta.scan_qr, file.explode, file.parse_eml, regex.icontains, strings.contains, strings.count, strings.icontains, strings.scan_base64. Reference lists: $file_extensions_macros.
Indicators matched (12)
| Field | Match | Value |
|---|---|---|
file.explode(file.parse_eml(attachments[]).attachments[])[].scan.qr.type | equals | url |
strings.contains | substring | /$ |
strings.contains | substring | /* |
strings.contains | substring | /# |
regex.icontains | regex | ^(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)(?:$|\.) |
regex.icontains | regex | \/(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)\/ |
strings.contains | substring | ! |
strings.contains | substring | @ |
strings.icontains | substring | %24 |
strings.icontains | substring | %2A |
strings.icontains | substring | %23 |
regex.icontains | regex | [!@].*(?:[$*]|%2[A43]) |