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 (
 27          strings.ilike(subject.subject,
 28                        "*picture*",
 29                        "*photo*",
 30                        "*image*",
 31                        "*sad news*",
 32                        "*sad announcement*",
 33                        "*sad update*",
 34                        "*new pics*",
 35                        "*Reunion*",
 36                        "*planing*",
 37                        "*back memories*",
 38                        "*any memories*",
 39                        "*old memories*",
 40                        "*evoke memories*",
 41                        "*bittersweet memories*"
 42          )
 43          or regex.icontains(subject.base, 'pics?\s*\(\d{1,2}\)')
 44        )
 45      )
 46      or (
 47        (
 48          (
 49            length(body.html.display_text) < 500
 50            and length(body.current_thread.text) == 0
 51          )
 52          and (
 53            strings.ilike(body.html.display_text,
 54                          "*picture*",
 55                          "*photo*",
 56                          "*image*",
 57                          "*sad news*",
 58                          "*sad announcement*",
 59                          "*sad update*",
 60                          "*new pics*",
 61                          "*back memories*",
 62                          "*any memories*",
 63                          "*old memories*",
 64                          "*evoke memories*",
 65                          "*bittersweet memories*",
 66                          "*ring a bell*"
 67            )
 68            or regex.icontains(body.html.display_text,
 69                               '[.!?]\W{0,3}[—–-]\s*[a-z]+'
 70            )
 71          )
 72        )
 73        or (
 74          (length(body.plain.raw) < 500 and length(body.current_thread.text) == 0)
 75          and strings.ilike(body.plain.raw,
 76                            "*picture*",
 77                            "*photo*",
 78                            "*image*",
 79                            "*sad news*",
 80                            "*sad announcement*",
 81                            "*sad update*",
 82                            "*new pics*",
 83                            "*back memories*",
 84                            "*any memories*",
 85                            "*old memories*",
 86                            "*evoke memories*",
 87                            "*bittersweet memories*",
 88                            "*ring a bell*"
 89          )
 90          and not strings.icontains(body.plain.raw, "[cid:image")
 91        )
 92        or (
 93          length(body.current_thread.text) < 500
 94          and (
 95            strings.ilike(body.current_thread.text,
 96                          "*picture*",
 97                          "*photo*",
 98                          "*image*",
 99                          "*sad news*",
100                          "*sad announcement*",
101                          "*sad update*",
102                          "*new pics*",
103                          "*back memories*",
104                          "*any memories*",
105                          "*old memories*",
106                          "*evoke memories*",
107                          "*bittersweet memories*",
108                          "*ring a bell*",
109                          "*way earlier*",
110                          "*emailed it*"
111            )
112            or regex.icontains(body.current_thread.text,
113                               '\bpics?\b.{0,40}https?://[a-z]+\.[a-z]+\.com'
114            )
115          )
116        )
117      )
118      or (
119        body.plain.raw is not null
120        and body.html.display_text is null
121        and (
122          // fake forward indicator in the plain text body
123          (
124            regex.contains(body.plain.raw,
125                           'On (Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday).{0,50} wrote'
126            )
127            or strings.icontains(body.plain.raw, 'Original Message')
128          )
129          and not regex.contains(body.current_thread.text,
130                                 'On (Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday).{0,50} wrote'
131          )
132          and not strings.icontains(body.current_thread.text, 'Original Message')
133          and not any(headers.hops, any(.fields, .name == "Resent-From"))
134        )
135        and (
136          (
137            strings.ilike(body.plain.raw,
138                          "*picture*",
139                          "*photo*",
140                          "*image*",
141                          "*sad news*",
142                          "*sad announcement*",
143                          "*sad update*",
144                          "*pics*",
145                          "*back memories*",
146                          "*any memories*",
147                          "*old memories*",
148                          "*evoke memories*",
149                          "*bittersweet memories*",
150                          "*ring a bell*"
151            )
152            and not strings.istarts_with(body.plain.raw, "[cid:image")
153          )
154          or regex.icontains(body.plain.raw, '[.!?]\W{0,3}[—–-]\s*[a-z]+')
155        )
156      )
157      or (
158        strings.icontains(subject.subject, sender.display_name)
159        and sender.email.domain.root_domain in $free_email_providers
160        and length(body.links) == 2
161        and length(filter(body.links, .display_text == "h")) == 1
162        and length(filter(body.links, .display_url.scheme == "ttp")) == 1
163      )
164    )
165    and length(body.links) < 5
166    and any(body.links,
167            (
168              (
169                network.whois(.href_url.domain).days_old < 30
170                or network.whois(.display_url.domain).days_old < 30
171                or not network.whois(.href_url.domain).found
172                or network.whois(.href_url.domain).found is null
173              )
174              and .href_url.domain.root_domain != sender.email.domain.root_domain
175            )
176            or (
177              length(.display_text) == 1
178              and .href_url.domain.root_domain in ("facebook.com", "youtube.com")
179            )
180            or (
181              // random 5-6 character subdomain
182              regex.imatch(.href_url.domain.domain,
183                           '[a-z]{5,6}\.[a-z]{5,}\.[a-z]+.*'
184              )
185              // subdomain contains 3+ consecutive consonants
186              and regex.imatch(.href_url.domain.domain,
187                               '[a-z]*[b-df-hj-np-tv-z]{3,}[a-z]*\..*'
188              )
189              and network.whois(.href_url.domain).days_old < 365
190            )
191    )
192  )
193  and (
194    (
195      (length(headers.references) > 0 or headers.in_reply_to is null)
196      and not (
197        (
198          strings.istarts_with(subject.subject, "RE:")
199          or strings.istarts_with(subject.subject, "R:")
200          or strings.istarts_with(subject.subject, "ODG:")
201          or strings.istarts_with(subject.subject, "答复:")
202          or strings.istarts_with(subject.subject, "AW:")
203          or strings.istarts_with(subject.subject, "TR:")
204          or strings.istarts_with(subject.subject, "FWD:")
205          or regex.imatch(subject.subject, '(\[[^\]]+\]\s?){0,3}(re|fwd?)\s?:')
206        )
207      )
208    )
209    or length(headers.references) == 0
210  )
211  // negate highly trusted sender domains unless they fail DMARC authentication
212  and not (
213    sender.email.domain.root_domain in $high_trust_sender_root_domains
214    and coalesce(headers.auth_summary.dmarc.pass, false)
215  )  
216attack_types:
217  - "Spam"
218tactics_and_techniques:
219  - "Evasion"
220  - "Social engineering"
221detection_methods:
222  - "Content analysis"
223  - "Sender analysis"
224  - "URL analysis"
225  - "Whois"
226id: "eb086f7d-3ad7-52cd-8e16-3ce08726b9ea"
to-top