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"
to-top