Detection rules › Sublime MQL
Credential phishing: 'Secure message' and engaging language
Body contains language resembling credential theft, and a "secure message" from an untrusted sender.
Threat classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Credential Phishing |
| Tactics and techniques | Social engineering |
Event coverage
Rule body MQL
type.inbound
and (
(
any(ml.nlu_classifier(body.current_thread.text).intents,
.name == "cred_theft" and .confidence == "high"
)
// add fallback when NLU doesn't pick up cred theft to check for suspicious links
or any(body.current_thread.links,
regex.icontains(.display_text, '(?:read|view|open) the message')
and (
.href_url.domain.root_domain not in $tranco_1m
or .href_url.domain.domain in $free_file_hosts
or .href_url.domain.root_domain in $free_file_hosts
or .href_url.domain.root_domain in $free_subdomain_hosts
or .href_url.domain.domain in $url_shorteners
or .href_url.domain.domain in $social_landing_hosts
)
)
)
or any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents,
.name == "cred_theft" and .confidence in ("medium", "high")
)
)
// ----- other suspicious signals here -----
and (
(
regex.icontains(body.current_thread.text,
"secured? (message|directory|document)"
)
or strings.icontains(body.current_thread.text, "document portal")
or strings.icontains(body.current_thread.text, "encrypted message")
or strings.icontains(body.current_thread.text, "protected message")
)
or any(body.previous_threads,
regex.icontains(.text, "secured? (message|directory|document)")
or strings.icontains(.text, "document portal")
or strings.icontains(.text, "encrypted message")
or strings.icontains(.text, "protected message")
)
or any(body.current_thread.links,
regex.icontains(ml.link_analysis(.).final_dom.display_text,
'secured? (?:message|directory|document) access'
)
or regex.icontains(ml.link_analysis(.).final_dom.inner_text,
'secured? (?:message|directory|document) access'
)
)
or (
length(filter(ml.nlu_classifier(body.current_thread.text).entities,
.name == "urgency"
)
) >= 2
and any(ml.nlu_classifier(body.current_thread.text).topics,
.name == "Secure Message" and .confidence != "low"
)
)
)
// todo: automated display name / human local part
// todo: suspicious link (unfurl click trackers)
// ----------
// has at least 1 link
and length(body.links) > 0
// negate legitimate message senders
and (
sender.email.domain.root_domain not in ("protectedtrust.com")
and any(body.links,
.href_url.domain.root_domain != sender.email.domain.root_domain
)
// negate known secure mailers
and not all(body.links,
.href_url.domain.root_domain in (
"mimecast.com",
"cisco.com",
"csiesafe.com"
)
)
and any(headers.hops,
.index == 0
and not any(.fields,
strings.contains(.value,
'multipart/mixed; boundary="PROOFPOINT_BOUNDARY_1"'
)
)
)
and not (
length(filter(attachments,
strings.ilike(.file_name,
"logo.*",
"lock.gif",
"SecureMessageAtt.html"
)
)
) == 3
and any(attachments,
.file_type == "html"
and any(file.explode(.),
.scan.html.title == "Proofpoint Encryption"
and any(.scan.url.urls,
strings.iends_with(.path,
'formpostdir/safeformpost.aspx'
)
)
)
and strings.count(file.parse_html(.).raw, 'name="msg') > 3
)
)
and not (
any(headers.hops,
any(.fields,
.name in (
'X-ZixNet',
'X-VPM-MIV',
'X-VPM-ActionCode',
'X-VPM-SmtpTo'
)
)
)
and any(headers.domains,
.root_domain in (
"zixport.com",
"zixcorp.com",
"zixmail.net",
"zixworks.com"
)
)
)
and not (
any(headers.hops, any(.fields, .name == 'X-SendInc-Message-Id'))
and any(headers.domains, .root_domain in ("sendinc.net"))
)
// negating Mimecast sends with MS banner and/or sender's email pulled out as a link
and not length(filter(body.links,
(
.display_text is null
and .display_url.url == sender.email.domain.root_domain
)
or .href_url.domain.root_domain in (
"aka.ms",
"mimecast.com",
"cisco.com"
)
)
) == length(body.links)
)
and (
(
profile.by_sender().prevalence in ("new", "outlier")
and not profile.by_sender().solicited
)
or (
profile.by_sender().any_messages_malicious_or_spam
and not profile.by_sender().any_messages_benign
)
// or the sender is all undisclosed or there are no recipients
or (
length(recipients.to) == 0
or all(recipients.to,
strings.ilike(.display_name, "undisclosed?recipients")
)
)
// or the sender exhibits a "self sender" pattern
or (
length(recipients.to) == 1
and any(recipients.to, .email.email == sender.email.email)
)
)
and not profile.by_sender().any_messages_benign
// 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.
Body contains language resembling credential theft, and a "secure message" from an untrusted sender.
- inbound message
any of:
any of:
any of
ml.nlu_classifier(body.current_thread.text).intentswhere all hold:- .name is 'cred_theft'
- .confidence is 'high'
any of
body.current_thread.linkswhere all hold:- .display_text matches '(?:read|view|open) the message'
any of:
- .href_url.domain.root_domain not in $tranco_1m
- .href_url.domain.domain in $free_file_hosts
- .href_url.domain.root_domain in $free_file_hosts
- .href_url.domain.root_domain in $free_subdomain_hosts
- .href_url.domain.domain in $url_shorteners
- .href_url.domain.domain in $social_landing_hosts
any of
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intentswhere all hold:- .name is 'cred_theft'
- .confidence in ('medium', 'high')
any of:
any of:
- body.current_thread.text matches 'secured? (message|directory|document)'
- body.current_thread.text contains 'document portal'
- body.current_thread.text contains 'encrypted message'
- body.current_thread.text contains 'protected message'
any of
body.previous_threadswhere any holds:- .text matches 'secured? (message|directory|document)'
- .text contains 'document portal'
- .text contains 'encrypted message'
- .text contains 'protected message'
any of
body.current_thread.linkswhere any holds:- ml.link_analysis(.).final_dom.display_text matches 'secured? (?:message|directory|document) access'
- ml.link_analysis(.).final_dom.inner_text matches 'secured? (?:message|directory|document) access'
all of:
- length(filter(ml.nlu_classifier(body.current_thread.text).entities, .name == 'urgency')) ≥ 2
any of
ml.nlu_classifier(body.current_thread.text).topicswhere all hold:- .name is 'Secure Message'
- .confidence is not 'low'
- length(body.links) > 0
all of:
- sender.email.domain.root_domain not in ('protectedtrust.com')
any of
body.linkswhere:- .href_url.domain.root_domain is not sender.email.domain.root_domain
not:
all of
body.linkswhere:- .href_url.domain.root_domain in ('mimecast.com', 'cisco.com', 'csiesafe.com')
any of
headers.hopswhere all hold:- .index is 0
not:
any of
.fieldswhere:- .value contains 'multipart/mixed; boundary="PROOFPOINT_BOUNDARY_1"'
not:
all of:
- length(filter(attachments, strings.ilike(.file_name, 'logo.*', 'lock.gif', 'SecureMessageAtt.html'))) is 3
any of
attachmentswhere all hold:- .file_type is 'html'
any of
file.explode(.)where all hold:- .scan.html.title is 'Proofpoint Encryption'
any of
.scan.url.urlswhere:- .path ends with 'formpostdir/safeformpost.aspx'
- strings.count(file.parse_html(.).raw, 'name="msg') > 3
not:
all of:
any of
headers.hopswhere:any of
.fieldswhere:- .name in ('X-ZixNet', 'X-VPM-MIV', 'X-VPM-ActionCode', 'X-VPM-SmtpTo')
any of
headers.domainswhere:- .root_domain in ('zixport.com', 'zixcorp.com', 'zixmail.net', 'zixworks.com')
not:
all of:
any of
headers.hopswhere:any of
.fieldswhere:- .name is 'X-SendInc-Message-Id'
any of
headers.domainswhere:- .root_domain in ('sendinc.net')
not:
- length(filter(body.links, .display_text is null and .display_url.url == sender.email.domain.root_domain or .href_url.domain.root_domain in ('aka.ms', 'mimecast.com', 'cisco.com'))) is length(body.links)
any of:
all of:
- profile.by_sender().prevalence in ('new', 'outlier')
not:
- profile.by_sender().solicited
all of:
- profile.by_sender().any_messages_malicious_or_spam
not:
- profile.by_sender().any_messages_benign
any of:
- length(recipients.to) is 0
all of
recipients.towhere:- .display_name matches 'undisclosed?recipients'
all of:
- length(recipients.to) is 1
any of
recipients.towhere:- .email.email is sender.email.email
not:
- profile.by_sender().any_messages_benign
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_name, attachments[].file_type, body.current_thread.links, body.current_thread.links[].display_text, body.current_thread.links[].href_url.domain.domain, body.current_thread.links[].href_url.domain.root_domain, body.current_thread.text, body.links, body.links[].display_text, body.links[].display_url.url, body.links[].href_url.domain.root_domain, body.previous_threads, body.previous_threads[].text, headers.auth_summary.dmarc.pass, headers.domains, headers.domains[].root_domain, headers.hops, headers.hops[].fields, headers.hops[].fields[].name, headers.hops[].fields[].value, headers.hops[].index, recipients.to, recipients.to[].display_name, recipients.to[].email.email, sender.email.domain.root_domain, sender.email.email, type.inbound. Sensors: beta.ocr, file.explode, file.message_screenshot, file.parse_html, ml.link_analysis, ml.nlu_classifier, profile.by_sender, regex.icontains, strings.contains, strings.count, strings.icontains, strings.iends_with, strings.ilike. Reference lists: $free_file_hosts, $free_subdomain_hosts, $high_trust_sender_root_domains, $social_landing_hosts, $tranco_1m, $url_shorteners.
Indicators matched (36)
| Field | Match | Value |
|---|---|---|
ml.nlu_classifier(body.current_thread.text).intents[].name | equals | cred_theft |
ml.nlu_classifier(body.current_thread.text).intents[].confidence | equals | high |
regex.icontains | regex | (?:read|view|open) the message |
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents[].name | equals | cred_theft |
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents[].confidence | member | medium |
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents[].confidence | member | high |
regex.icontains | regex | secured? (message|directory|document) |
strings.icontains | substring | document portal |
strings.icontains | substring | encrypted message |
strings.icontains | substring | protected message |
regex.icontains | regex | secured? (?:message|directory|document) access |
ml.nlu_classifier(body.current_thread.text).entities[].name | equals | urgency |
24 more
ml.nlu_classifier(body.current_thread.text).topics[].name | equals | Secure Message |
sender.email.domain.root_domain | member | protectedtrust.com |
body.links[].href_url.domain.root_domain | member | mimecast.com |
body.links[].href_url.domain.root_domain | member | cisco.com |
body.links[].href_url.domain.root_domain | member | csiesafe.com |
strings.contains | substring | multipart/mixed; boundary="PROOFPOINT_BOUNDARY_1" |
strings.ilike | substring | logo.* |
strings.ilike | substring | lock.gif |
strings.ilike | substring | SecureMessageAtt.html |
attachments[].file_type | equals | html |
file.explode(attachments[])[].scan.html.title | equals | Proofpoint Encryption |
strings.iends_with | suffix | formpostdir/safeformpost.aspx |
headers.hops[].fields[].name | member | X-ZixNet |
headers.hops[].fields[].name | member | X-VPM-MIV |
headers.hops[].fields[].name | member | X-VPM-ActionCode |
headers.hops[].fields[].name | member | X-VPM-SmtpTo |
headers.domains[].root_domain | member | zixport.com |
headers.domains[].root_domain | member | zixcorp.com |
headers.domains[].root_domain | member | zixmail.net |
headers.domains[].root_domain | member | zixworks.com |
headers.hops[].fields[].name | equals | X-SendInc-Message-Id |
headers.domains[].root_domain | member | sendinc.net |
body.links[].href_url.domain.root_domain | member | aka.ms |
strings.ilike | substring | undisclosed?recipients |