Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update link_credential_phishing_voicemail_language.yml #2195

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 123 additions & 16 deletions detection-rules/link_credential_phishing_voicemail_language.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ severity: "medium"
source: |
type.inbound
// contains links or attachments
and (0 < length(body.links) <= 15 or 0 < length(attachments) <= 3)
and (
0 < length(body.links) <= 15 or 0 < length(distinct(attachments, .md5)) <= 3
)

// the subject or display_name need some keywords which are voicemail related
and (
any([subject.subject, sender.display_name],
Expand All @@ -21,7 +24,6 @@ source: |
// starts in the format of `(4)` and contains some voicemail keywords
'^\(\d\)\s(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}(?:message|voip|voice|unread|call)',
'ca[li1][li1](?:er)?(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}(?:playback|transcript)',

// obfuscated phone number with at least one digit in the area code and at least one obfuscated number in the last group
// 555-555-555X, 555-555-XXXX, 555-5XX-XXXX
'\b1?\(?(\d{3}|\d{2}[\*X]|\d[\*X]{2})\)?[^a-z0-9]{0,2}(\d{2,3}|\d{2}[\*X]|\d[\*X]{2}|[\*X]{2,3})[^a-z0-9]{0,4}(\d{3}[\*X]|\d{2}[\*X]{2}|\d[\*X]{3}|[\*X]{3,4})[^0-9]',
Expand All @@ -31,9 +33,8 @@ source: |
)
)
// body.current_thread.text inspection should be very specific to avoid FP
or regex.icontains(
strings.replace_confusables(body.current_thread.text),
//body.current_thread.text,
or regex.icontains(strings.replace_confusables(body.current_thread.text),
// body.current_thread.text,
'you (?:have |received )*(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}\bvoice\s?(?:mail|audio|message)',
'sent (?:from|by) (?:your )?voice (?:mail )?system',
'new (?:voice(?:mail)?|audio) (?:message|notification|record)',
Expand All @@ -49,11 +50,30 @@ source: |
'Listen to VoiceMail',
'New voicemail from'
)
// Reuse the body.current_thread.text logic against the OCR output of the message screenshot
or any((filter(file.explode(beta.message_screenshot()), .depth == 0)),
regex.icontains( .scan.ocr.raw,
// body.current_thread.text,
'you (?:have |received )*(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}\bvoice\s?(?:mail|audio|message)',
'sent (?:from|by) (?:your )?voice (?:mail )?system',
'new (?:voice(?:mail)?|audio) (?:message|notification|record)',
'voicemail (is )?attached',
'an? (?:new )?encrypted voicemail',
'a (?:new )?pending message',
'Your? have (?: an?)?incoming voiceRec',
"you(?:\'ve| have) a (?:new )?missed ca[li1][li1]",
'New Voicemail Received',
'left you a (?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}(?:voice(?:mail)?|audio)(?: message)?',
'New missed ca[li1][li1] record',
'voicemail transcript(?:ion)?',
'Listen to VoiceMail',
'New voicemail from'
)
)
// phishing template observed https://platform.sublime.security/messages/341eed2be003036cdd3eeee575202df8a7472b6567d0dfa0f99c3b3fb42a8e7f
or strings.icontains(body.html.raw, '<title>Voicemail Notification</title>')
or strings.icontains(body.html.raw, '<!-- Voicemail phone logo')
)

