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        )
 19        and strings.ilike(subject.subject,
 20                          "*picture*",
 21                          "*photo*",
 22                          "*image*",
 23                          "*sad news*",
 24                          "*sad announcement*",
 25                          "*new pics*"
 26        )
 27      )
 28      or (
 29        (
 30          (
 31            length(body.html.display_text) < 500
 32            and length(body.current_thread.text) == 0
 33          )
 34          and strings.ilike(body.html.display_text,
 35                            "*picture*",
 36                            "*photo*",
 37                            "*image*",
 38                            "*sad news*",
 39                            "*sad announcement*",
 40                            "*new pics*"
 41          )
 42        )
 43        or (
 44          (length(body.plain.raw) < 500 and length(body.current_thread.text) == 0)
 45          and strings.ilike(body.plain.raw,
 46                            "*picture*",
 47                            "*photo*",
 48                            "*image*",
 49                            "*sad news*",
 50                            "*sad announcement*",
 51                            "*new pics*"
 52          )
 53          and not strings.icontains(body.plain.raw, "[cid:image")
 54        )
 55        or (
 56          length(body.current_thread.text) < 500
 57          and strings.ilike(body.current_thread.text,
 58                            "*picture*",
 59                            "*photo*",
 60                            "*image*",
 61                            "*sad news*",
 62                            "*sad announcement*",
 63                            "*new pics*"
 64          )
 65        )
 66      )
 67      or (
 68        body.plain.raw is not null
 69        and body.html.display_text is null
 70        and (
 71          length(body.current_thread.text) == 0
 72          or (
 73            length(body.current_thread.text) < 500
 74            // fake forward indicator in the plain text body
 75            and (
 76              regex.contains(body.plain.raw,
 77                             'On (Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday).{0,50} wrote'
 78              )
 79              or strings.icontains(body.plain.raw, 'Original Message')
 80            )
 81            and not regex.contains(body.current_thread.text,
 82                                   'On (Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday).{0,50} wrote'
 83            )
 84            and not strings.icontains(body.current_thread.text,
 85                                      'Original Message'
 86            )
 87            and not any(headers.hops, any(.fields, .name == "Resent-From"))
 88          )
 89        )
 90        and strings.ilike(body.plain.raw,
 91                          "*picture*",
 92                          "*photo*",
 93                          "*image*",
 94                          "*sad news*",
 95                          "*sad announcement*",
 96                          "*pics*"
 97        )
 98        and not strings.istarts_with(body.plain.raw, "[cid:image")
 99        and strings.icontains(subject.subject, sender.display_name)
100      )
101      or (
102        strings.icontains(subject.subject, sender.display_name)
103        and sender.email.domain.root_domain in $free_email_providers
104        and length(body.links) == 2
105        and length(filter(body.links, .display_text == "h")) == 1
106        and length(filter(body.links, .display_url.scheme == "ttp")) == 1
107      )
108    )
109    and length(body.links) < 5
110    and any(body.links,
111            (
112              (
113                network.whois(.href_url.domain).days_old < 30
114                or not network.whois(.href_url.domain).found
115                or network.whois(.href_url.domain).found is null
116              )
117              and .href_url.domain.root_domain != sender.email.domain.root_domain
118            )
119            or (
120              length(.display_text) == 1
121              and .href_url.domain.root_domain in ("facebook.com", "youtube.com")
122            )
123    )
124  )
125  and (
126    (
127      (
128        length(headers.references) > 0
129        or not any(headers.hops,
130                   any(.fields, strings.ilike(.name, "In-Reply-To"))
131        )
132      )
133      and not (
134        (
135          strings.istarts_with(subject.subject, "RE:")
136          or strings.istarts_with(subject.subject, "R:")
137          or strings.istarts_with(subject.subject, "ODG:")
138          or strings.istarts_with(subject.subject, "答复:")
139          or strings.istarts_with(subject.subject, "AW:")
140          or strings.istarts_with(subject.subject, "TR:")
141          or strings.istarts_with(subject.subject, "FWD:")
142          or regex.imatch(subject.subject, '(\[[^\]]+\]\s?){0,3}(re|fwd?)\s?:')
143        )
144      )
145    )
146    or length(headers.references) == 0
147  )  
148
149attack_types:
150  - "Spam"
151tactics_and_techniques:
152  - "Evasion"
153  - "Social engineering"
154detection_methods:
155  - "Content analysis"
156  - "Sender analysis"
157  - "URL analysis"
158  - "Whois"
159id: "eb086f7d-3ad7-52cd-8e16-3ce08726b9ea"
to-top