Spam: Commonly observed formatting of unauthorized free giveaways

Detects commonly observed formatting of unauthorized giveaways, free tools, and products by multiple different brands.

Sublime rule (View on GitHub)

  1name: "Spam: Commonly observed formatting of unauthorized free giveaways"
  2description: "Detects commonly observed formatting of unauthorized giveaways, free tools, and products by multiple different brands."
  3type: "rule"
  4severity: "low"
  5source: |
  6  type.inbound
  7  and (
  8    (
  9      any(html.xpath(body.html, "//div[contains(@style, 'BACKGROUND: URL')]").nodes,
 10          .raw is not null
 11      )
 12    )
 13    or (
 14      any(body.links,
 15          any([
 16                "blob.core.windows.net",
 17                "click.email.formula1.com",
 18                "firmy-praha.eu"
 19              ],
 20              ..href_url.domain.domain == .
 21              or strings.ends_with(..href_url.domain.domain, .)
 22          )
 23      )
 24    )
 25  )
 26  and (
 27    (
 28      // subject has # plus random characters only
 29      regex.icontains(subject.base, "#[a-z0-9]{5,}?")
 30      // plus one of these
 31      and (
 32        // display name has a # + random characters only
 33        regex.icontains(sender.display_name, "#[a-z0-9]{5,}?")
 34        // subject starts with a period (yes, both subject cases should be true)
 35        or strings.starts_with(subject.base, ".")
 36        // Display name contains at least 2 emojis
 37        or length(distinct(map(regex.extract(sender.display_name,
 38                                             '(?P<emoji>[\x{1F300}-\x{1F5FF}\x{1F600}-\x{1F64F}\x{1F680}-\x{1F6FF}\x{1F700}-\x{1F77F}\x{1F780}-\x{1F7FF}\x{1F900}-\x{1F9FF}\x{2600}-\x{26FF}\x{2700}-\x{27BF}\x{2300}-\x{23FF}])'
 39                               ),
 40                               .full_match
 41                           )
 42                  )
 43        ) >= 2
 44      )
 45    )
 46    or (
 47      // Subject contains at least 2 emojias
 48      length(distinct(map(regex.extract(subject.base,
 49                                        '(?P<emoji>[\x{1F300}-\x{1F5FF}\x{1F600}-\x{1F64F}\x{1F680}-\x{1F6FF}\x{1F700}-\x{1F77F}\x{1F780}-\x{1F7FF}\x{1F900}-\x{1F9FF}\x{2600}-\x{26FF}\x{2700}-\x{27BF}\x{2300}-\x{23FF}])'
 50                          ),
 51                          .full_match
 52                      )
 53             )
 54      ) >= 2
 55    )
 56    or 
 57    // another variant with different strings that have numbers but the same pattern is in both subject and displayname
 58    (
 59      // subject has # plus random characters & numbers
 60      regex.icontains(subject.base, "#[1-9a-z]+")
 61      // plus one of these
 62      and (
 63        regex.icontains(sender.display_name, "#[1-9a-z]+")
 64        or strings.icontains(sender.display_name, "rewards")
 65      )
 66    )
 67    or (
 68      // or prornotions (promotions) once confusables are stripped in subject
 69      strings.icontains(strings.replace_confusables(subject.base), "prornotions")
 70      // and rewards in display name
 71      and strings.icontains(sender.display_name, "rewards")
 72    )
 73    or (
 74      // subject has * plus 4 random characters and numbers *
 75      regex.icontains(subject.base, '\*[1-9a-z]{4,}\*')
 76      // same with the display name
 77      and regex.icontains(sender.display_name, '\*[1-9a-z]{4,}\*')
 78    )
 79    or (
 80      // subject and display name has two *
 81      strings.count(subject.base, "*") == 2
 82      and strings.count(sender.display_name, "*") == 2
 83    )
 84    or (
 85      // subject has string of random characters and numbers
 86      // checking if string has 1 uppercase, 1 lowercase and 1 number
 87      any(regex.extract(subject.base, '(?:-{1,2}|\s)([a-zA-Z0-9]{11,})'),
 88          regex.contains(.full_match, '[A-Z]')
 89          and regex.contains(.full_match, '[a-z]')
 90          and regex.contains(.full_match, '[0-9]')
 91          // some matches are legit but they are 35+ characters
 92          and length(.full_match) <= 30
 93      )
 94      // negating support thread email subjects containg multiple : in their IDs
 95      and not regex.count(subject.base, ':') > 5
 96    )
 97  )  
 98
 99attack_types:
100  - "Spam"
101tactics_and_techniques:
102  - "Impersonation: Brand"
103  - "Social engineering"
104detection_methods:
105  - "Content analysis"
106  - "HTML analysis"
107  - "Sender analysis"
108  - "URL analysis"
109id: "8bc49fa3-5fdc-5eca-a9cd-f9f5ecf04a7c"
to-top