Detection rules › Sublime MQL
Spam: Attendee list solicitation
This rule detects messages claiming to have the attendee list from a specific event, they may list various information such as the number of contacts, the demographic and sample contacts. The messages typically offer to send pricing information upon request.
Threat classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Spam |
Event coverage
Rule body MQL
type.inbound
and length(body.current_thread.text) < 2000
and length(body.links) < 5
and any(ml.nlu_classifier(coalesce(body.html.display_text, body.plain.raw)).topics,
.name in ("Contact List Solicitation", "B2B Cold Outreach")
and .confidence in ("medium", "high")
)
and (
(
(
any([subject.subject, body.current_thread.text],
(
regex.icontains(.,
'(?:Attendee|Buyer|Contact|Decision Maker|Email|Member|Participant|Professional|Registrant|User|Visitor|Store|Grocer|Lead)(?:[[:punct:]]*s)?(?:\s\w*){0,9}(?:\blist(?:\b|[^ei])|database)'
)
and not (
regex.icount(.,
'(email|contact)(?:[[:punct:]]*s)?(?:\s\w*){0,9}list'
) == 1
and regex.icontains(.,
'(?:unsub|remove|safe|delete|leave|update|part of|be added|safe)[[:punct:]]*s?(?:\s\w*){0,9}(mailing|email|my|sender)(?:\s\w*){0,9}list(?:\b|[^ei])',
'email list(?:\b|[^ei])[[:punct:]]*s?(\s\w*){0,5}(?:unsub|remove|safe|delete|leave|up to date|part of|be added)'
)
)
)
or regex.icontains(.,
'\b(?:list|database)(?:[[:punct:]]*s)?\b(\s\w*){0,9}(?:Attendee|Buyer|Contact|Decision Maker|Email|Member|Participant|Professional|Registrant|User|Visitor|Store|Grocer)s?'
)
)
)
and (
regex.icontains(body.current_thread.text,
"(?:interest(s|ed)|accessing|purchas|obtain|acuir|sample|provide.{0,10}samples|counts|pricing)"
)
or any(body.previous_threads,
regex.icontains(.text,
"(?:interest(s|ed)|accessing|purchas|obtain|acuir|sample|provide.{0,10}samples|counts|pricing)"
)
)
)
and not regex.icontains(body.current_thread.text,
"(?:debit card|transaction.{0,20}processed)"
)
)
// if there are indicators of a previous thread, also inspect the previous thread
or (
// contains references to the previous thread
2 of (
regex.icontains(body.current_thread.text, '(?:get|got|had) a chance'),
regex.icontains(body.current_thread.text, '(take|move)(\Wthis)?\Wforward'),
regex.icontains(body.current_thread.text,
'(review|drop me a line about) (my|this|it)'
),
regex.icontains(body.current_thread.text, 'missed it( the)? first time'),
regex.icontains(body.current_thread.text,
'(?:below|previous(ly)?|last|prior|earlier) (message|email|sent)'
),
regex.icontains(body.current_thread.text,
// "the email I sent you earlier"
'(e?mail|message).{0,20}(sent).{0,20}(?:below|previous(ly)?|last|prior|earlier)'
),
regex.icontains(body.current_thread.text,
'(sent).{0,50}(e?mail|message) (?:below|previous(ly)?|last|prior|earlier)'
),
regex.icontains(body.current_thread.text, 'follow(?:ing)?(-| )up'),
regex.icontains(body.current_thread.text, '(?:contact|attendee)s? list'),
regex.icontains(body.current_thread.text, '(any|get an) update.{0,50}\?'),
regex.icontains(body.current_thread.text, '(heard?|circling) back'),
strings.icontains(body.current_thread.text, 'recently sent'),
strings.icontains(body.current_thread.text, 'still interested'),
regex.icontains(body.current_thread.text,
'did you (get|receive) (it|my (message|e?mail))'
),
regex.icontains(body.current_thread.text, '(swift|quick|short) response'),
regex.icontains(body.current_thread.text, 'kindly.{0,30}.interested'),
)
and any([body.html.display_text, body.plain.raw],
(
3 of (
strings.icontains(., "from:"),
strings.icontains(., "to:"),
strings.icontains(., "sent:"),
strings.icontains(., "date:"),
strings.icontains(., "cc:"),
strings.icontains(., "subject:"),
strings.icontains(., "--Original Message--")
)
or strings.icontains(.,
strings.concat(sender.display_name,
" <",
sender.email.email,
"> wrote:"
)
)
)
// match _after_ the previous thread indciators
and (
regex.icontains(.,
'(?:from|to|sent|date|cc|subject|wrote):(.|\W)*(?:Attendee|Buyer|Contact|Decision Maker|Email|Member|Participant|Professional|Registrant|User|Visitor|Mailing)(?:[[:punct:]]*s)?(?:\s\w*){0,9}(?:list(?:\b|[^ei])|database)'
)
or regex.icontains(.,
'(?:from|to|sent|date|cc|subject|wrote):(.|\W)*(?:list(?:\b|[^ei])|database)(?:[[:punct:]]*s)?(\s\w*){0,9}(?:Attendee|Buyer|Contact|Decision Maker|Email|Member|Participant|Professional|Registrant|User|Visitor|Mailing)s?'
)
or (
2 of (
strings.icontains(., "provide counts"),
regex.icontains(., "(?:verified|fresh) data"),
strings.icontains(., "precise targeting"),
strings.icontains(., "deliverability"),
regex.icontains(., "target (verticals|regions|criteria)")
)
and regex.icontains(., '(?:list(?:\b|[^ei])|database)')
)
)
)
)
)
// negate Zendesk support tickets
and not any(body.links,
.href_url.domain.root_domain in ('zendesk.com')
and .display_text == 'Zendesk'
)
and not profile.by_sender().solicited
and not profile.by_sender().any_messages_benign
Detection logic
Scope: inbound message.
This rule detects messages claiming to have the attendee list from a specific event, they may list various information such as the number of contacts, the demographic and sample contacts. The messages typically offer to send pricing information upon request.
- inbound message
- length(body.current_thread.text) < 2000
- length(body.links) < 5
any of
ml.nlu_classifier(coalesce(body.html.display_text, body.plain.raw)).topicswhere all hold:- .name in ('Contact List Solicitation', 'B2B Cold Outreach')
- .confidence in ('medium', 'high')
any of:
all of:
any of
[subject.subject, body.current_thread.text]where any holds:all of:
- . matches '(?:Attendee|Buyer|Contact|Decision Maker|Email|Member|Participant|Professional|Registrant|User|Visitor|Store|Grocer|Lead)(?:[[:punct:]]*s)?(?:\\s\\w*){0,9}(?:\\blist(?:\\b|[^ei])|database)'
not:
all of:
- regex.icount(., '(email|contact)(?:[[:punct:]]*s)?(?:\\s\\w*){0,9}list') is 1
. matches any of 2 patterns
(?:unsub|remove|safe|delete|leave|update|part of|be added|safe)[[:punct:]]*s?(?:\s\w*){0,9}(mailing|email|my|sender)(?:\s\w*){0,9}list(?:\b|[^ei])email list(?:\b|[^ei])[[:punct:]]*s?(\s\w*){0,5}(?:unsub|remove|safe|delete|leave|up to date|part of|be added)
- . matches '\\b(?:list|database)(?:[[:punct:]]*s)?\\b(\\s\\w*){0,9}(?:Attendee|Buyer|Contact|Decision Maker|Email|Member|Participant|Professional|Registrant|User|Visitor|Store|Grocer)s?'
any of:
- body.current_thread.text matches '(?:interest(s|ed)|accessing|purchas|obtain|acuir|sample|provide.{0,10}samples|counts|pricing)'
any of
body.previous_threadswhere:- .text matches '(?:interest(s|ed)|accessing|purchas|obtain|acuir|sample|provide.{0,10}samples|counts|pricing)'
not:
- body.current_thread.text matches '(?:debit card|transaction.{0,20}processed)'
all of:
at least 2 of:
- body.current_thread.text matches '(?:get|got|had) a chance'
- body.current_thread.text matches '(take|move)(\\Wthis)?\\Wforward'
- body.current_thread.text matches '(review|drop me a line about) (my|this|it)'
- body.current_thread.text matches 'missed it( the)? first time'
- body.current_thread.text matches '(?:below|previous(ly)?|last|prior|earlier) (message|email|sent)'
- body.current_thread.text matches '(e?mail|message).{0,20}(sent).{0,20}(?:below|previous(ly)?|last|prior|earlier)'
- body.current_thread.text matches '(sent).{0,50}(e?mail|message) (?:below|previous(ly)?|last|prior|earlier)'
- body.current_thread.text matches 'follow(?:ing)?(-| )up'
- body.current_thread.text matches '(?:contact|attendee)s? list'
- body.current_thread.text matches '(any|get an) update.{0,50}\\?'
- body.current_thread.text matches '(heard?|circling) back'
- body.current_thread.text contains 'recently sent'
- body.current_thread.text contains 'still interested'
- body.current_thread.text matches 'did you (get|receive) (it|my (message|e?mail))'
- body.current_thread.text matches '(swift|quick|short) response'
- body.current_thread.text matches 'kindly.{0,30}.interested'
any of
[body.html.display_text, body.plain.raw]where all hold:any of:
at least 3 of 7: . contains any of 7 patterns
from:to:sent:date:cc:subject:--Original Message--
- strings.icontains(.)
any of:
- . matches '(?:from|to|sent|date|cc|subject|wrote):(.|\\W)*(?:Attendee|Buyer|Contact|Decision Maker|Email|Member|Participant|Professional|Registrant|User|Visitor|Mailing)(?:[[:punct:]]*s)?(?:\\s\\w*){0,9}(?:list(?:\\b|[^ei])|database)'
- . matches '(?:from|to|sent|date|cc|subject|wrote):(.|\\W)*(?:list(?:\\b|[^ei])|database)(?:[[:punct:]]*s)?(\\s\\w*){0,9}(?:Attendee|Buyer|Contact|Decision Maker|Email|Member|Participant|Professional|Registrant|User|Visitor|Mailing)s?'
all of:
at least 2 of:
- . contains 'provide counts'
- . matches '(?:verified|fresh) data'
- . contains 'precise targeting'
- . contains 'deliverability'
- . matches 'target (verticals|regions|criteria)'
- . matches '(?:list(?:\\b|[^ei])|database)'
not:
any of
body.linkswhere all hold:- .href_url.domain.root_domain in ('zendesk.com')
- .display_text is 'Zendesk'
not:
- profile.by_sender().solicited
not:
- profile.by_sender().any_messages_benign
Inspects: body.current_thread.text, body.html.display_text, body.links, body.links[].display_text, body.links[].href_url.domain.root_domain, body.plain.raw, body.previous_threads, body.previous_threads[].text, sender.display_name, sender.email.email, subject.subject, type.inbound. Sensors: ml.nlu_classifier, profile.by_sender, regex.icontains, regex.icount, strings.concat, strings.icontains.
Indicators matched (44)
| Field | Match | Value |
|---|---|---|
ml.nlu_classifier(coalesce(body.html.display_text, body.plain.raw)).topics[].name | member | Contact List Solicitation |
ml.nlu_classifier(coalesce(body.html.display_text, body.plain.raw)).topics[].name | member | B2B Cold Outreach |
ml.nlu_classifier(coalesce(body.html.display_text, body.plain.raw)).topics[].confidence | member | medium |
ml.nlu_classifier(coalesce(body.html.display_text, body.plain.raw)).topics[].confidence | member | high |
regex.icontains | regex | (?:Attendee|Buyer|Contact|Decision Maker|Email|Member|Participant|Professional|Registrant|User|Visitor|Store|Grocer|Lead)(?:[[:punct:]]*s)?(?:\s\w*){0,9}(?:\blist(?:\b|[^ei])|database) |
regex.icount | regex | (email|contact)(?:[[:punct:]]*s)?(?:\s\w*){0,9}list |
regex.icontains | regex | (?:unsub|remove|safe|delete|leave|update|part of|be added|safe)[[:punct:]]*s?(?:\s\w*){0,9}(mailing|email|my|sender)(?:\s\w*){0,9}list(?:\b|[^ei]) |
regex.icontains | regex | email list(?:\b|[^ei])[[:punct:]]*s?(\s\w*){0,5}(?:unsub|remove|safe|delete|leave|up to date|part of|be added) |
regex.icontains | regex | \b(?:list|database)(?:[[:punct:]]*s)?\b(\s\w*){0,9}(?:Attendee|Buyer|Contact|Decision Maker|Email|Member|Participant|Professional|Registrant|User|Visitor|Store|Grocer)s? |
regex.icontains | regex | (?:interest(s|ed)|accessing|purchas|obtain|acuir|sample|provide.{0,10}samples|counts|pricing) |
regex.icontains | regex | (?:debit card|transaction.{0,20}processed) |
regex.icontains | regex | (?:get|got|had) a chance |
32 more
regex.icontains | regex | (take|move)(\Wthis)?\Wforward |
regex.icontains | regex | (review|drop me a line about) (my|this|it) |
regex.icontains | regex | missed it( the)? first time |
regex.icontains | regex | (?:below|previous(ly)?|last|prior|earlier) (message|email|sent) |
regex.icontains | regex | (e?mail|message).{0,20}(sent).{0,20}(?:below|previous(ly)?|last|prior|earlier) |
regex.icontains | regex | (sent).{0,50}(e?mail|message) (?:below|previous(ly)?|last|prior|earlier) |
regex.icontains | regex | follow(?:ing)?(-| )up |
regex.icontains | regex | (?:contact|attendee)s? list |
regex.icontains | regex | (any|get an) update.{0,50}\? |
regex.icontains | regex | (heard?|circling) back |
strings.icontains | substring | recently sent |
strings.icontains | substring | still interested |
regex.icontains | regex | did you (get|receive) (it|my (message|e?mail)) |
regex.icontains | regex | (swift|quick|short) response |
regex.icontains | regex | kindly.{0,30}.interested |
strings.icontains | substring | from: |
strings.icontains | substring | to: |
strings.icontains | substring | sent: |
strings.icontains | substring | date: |
strings.icontains | substring | cc: |
strings.icontains | substring | subject: |
strings.icontains | substring | --Original Message-- |
regex.icontains | regex | (?:from|to|sent|date|cc|subject|wrote):(.|\W)*(?:Attendee|Buyer|Contact|Decision Maker|Email|Member|Participant|Professional|Registrant|User|Visitor|Mailing)(?:[[:punct:]]*s)?(?:\s\w*){0,9}(?:list(?:\b|[^ei])|database) |
regex.icontains | regex | (?:from|to|sent|date|cc|subject|wrote):(.|\W)*(?:list(?:\b|[^ei])|database)(?:[[:punct:]]*s)?(\s\w*){0,9}(?:Attendee|Buyer|Contact|Decision Maker|Email|Member|Participant|Professional|Registrant|User|Visitor|Mailing)s? |
strings.icontains | substring | provide counts |
regex.icontains | regex | (?:verified|fresh) data |
strings.icontains | substring | precise targeting |
strings.icontains | substring | deliverability |
regex.icontains | regex | target (verticals|regions|criteria) |
regex.icontains | regex | (?:list(?:\b|[^ei])|database) |
body.links[].href_url.domain.root_domain | member | zendesk.com |
body.links[].display_text | equals | Zendesk |