Spam: Fake photo share
Message contains pretexting language about sharing photos ("found these photos and thought you'd like them", "remember these photos?") and a link with a newly registered domain. Fake threads and plain text bodies have been seen in the wild, indicating active evasion techniques.
Sublime rule (View on GitHub)
1name: "Spam: Fake photo share"
2description: 'Message contains pretexting language about sharing photos ("found these photos and thought you''d like them", "remember these photos?") and a link with a newly registered domain. Fake threads and plain text bodies have been seen in the wild, indicating active evasion techniques.'
3type: "rule"
4severity: "low"
5source: |
6 type.inbound
7 and length(attachments) == 0
8 and (
9 (
10 (
11 (
12 (length(body.plain.raw) < 500 and length(body.current_thread.text) == 0)
13 or (
14 length(body.html.display_text) < 500
15 and length(body.current_thread.text) == 0
16 )
17 or length(body.current_thread.text) < 500
18 or any(map(filter(ml.nlu_classifier(body.current_thread.text).entities,
19 .name == "disclaimer"
20 ),
21 .text
22 ),
23 (length(body.current_thread.text) - length(.)) < 500
24 )
25 )
26 and strings.ilike(subject.subject,
27 "*picture*",
28 "*photo*",
29 "*image*",
30 "*sad news*",
31 "*sad announcement*",
32 "*sad update*",
33 "*new pics*",
34 "*Reunion*",
35 "*planing*",
36 "*back memories*",
37 "*any memories*",
38 "*old memories*",
39 "*evoke memories*",
40 "*bittersweet memories*"
41 )
42 )
43 or (
44 (
45 (
46 length(body.html.display_text) < 500
47 and length(body.current_thread.text) == 0
48 )
49 and strings.ilike(body.html.display_text,
50 "*picture*",
51 "*photo*",
52 "*image*",
53 "*sad news*",
54 "*sad announcement*",
55 "*sad update*",
56 "*new pics*",
57 "*back memories*",
58 "*any memories*",
59 "*old memories*",
60 "*evoke memories*",
61 "*bittersweet memories*"
62 )
63 )
64 or (
65 (length(body.plain.raw) < 500 and length(body.current_thread.text) == 0)
66 and strings.ilike(body.plain.raw,
67 "*picture*",
68 "*photo*",
69 "*image*",
70 "*sad news*",
71 "*sad announcement*",
72 "*sad update*",
73 "*new pics*",
74 "*back memories*",
75 "*any memories*",
76 "*old memories*",
77 "*evoke memories*",
78 "*bittersweet memories*"
79 )
80 and not strings.icontains(body.plain.raw, "[cid:image")
81 )
82 or (
83 length(body.current_thread.text) < 500
84 and strings.ilike(body.current_thread.text,
85 "*picture*",
86 "*photo*",
87 "*image*",
88 "*sad news*",
89 "*sad announcement*",
90 "*sad update*",
91 "*new pics*",
92 "*back memories*",
93 "*any memories*",
94 "*old memories*",
95 "*evoke memories*",
96 "*bittersweet memories*"
97 )
98 )
99 )
100 or (
101 body.plain.raw is not null
102 and body.html.display_text is null
103 and (
104 length(body.current_thread.text) == 0
105 or (
106 length(body.current_thread.text) < 500
107 // fake forward indicator in the plain text body
108 and (
109 regex.contains(body.plain.raw,
110 'On (Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday).{0,50} wrote'
111 )
112 or strings.icontains(body.plain.raw, 'Original Message')
113 )
114 and not regex.contains(body.current_thread.text,
115 'On (Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday).{0,50} wrote'
116 )
117 and not strings.icontains(body.current_thread.text,
118 'Original Message'
119 )
120 and not any(headers.hops, any(.fields, .name == "Resent-From"))
121 )
122 )
123 and strings.ilike(body.plain.raw,
124 "*picture*",
125 "*photo*",
126 "*image*",
127 "*sad news*",
128 "*sad announcement*",
129 "*sad update*",
130 "*pics*",
131 "*back memories*",
132 "*any memories*",
133 "*old memories*",
134 "*evoke memories*",
135 "*bittersweet memories*"
136 )
137 and not strings.istarts_with(body.plain.raw, "[cid:image")
138 and strings.icontains(subject.subject, sender.display_name)
139 )
140 or (
141 strings.icontains(subject.subject, sender.display_name)
142 and sender.email.domain.root_domain in $free_email_providers
143 and length(body.links) == 2
144 and length(filter(body.links, .display_text == "h")) == 1
145 and length(filter(body.links, .display_url.scheme == "ttp")) == 1
146 )
147 )
148 and length(body.links) < 5
149 and any(body.links,
150 (
151 (
152 network.whois(.href_url.domain).days_old < 30
153 or not network.whois(.href_url.domain).found
154 or network.whois(.href_url.domain).found is null
155 )
156 and .href_url.domain.root_domain != sender.email.domain.root_domain
157 )
158 or (
159 length(.display_text) == 1
160 and .href_url.domain.root_domain in ("facebook.com", "youtube.com")
161 )
162 or (
163 // random 5-6 character subdomain
164 regex.icontains(.href_url.domain.domain,
165 '^[a-z]{5,6}\.[a-z]{5,}\.[a-z]+'
166 )
167 // subdomain contains 3+ consecutive consonants
168 and regex.icontains(.href_url.domain.domain,
169 '^[a-z]*[b-df-hj-np-tv-z]{3,}[a-z]*\.'
170 )
171 and network.whois(.href_url.domain).days_old < 365
172 )
173 )
174 )
175 and (
176 (
177 (length(headers.references) > 0 or headers.in_reply_to is null)
178 and not (
179 (
180 strings.istarts_with(subject.subject, "RE:")
181 or strings.istarts_with(subject.subject, "R:")
182 or strings.istarts_with(subject.subject, "ODG:")
183 or strings.istarts_with(subject.subject, "答复:")
184 or strings.istarts_with(subject.subject, "AW:")
185 or strings.istarts_with(subject.subject, "TR:")
186 or strings.istarts_with(subject.subject, "FWD:")
187 or regex.imatch(subject.subject, '(\[[^\]]+\]\s?){0,3}(re|fwd?)\s?:')
188 )
189 )
190 )
191 or length(headers.references) == 0
192 )
193 // negate highly trusted sender domains unless they fail DMARC authentication
194 and (
195 (
196 sender.email.domain.root_domain in $high_trust_sender_root_domains
197 and not headers.auth_summary.dmarc.pass
198 )
199 or sender.email.domain.root_domain not in $high_trust_sender_root_domains
200 )
201attack_types:
202 - "Spam"
203tactics_and_techniques:
204 - "Evasion"
205 - "Social engineering"
206detection_methods:
207 - "Content analysis"
208 - "Sender analysis"
209 - "URL analysis"
210 - "Whois"
211id: "eb086f7d-3ad7-52cd-8e16-3ce08726b9ea"