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