Detection rules › Sublime MQL
Extortion / sextortion (untrusted sender)
Detects extortion and sextortion attempts by analyzing the email body text from an untrusted sender.
Threat classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Extortion |
| Tactics and techniques | Social engineering, Spoofing |
Event coverage
Rule body MQL
type.inbound
and length(filter(body.links, .display_text is not null)) < 10
and not (
ml.nlu_classifier(body.current_thread.text).language == "english"
and any(ml.nlu_classifier(body.html.display_text).topics,
.name in (
"News and Current Events",
"Newsletters and Digests",
"Advertising and Promotions"
)
and .confidence in ("high", "medium")
)
)
and (
(
any(ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).intents,
(.name == "extortion" and .confidence == "high")
)
and (
any(ml.nlu_classifier(strings.replace_confusables(body.current_thread.text
)
).entities,
.name == "financial"
or (
.name is not null
and regex.icontains(.text,
"cybḛ[rŗřṙȑȓɍʀɼɽг]c[rŗřṙȑȓɍʀɼɽг]imina[lĺļľḷḹḽłƖʟḻ]s"
)
)
)
or any(ml.nlu_classifier(strings.replace_confusables(body.current_thread.text
)
).topics,
.name == "Financial Communications" and .confidence != "low"
)
)
)
// catches extortion content delivered as inline base64 images
or (
(body.current_thread.text is null or length(body.current_thread.text) < 10)
and any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents,
.name == "extortion" and .confidence == "high"
)
and (
any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).entities,
.name == "financial"
)
or any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topics,
.name == "Financial Communications" and .confidence != "low"
)
)
)
// manual indicators failsafe
or 3 of (
// malware terms
regex.icontains(strings.replace_confusables(body.current_thread.text),
"(?:(?:spy|[mṁ][aȁḁ]l)[wŵ][aȁḁ][rŗ]e|[tŢ][rŗȓ][oốởộ]j[aǻä][nņ]|[rȓ]emote (?:entry|cont[rř]o[lĺ])|infiltrat(?:ed|ion)|backdoor|vi[rṙ]us|intruder|(?:your|the).{0,15}(?:device|system|computer|phone).{0,10}(?:became|was|got|is).{0,5}comprom[ḯiïíįī]sed|prov[ḯiïíįī]d[ḯiïíįī]ng.{0,20}full [aảǡą]ccess)"
),
// actions recorded
regex.icontains(strings.replace_confusables(body.current_thread.text),
"(?:p[oộ][rŗ]n|a[dȡ]ult (?:web)?site|webcam|mastu[rŗ]bating|je[rŗ]king off|pleasu[rŗȑ]i[nŋ]g you[rŗṛ]self|getting off|expli[cƈ]it|cl[ḯiïíįī]ps.{0,20}screenshots|NSFW|gr[aǻẳ]phic c[oỡở]ntent)"
),
regex.icontains(strings.replace_confusables(body.current_thread.text),
"(?:pe[rŗ]ve[rŗ]t|pe[rŗ]ve[rŗ]sion|mastu[rŗ]bat)"
),
// a timeframe to pay
regex.icontains(strings.replace_confusables(body.current_thread.text),
'[ilo0-9]{2} (?:hou[rŗṝ][sṣ]|uu[rŗ])',
'(?:one|tw[oờȍ]|2|th[rŗ]ee|\d) [dḍ][aảǡą]y[sṣ]?',
'set a timer'
),
// a promise from the actor
regex.icontains(strings.replace_confusables(body.current_thread.text),
'(?:pe[rŗ]manently|will|I''ll) delete|([rŗ]emove|destroy) (?:[\p{L}\p{M}\p{N}]+\s*){0,4} (?:data|ev[ḯiïįīí]dence|v[ḯiïíįī]deos?)'
),
// a threat from the actor
regex.icontains(strings.replace_confusables(body.current_thread.text),
'(?:\bsen[dt]|forward|expose|share)\s*(?:[\p{L}\p{N}]+\s*){0,5}\s*to\s*(?:[\p{L}\p{N}]+\s*){0,5}(?:contacts|media|family|f[rŗ]iends|coworkers|co-workers|associates|kin\b)'
),
// bitcoin language (excluding newsletters)
(
regex.icontains(strings.replace_confusables(body.current_thread.text),
'[bḆḂ]it[cĉƈ][oöة]i[nņɲ]|\bbtc\b|blockchain'
)
// negate cryptocurrency newsletters
and not (
any(body.links,
strings.icontains(.display_text, "unsubscribe")
and (
strings.icontains(.href_url.path, "unsubscribe")
// handle mimecast URL rewrites
or (
.href_url.domain.root_domain == 'mimecastprotect.com'
and strings.icontains(.href_url.query_params,
sender.email.domain.root_domain
)
)
)
)
)
),
(
regex.icontains(strings.replace_confusables(body.current_thread.text),
'(?:contact the police|(?:bitcoin|\bbtc\b).{0,20}(?:wallet|address))'
)
and regex.icontains(strings.replace_confusables(body.current_thread.text),
'(?:\b[13][a-km-zA-HJ-NP-Z0-9]{24,34}\b)|\bX[1-9A-HJ-NP-Za-km-z]{33}\b|\b(?:0x[a-fA-F0-9]{40})\b|\b[LM3][a-km-zA-HJ-NP-Z1-9]{26,33}\b|\b[48][0-9AB][1-9A-HJ-NP-Za-km-z]{93}\b'
)
),
regex.icontains(strings.replace_confusables(body.current_thread.text),
'bc1q.{0,50}\b'
),
(
regex.count(body.current_thread.text,
'[\x{0300}-\x{036F}\x{1AB0}-\x{1AFF}\x{1DC0}-\x{1DFF}\x{0100}-\x{024F}\x{1E00}-\x{1EFF}]'
) > 20
and length(body.current_thread.links) == 0
)
)
)
and (
not profile.by_sender().solicited
or (
profile.by_sender().any_messages_malicious_or_spam
and not profile.by_sender().any_messages_benign
)
or any(headers.hops, any(.fields, .name == "X-Google-Group-Id"))
// many extortion emails spoof sender domains and fail sender authentication
or (
not headers.auth_summary.dmarc.pass
or headers.auth_summary.dmarc.pass is null
or not headers.auth_summary.spf.pass
)
)
// negate legit bounce backs
and not any(ml.nlu_classifier(body.current_thread.text).topics,
.name in ("Bounce Back and Delivery Failure Notifications")
)
// negate legit forwards and replies
and not (
(subject.is_reply or subject.is_forward)
and length(body.previous_threads) > 0
and (length(headers.references) > 0 or headers.in_reply_to is not null)
)
// negate benign newsletters that mention cyber extortion
and not (
any(body.links,
strings.icontains(.display_text, "unsubscribe")
and strings.icontains(.href_url.path, "unsubscribe")
)
// newsletters are typically longer than the average extortion script
and length(body.current_thread.text) > 2000
)
and length(body.current_thread.text) < 8000
// 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 extortion and sextortion attempts by analyzing the email body text from an untrusted sender.
- inbound message
- length(filter(body.links, .display_text is not null)) < 10
not:
all of:
- ml.nlu_classifier(body.current_thread.text).language is 'english'
any of
ml.nlu_classifier(body.html.display_text).topicswhere all hold:- .name in ('News and Current Events', 'Newsletters and Digests', 'Advertising and Promotions')
- .confidence in ('high', 'medium')
any of:
all of:
any of
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).intentswhere all hold:- .name is 'extortion'
- .confidence is 'high'
any of:
any of
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).entitieswhere any holds:- .name is 'financial'
all of:
- .name is set
- .text matches 'cybḛ[rŗřṙȑȓɍʀɼɽг]c[rŗřṙȑȓɍʀɼɽг]imina[lĺļľḷḹḽłƖʟḻ]s'
any of
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).topicswhere all hold:- .name is 'Financial Communications'
- .confidence is not 'low'
all of:
any of:
- body.current_thread.text is missing
- length(body.current_thread.text) < 10
any of
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intentswhere all hold:- .name is 'extortion'
- .confidence is 'high'
any of:
any of
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).entitieswhere:- .name is 'financial'
any of
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topicswhere all hold:- .name is 'Financial Communications'
- .confidence is not 'low'
at least 3 of:
- strings.replace_confusables(body.current_thread.text) matches '(?:(?:spy|[mṁ][aȁḁ]l)[wŵ][aȁḁ][rŗ]e|[tŢ][rŗȓ][oốởộ]j[aǻä][nņ]|[rȓ]emote (?:entry|cont[rř]o[lĺ])|infiltrat(?:ed|ion)|backdoor|vi[rṙ]us|intruder|(?:your|the).{0,15}(?:device|system|computer|phone).{0,10}(?:became|was|got|is).{0,5}comprom[ḯiïíįī]sed|prov[ḯiïíįī]d[ḯiïíįī]ng.{0,20}full [aảǡą]ccess)'
- strings.replace_confusables(body.current_thread.text) matches '(?:p[oộ][rŗ]n|a[dȡ]ult (?:web)?site|webcam|mastu[rŗ]bating|je[rŗ]king off|pleasu[rŗȑ]i[nŋ]g you[rŗṛ]self|getting off|expli[cƈ]it|cl[ḯiïíįī]ps.{0,20}screenshots|NSFW|gr[aǻẳ]phic c[oỡở]ntent)'
- strings.replace_confusables(body.current_thread.text) matches '(?:pe[rŗ]ve[rŗ]t|pe[rŗ]ve[rŗ]sion|mastu[rŗ]bat)'
strings.replace_confusables(body.current_thread.text) matches any of 3 patterns
[ilo0-9]{2} (?:hou[rŗṝ][sṣ]|uu[rŗ])(?:one|tw[oờȍ]|2|th[rŗ]ee|\d) [dḍ][aảǡą]y[sṣ]?set a timer
- strings.replace_confusables(body.current_thread.text) matches "(?:pe[rŗ]manently|will|I'll) delete|([rŗ]emove|destroy) (?:[\\p{L}\\p{M}\\p{N}]+\\s*){0,4} (?:data|ev[ḯiïįīí]dence|v[ḯiïíįī]deos?)"
- strings.replace_confusables(body.current_thread.text) matches '(?:\\bsen[dt]|forward|expose|share)\\s*(?:[\\p{L}\\p{N}]+\\s*){0,5}\\s*to\\s*(?:[\\p{L}\\p{N}]+\\s*){0,5}(?:contacts|media|family|f[rŗ]iends|coworkers|co-workers|associates|kin\\b)'
all of:
- strings.replace_confusables(body.current_thread.text) matches '[bḆḂ]it[cĉƈ][oöة]i[nņɲ]|\\bbtc\\b|blockchain'
not:
any of
body.linkswhere all hold:- .display_text contains 'unsubscribe'
any of:
- .href_url.path contains 'unsubscribe'
all of:
- .href_url.domain.root_domain is 'mimecastprotect.com'
- strings.icontains(.href_url.query_params)
all of:
- strings.replace_confusables(body.current_thread.text) matches '(?:contact the police|(?:bitcoin|\\bbtc\\b).{0,20}(?:wallet|address))'
- strings.replace_confusables(body.current_thread.text) matches '(?:\\b[13][a-km-zA-HJ-NP-Z0-9]{24,34}\\b)|\\bX[1-9A-HJ-NP-Za-km-z]{33}\\b|\\b(?:0x[a-fA-F0-9]{40})\\b|\\b[LM3][a-km-zA-HJ-NP-Z1-9]{26,33}\\b|\\b[48][0-9AB][1-9A-HJ-NP-Za-km-z]{93}\\b'
- strings.replace_confusables(body.current_thread.text) matches 'bc1q.{0,50}\\b'
all of:
- regex.count(body.current_thread.text, '[\\x{0300}-\\x{036F}\\x{1AB0}-\\x{1AFF}\\x{1DC0}-\\x{1DFF}\\x{0100}-\\x{024F}\\x{1E00}-\\x{1EFF}]') > 20
- length(body.current_thread.links) is 0
any of:
not:
- profile.by_sender().solicited
all of:
- profile.by_sender().any_messages_malicious_or_spam
not:
- profile.by_sender().any_messages_benign
any of
headers.hopswhere:any of
.fieldswhere:- .name is 'X-Google-Group-Id'
any of:
not:
- headers.auth_summary.dmarc.pass
- headers.auth_summary.dmarc.pass is missing
not:
- headers.auth_summary.spf.pass
not:
any of
ml.nlu_classifier(body.current_thread.text).topicswhere:- .name in ('Bounce Back and Delivery Failure Notifications')
not:
all of:
any of:
- subject.is_reply
- subject.is_forward
- length(body.previous_threads) > 0
any of:
- length(headers.references) > 0
- headers.in_reply_to is set
not:
all of:
any of
body.linkswhere all hold:- .display_text contains 'unsubscribe'
- .href_url.path contains 'unsubscribe'
- length(body.current_thread.text) > 2000
- length(body.current_thread.text) < 8000
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: body.current_thread.links, body.current_thread.text, body.html.display_text, body.links, body.links[].display_text, body.links[].href_url.domain.root_domain, body.links[].href_url.path, body.links[].href_url.query_params, body.previous_threads, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, headers.hops, headers.hops[].fields, headers.hops[].fields[].name, headers.in_reply_to, headers.references, sender.email.domain.root_domain, subject.is_forward, subject.is_reply, type.inbound. Sensors: beta.ocr, file.message_screenshot, ml.nlu_classifier, profile.by_sender, regex.count, regex.icontains, strings.icontains, strings.replace_confusables. Reference lists: $high_trust_sender_root_domains.
Indicators matched (31)
| Field | Match | Value |
|---|---|---|
ml.nlu_classifier(body.html.display_text).topics[].name | member | News and Current Events |
ml.nlu_classifier(body.html.display_text).topics[].name | member | Newsletters and Digests |
ml.nlu_classifier(body.html.display_text).topics[].name | member | Advertising and Promotions |
ml.nlu_classifier(body.html.display_text).topics[].confidence | member | high |
ml.nlu_classifier(body.html.display_text).topics[].confidence | member | medium |
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).intents[].name | equals | extortion |
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).intents[].confidence | equals | high |
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).entities[].name | equals | financial |
regex.icontains | regex | cybḛ[rŗřṙȑȓɍʀɼɽг]c[rŗřṙȑȓɍʀɼɽг]imina[lĺļľḷḹḽłƖʟḻ]s |
ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).topics[].name | equals | Financial Communications |
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents[].name | equals | extortion |
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents[].confidence | equals | high |
19 more
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).entities[].name | equals | financial |
ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topics[].name | equals | Financial Communications |
regex.icontains | regex | (?:(?:spy|[mṁ][aȁḁ]l)[wŵ][aȁḁ][rŗ]e|[tŢ][rŗȓ][oốởộ]j[aǻä][nņ]|[rȓ]emote (?:entry|cont[rř]o[lĺ])|infiltrat(?:ed|ion)|backdoor|vi[rṙ]us|intruder|(?:your|the).{0,15}(?:device|system|computer|phone).{0,10}(?:became|was|got|is).{0,5}comprom[ḯiïíįī]sed|prov[ḯiïíįī]d[ḯiïíįī]ng.{0,20}full [aảǡą]ccess) |
regex.icontains | regex | (?:p[oộ][rŗ]n|a[dȡ]ult (?:web)?site|webcam|mastu[rŗ]bating|je[rŗ]king off|pleasu[rŗȑ]i[nŋ]g you[rŗṛ]self|getting off|expli[cƈ]it|cl[ḯiïíįī]ps.{0,20}screenshots|NSFW|gr[aǻẳ]phic c[oỡở]ntent) |
regex.icontains | regex | (?:pe[rŗ]ve[rŗ]t|pe[rŗ]ve[rŗ]sion|mastu[rŗ]bat) |
regex.icontains | regex | [ilo0-9]{2} (?:hou[rŗṝ][sṣ]|uu[rŗ]) |
regex.icontains | regex | (?:one|tw[oờȍ]|2|th[rŗ]ee|\d) [dḍ][aảǡą]y[sṣ]? |
regex.icontains | regex | set a timer |
regex.icontains | regex | (?:pe[rŗ]manently|will|I'll) delete|([rŗ]emove|destroy) (?:[\p{L}\p{M}\p{N}]+\s*){0,4} (?:data|ev[ḯiïįīí]dence|v[ḯiïíįī]deos?) |
regex.icontains | regex | (?:\bsen[dt]|forward|expose|share)\s*(?:[\p{L}\p{N}]+\s*){0,5}\s*to\s*(?:[\p{L}\p{N}]+\s*){0,5}(?:contacts|media|family|f[rŗ]iends|coworkers|co-workers|associates|kin\b) |
regex.icontains | regex | [bḆḂ]it[cĉƈ][oöة]i[nņɲ]|\bbtc\b|blockchain |
strings.icontains | substring | unsubscribe |
body.links[].href_url.domain.root_domain | equals | mimecastprotect.com |
regex.icontains | regex | (?:contact the police|(?:bitcoin|\bbtc\b).{0,20}(?:wallet|address)) |
regex.icontains | regex | (?:\b[13][a-km-zA-HJ-NP-Z0-9]{24,34}\b)|\bX[1-9A-HJ-NP-Za-km-z]{33}\b|\b(?:0x[a-fA-F0-9]{40})\b|\b[LM3][a-km-zA-HJ-NP-Z1-9]{26,33}\b|\b[48][0-9AB][1-9A-HJ-NP-Za-km-z]{93}\b |
regex.icontains | regex | bc1q.{0,50}\b |
regex.count | regex | [\x{0300}-\x{036F}\x{1AB0}-\x{1AFF}\x{1DC0}-\x{1DFF}\x{0100}-\x{024F}\x{1E00}-\x{1EFF}] |
headers.hops[].fields[].name | equals | X-Google-Group-Id |
ml.nlu_classifier(body.current_thread.text).topics[].name | member | Bounce Back and Delivery Failure Notifications |