and 2 of (
(
// the sender is a freemail
Expand All @@ -63,6 +83,13 @@ source: |
any(ml.nlu_classifier(body.current_thread.text).intents,
.name in ("cred_theft") and .confidence in ("medium", "high")
)
or
// use the OCR from the message screenshot
any(filter(file.explode(beta.message_screenshot()), .depth == 0),
any(ml.nlu_classifier(.scan.ocr.raw).intents,
.name in ("cred_theft") and .confidence in ("medium", "high")
)
)
),
(
any(attachments,
Expand Down Expand Up @@ -117,22 +144,23 @@ source: |
.content_type in ("html", "text", "text/html")
or .file_type in ("html", "unknown")
)
and (.size < 1500 and any(file.explode(.), length(.scan.html.scripts) > 0)
and (
.size < 1500 and any(file.explode(.), length(.scan.html.scripts) > 0)
)
)
),
(
any(attachments,
(
.content_type in ("html", "text", "text/html")
or .file_type in ("html", "unknown")
.content_type in ("html", "text", "text/html")
or .file_type in ("html", "unknown")
)
and any(recipients.to,
// the html attachment contains a receipient email address
strings.contains(file.parse_html(..).raw, .email.email)
// the sld of the domain is in the attachment name
or strings.contains(..file_name, .email.domain.sld)
)
)
)
),
// the body links contain the recipients email
Expand All @@ -155,11 +183,15 @@ source: |
// sender domain matches no body domains
// only inspect "links" that have a display_text and display_url is null to remove "plain text" email address from being caught
length(filter(body.links,
.display_text is not null and .display_url.url is null and .href_url.domain.valid
.display_text is not null
and .display_url.url is null
and .href_url.domain.valid
)
) > 0
and all(filter(body.links,
.display_text is not null and .display_url.url is null and .href_url.domain.valid
.display_text is not null
and .display_url.url is null
and .href_url.domain.valid
),
.href_url.domain.root_domain != sender.email.domain.root_domain
and .href_url.domain.root_domain not in $org_domains
Expand Down Expand Up @@ -200,12 +232,15 @@ source: |
and not strings.icontains(.href_url.path, "unsubscribe")
)
),
// sld use in sender/subject selements
(
any(recipients.to,
// recipient's SLD is in the sender's display name
strings.icontains(sender.display_name, .email.domain.sld)
// recipient's SLD is in the sender's display name
or strings.icontains(subject.subject, .email.domain.sld)
// recipient's SLD is in the senders local_part
or strings.icontains(sender.email.local_part, .email.domain.sld)
)
),
// often times the subject or sender display name will contain time references
Expand All @@ -225,6 +260,22 @@ source: |
'[\(\[](?:\d{1,2}[\:\s-])\d{1,2}[\)\]]\s'
)
)
// resuse the same logic against ORC output of message_screenshot
or any(filter(file.explode(beta.message_screenshot()), .depth == 0),
regex.icontains(.scan.ocr.raw,
// 01min , 60secs
'0?[1-9]\s*min(?:(?:ute)?s)?\b',
'\d{1,2}\s*s(?:ec(?:ond)?s)?\b',
// (00:50s)
// 3:26 seconds
'[\(\[]?(?:\d{1,2}[\:\s-])\d{1,2}[\)\]]?\s*(?:s(?:(?:ecs?)onds)?)[\)\]]?',
// 03min25secs
'0?[1-9]\s*min(?:(?:ute)?s)?\d{1,2}\s*s(?:ec(?:ond)?s)?',
// [0:39]
// (0:39)
'[\(\[](?:\d{1,2}[\:\s-])\d{1,2}[\)\]]\s'
)
)
),
// often times the subject or sender display name will contain dates
(
Expand Down Expand Up @@ -283,6 +334,62 @@ source: |
'(0[1-9]|1[0-2]):([0-5]\d):([0-5]\d) ?([AaPp][Mm])'
)
)
// or use the OCR results from beta.message_screenshot
or any(filter(file.explode(beta.message_screenshot()), .depth == 0),
// days of week
any([
'monday',
'tuesday',
'wednesday',
'thursday',
'friday',
'saturday',
'sunday'
],
strings.icontains(..scan.ocr.raw, .)
)
// months
// may is problematic for words like "Mayor", "Maybe", "MayFlower", etc
or any([
"January",
"February",
"March",
"April",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
],
strings.icontains(..scan.ocr.raw, .)
)
// use a regex for May
or regex.icontains(.scan.ocr.raw, '\bmay\b')
// common date formats
or regex.contains(.scan.ocr.raw,
// YYYY-MM-DD or YY-MM-DD (ISO 8601 format)
'\d{2}(\d{2})?-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])',
// MM/DD/YYYY or MM/DD/YY (US format)
'(0[1-9]|1[0-2])/(0[1-9]|[12]\d|3[01])/\d{2}(\d{2})?',
// DD/MM/YYYY or DD/MM/YY (European format)
'(0[1-9]|[12]\d|3[01])/(0[1-9]|1[0-2])/\d{2}(\d{2})?',
// Month DD, YYYY or Month DD, YY (e.g., March 15, 2024 or March 15, 24)
'(January|February|March|April|May|June|July|August|September|October|November|December) (0[1-9]|[12]\d|3[01]), \d{2}(\d{2})?'
)
// common time formats
or regex.contains(.scan.ocr.raw,
// Example: 23:45, 08:30
'([01]\d|2[0-3]):([0-5]\d)',
// Example: 23:45:59, 08:30:12
'([01]\d|2[0-3]):([0-5]\d):([0-5]\d)',
// Example: 08:30 AM, 12:45 pm
'(0[1-9]|1[0-2]):([0-5]\d)\s?([AaPp][Mm])',
// Example: 08:30 AM, 12:45 pm
'(0[1-9]|1[0-2]):([0-5]\d):([0-5]\d) ?([AaPp][Mm])'
)
)
),
// there are often emoji in the sender display name
(
Expand Down Expand Up @@ -354,10 +461,10 @@ source: |
)
// bounce-back negations
and not any(attachments,
any(file.parse_eml(.).attachments,
.content_type == "message/delivery-status"
)
)
any(file.parse_eml(.).attachments,
.content_type == "message/delivery-status"
)
)
// bounce-back negations
and not (
any(attachments,
Expand Down
Loading