Detection rules › Sublime MQL
Attachment: QR code with credential phishing indicators
Detects messages with between 1-3 attachments containing a QR code with suspicious credential theft indicators, such as: LinkAnalysis credential phishing conclusion, decoded QR code url traverses suspicious infrastructure, the final destination is in URLhaus, decoded URL downloads a zip or executable, leverages URL shorteners, known QR abused openredirects, and more.
Threat classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Credential Phishing |
| Tactics and techniques | QR code, Social engineering |
Event coverage
Rule body MQL
type.inbound
and (
1 <= length(attachments) < 3
or (
// if there are more than three attachments
3 <= length(attachments) < 20
// there are only pngs and pdf/docx
and length(distinct(map(attachments, .file_extension))) == 2
and all(distinct(map(attachments, .file_extension)),
. in ('png', 'pdf', 'docx')
)
and (
// multiple attachments mention common brands or other common common filenames
(
length(filter(attachments,
strings.icontains(.file_name, 'adobe')
or strings.icontains(.file_name, 'office')
or strings.icontains(.file_name, 'appstore')
or strings.icontains(.file_name, 'google')
or strings.icontains(.file_name, 'padlock')
or regex.icontains(.file_name, '\bdoc\b')
)
) > 3
)
// the attachment name contains the SLD of a recipient
or any(filter(attachments, .file_extension in ('pdf', 'docx')),
any(filter(recipients.to, .email.domain.valid),
strings.icontains(..file_name, .email.domain.sld)
)
)
)
)
)
// Inspects image attachments for QR codes
and any(attachments,
(
.file_type in $file_types_images
or .file_type == "pdf"
or .file_extension in $file_extensions_macros
)
and (
any(file.explode(.),
.scan.qr.type == "url"
and not .scan.qr.url.domain.domain == "geico.app.link"
and (
// pass the QR URL to LinkAnalysis
any([ml.link_analysis(.scan.qr.url)],
.credphish.disposition == "phishing"
// any routing traverses via $suspicious_tld list
or any(.redirect_history, .domain.tld in $suspicious_tlds)
// effective destination in $suspicious_tld list
or .effective_url.domain.tld in $suspicious_tlds
// or the effective destination domain is in $abuse_ch_urlhaus_domains_trusted_reporters
or .effective_url.domain.root_domain in $abuse_ch_urlhaus_domains_trusted_reporters
// or any files downloaded are zips or executables
or any(.files_downloaded,
.file_extension in $file_extensions_common_archives
or .file_extension in $file_extensions_executables
)
)
or (
// or the QR code's root domain is a url_shortener
.scan.qr.url.domain.root_domain in $url_shorteners
or .scan.qr.url.domain.root_domain in $social_landing_hosts
and (
not (
any(ml.nlu_classifier(body.current_thread.text).intents,
.name == "benign"
)
or any(ml.nlu_classifier(body.current_thread.text).entities,
.name == "disclaimer"
)
)
or not any(attachments,
any(file.explode(.),
any(ml.nlu_classifier(.scan.ocr.raw).intents,
.name == "benign"
)
)
)
// the QR code contains the email address of a recipient
or (
any(filter(recipients.to, .email.domain.valid),
strings.icontains(..scan.qr.url.url, .email.email)
)
)
)
// exclude google maps
and not strings.starts_with(.scan.qr.url.url,
'https://goo.gl/maps'
)
and not strings.starts_with(.scan.qr.url.url,
'https://maps.app.goo.gl'
)
)
// the QR code url is a bing open redirect
or (
.scan.qr.url.domain.root_domain == 'bing.com'
and .scan.qr.url.path =~ '/ck/a'
)
// QR code contains non ascii chars
or regex.contains(.scan.qr.url.url, '[^\x00-\x7F]')
or (
// usap-dc open redirect
.scan.qr.url.domain.root_domain == "usap-dc.org"
and .scan.qr.url.path =~ "/tracker"
and strings.starts_with(.scan.qr.url.query_params,
"type=dataset&url=http"
)
// the QR code contains the email address of a recipient
// allowing for base64 encoded variants
or (
any(filter(recipients.to, .email.domain.valid),
strings.icontains(..scan.qr.url.url, .email.email)
or any(beta.scan_base64(..scan.qr.url.url,
ignore_padding=true
),
strings.icontains(., ..email.email)
)
or any(beta.scan_base64(..scan.qr.url.fragment,
ignore_padding=true
),
strings.icontains(., ..email.email)
)
)
)
)
)
)
)
)
and (
(
profile.by_sender_email().prevalence in ("new", "outlier")
and not profile.by_sender_email().solicited
)
or (
profile.by_sender_email().any_messages_malicious_or_spam
and not profile.by_sender_email().any_messages_benign
)
or (
sender.email.domain.domain in $org_domains
and not coalesce(headers.auth_summary.dmarc.pass, false)
)
)
// negate highly trusted sender domains unless they fail DMARC authentication
and (
(
sender.email.domain.root_domain in $high_trust_sender_root_domains
and not headers.auth_summary.dmarc.pass
)
or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)
Detection logic
Scope: inbound message.
Detects messages with between 1-3 attachments containing a QR code with suspicious credential theft indicators, such as: LinkAnalysis credential phishing conclusion, decoded QR code url traverses suspicious infrastructure, the final destination is in URLhaus, decoded URL downloads a zip or executable, leverages URL shorteners, known QR abused openredirects, and more.
- inbound message
any of:
all of:
- length(attachments) ≥ 1
- length(attachments) < 3
all of:
all of:
- length(attachments) ≥ 3
- length(attachments) < 20
- length(distinct(map(attachments, .file_extension))) is 2
all of
distinct(...)where:- . in ('png', 'pdf', 'docx')
any of:
- length(filter(attachments, strings.icontains(.file_name, 'adobe') or strings.icontains(.file_name, 'office') or strings.icontains(.file_name, 'appstore') or strings.icontains(.file_name, 'google') or strings.icontains(.file_name, 'padlock') or regex.icontains(.file_name, '\\bdoc\\b'))) > 3
any of
filter(attachments)where:any of
filter(recipients.to)where:- strings.icontains(.file_name)
any of
attachmentswhere all hold:any of:
- .file_type in $file_types_images
- .file_type is 'pdf'
- .file_extension in $file_extensions_macros
any of
file.explode(.)where all hold:- .scan.qr.type is 'url'
not:
- .scan.qr.url.domain.domain is 'geico.app.link'
any of:
any of
[ml.link_analysis(.scan.qr.url)]where any holds:- .credphish.disposition is 'phishing'
any of
.redirect_historywhere:- .domain.tld in $suspicious_tlds
- .effective_url.domain.tld in $suspicious_tlds
- .effective_url.domain.root_domain in $abuse_ch_urlhaus_domains_trusted_reporters
any of
.files_downloadedwhere any holds:- .file_extension in $file_extensions_common_archives
- .file_extension in $file_extensions_executables
any of:
- .scan.qr.url.domain.root_domain in $url_shorteners
all of:
- .scan.qr.url.domain.root_domain in $social_landing_hosts
any of:
none of:
any of
ml.nlu_classifier(body.current_thread.text).intentswhere:- .name is 'benign'
any of
ml.nlu_classifier(body.current_thread.text).entitieswhere:- .name is 'disclaimer'
not:
any of
attachmentswhere:any of
file.explode(.)where:any of
ml.nlu_classifier(.scan.ocr.raw).intentswhere:- .name is 'benign'
any of
filter(recipients.to)where:- strings.icontains(.scan.qr.url.url)
not:
- .scan.qr.url.url starts with 'https://goo.gl/maps'
not:
- .scan.qr.url.url starts with 'https://maps.app.goo.gl'
all of:
- .scan.qr.url.domain.root_domain is 'bing.com'
- .scan.qr.url.path is '/ck/a'
- .scan.qr.url.url matches '[^\\x00-\\x7F]'
any of:
all of:
- .scan.qr.url.domain.root_domain is 'usap-dc.org'
- .scan.qr.url.path is '/tracker'
- .scan.qr.url.query_params starts with 'type=dataset&url=http'
any of
filter(recipients.to)where any holds:- strings.icontains(.scan.qr.url.url)
any of
beta.scan_base64(.scan.qr.url.url)where:- strings.icontains(.)
any of
beta.scan_base64(.scan.qr.url.fragment)where:- strings.icontains(.)
any of:
all of:
- profile.by_sender_email().prevalence in ('new', 'outlier')
not:
- profile.by_sender_email().solicited
all of:
- profile.by_sender_email().any_messages_malicious_or_spam
not:
- profile.by_sender_email().any_messages_benign
all of:
- sender.email.domain.domain in $org_domains
not:
- coalesce(headers.auth_summary.dmarc.pass)
any of:
all of:
- sender.email.domain.root_domain in $high_trust_sender_root_domains
not:
- headers.auth_summary.dmarc.pass
- sender.email.domain.root_domain not in $high_trust_sender_root_domains
Inspects: attachments[].file_extension, attachments[].file_name, attachments[].file_type, body.current_thread.text, headers.auth_summary.dmarc.pass, recipients.to, recipients.to[].email.domain.valid, sender.email.domain.domain, sender.email.domain.root_domain, type.inbound. Sensors: beta.scan_base64, file.explode, ml.link_analysis, ml.nlu_classifier, profile.by_sender_email, regex.contains, regex.icontains, strings.icontains, strings.starts_with. Reference lists: $abuse_ch_urlhaus_domains_trusted_reporters, $file_extensions_common_archives, $file_extensions_executables, $file_extensions_macros, $file_types_images, $high_trust_sender_root_domains, $org_domains, $social_landing_hosts, $suspicious_tlds, $url_shorteners.
Indicators matched (26)
| Field | Match | Value |
|---|---|---|
distinct(...)[] | member | png |
distinct(...)[] | member | pdf |
distinct(...)[] | member | docx |
strings.icontains | substring | adobe |
strings.icontains | substring | office |
strings.icontains | substring | appstore |
strings.icontains | substring | google |
strings.icontains | substring | padlock |
regex.icontains | regex | \bdoc\b |
attachments[].file_extension | member | pdf |
attachments[].file_extension | member | docx |
attachments[].file_type | equals | pdf |
14 more
file.explode(attachments[])[].scan.qr.type | equals | url |
file.explode(attachments[])[].scan.qr.url.domain.domain | equals | geico.app.link |
[ml.link_analysis(file.explode(attachments[])[].scan.qr.url)][].credphish.disposition | equals | phishing |
ml.nlu_classifier(body.current_thread.text).intents[].name | equals | benign |
ml.nlu_classifier(body.current_thread.text).entities[].name | equals | disclaimer |
ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].name | equals | benign |
strings.starts_with | prefix | https://goo.gl/maps |
strings.starts_with | prefix | https://maps.app.goo.gl |
file.explode(attachments[])[].scan.qr.url.domain.root_domain | equals | bing.com |
file.explode(attachments[])[].scan.qr.url.path | equals | /ck/a |
regex.contains | regex | [^\x00-\x7F] |
file.explode(attachments[])[].scan.qr.url.domain.root_domain | equals | usap-dc.org |
file.explode(attachments[])[].scan.qr.url.path | equals | /tracker |
strings.starts_with | prefix | type=dataset&url=http |