Spam: Image as content with hidden HTML element
This has been observed in the delivery of emails containing account/membership expiration lure themes of popular online services or delivery notifications.
Sublime rule (View on GitHub)
1name: "Spam: Image as content with hidden HTML element"
2description: "This has been observed in the delivery of emails containing account/membership expiration lure themes of popular online services or delivery notifications."
3type: "rule"
4severity: "low"
5source: |
6 type.inbound
7 and (not profile.by_sender().solicited or sender.email.email == "")
8 // not high trust sender domains
9 and (
10 (
11 sender.email.domain.root_domain in $high_trust_sender_root_domains
12 and not headers.auth_summary.dmarc.pass
13 )
14 or sender.email.domain.root_domain not in $high_trust_sender_root_domains
15 )
16 and (
17 // find the template - a link that is a centered image
18 (
19 // at the start of a center
20 regex.contains(body.html.raw,
21 'center(?:\x22[^\>]*)?\>\s*<a href=\"https?:\/\/[^\x22]+\x22(?:\s[a-z]+=\x22[^\x22]+\x22)*>\s*[^\n]*?(?:\<img src=\x22[^\x22]+\x22>(?:<[a-z]+>\s*)*){1,}<\/a>'
22 )
23 // method two for the start of a center but includes an header line
24 or regex.contains(body.html.raw,
25 'center(?:\x22[^\>]*)?\>\s*<a href=\"https?:\/\/[^\x22]+\x22(?:\s[a-z]+=\x22[^\x22]+\x22)*>\s*[^\n]*?<h\d>[^\<]+<\/h\d+>\s*(?:\<img src=\x22[^\x22]+\x22>(?:<[a-z]+>\s*)*){1,}<\/a>(?:<[a-z]+>\s*)*<\/'
26 )
27 // method three for the start of a center, but includes words not in a header line
28 or regex.contains(body.html.raw,
29 'center(?:[\x22\x3b][^\>]*)?\>\s*<a href=\"https?:\/\/[^\x22]+\x22(?:\s[a-z]+=\x22[^\x22]+\x22)*>\s*[^\<][^\/][^\a]+\s*<\/a>\s*(?:<[a-z]+>\s*)*\s*<a href=\"https?:\/\/[^\x22]+\x22(?:\s[a-z]+=\x22[^\x22]+\x22)*>\s*(?:<img src=\x22[^\x22]+\x22>(?:<[a-z]+>\s*)*){1,}<\/a>'
30 )
31 // method four - the body starts with a centered div which is not visable, which contains a link and img within the link
32 or regex.contains(body.html.raw,
33 '<body(?:\x22[^\>]+)?\>\s*<center>\s*<(?:span|div)[^\>]*style=\x22[^\x22]*\s*(?:display\s*\x3a\s*none|visibility\s*\x3a\s*hidden)\x3b[^\x22]*\x22(?:\s*\w+=\"\w+\")*>[^\<]+</div>\s*<a[^\>]*href="[^\x22]+\x22(?:\s[a-z]+=\x22[^\x22]+\x22)*>\s*(?:<img src=\x22[^\x22]+\x22(?:\s[a-z]+=\x22[^\x22]+\x22)*>\s*){1,}\<\/a>'
34 )
35 // or at the end of the center
36 or regex.contains(body.html.raw,
37 '<a href=\"https?:\/\/[^\x22]+\x22(?:\s[a-z]+=\x22[^\x22]+\x22)*>\s*(?:\<img src=\x22[^\x22]+\x22>(?:<\/a>|(?:<[a-z]+>\s*))*){1,}<\/center>'
38 )
39 // at the start of the body
40 or regex.contains(body.html.raw,
41 'body(?:\x22[^\>]+)?\>\s*<a href=\"https?:\/\/[^\x22]+\x22(?:\s[a-z]+=\x22[^\x22]+\x22)*>\s*[^\n]*?(?:\<img src=\x22[^\x22]+\x22>(?:<[a-z]+>\s*)*){1,}<\/a>'
42 )
43 // a href with background url which is centered very early on in the body.html.raw
44 or regex.contains(body.html.raw,
45 '^(?:<[^\>]+>\s*){0,6}<a[^\>]*href=\x22[^\>]+\>\s*<(?:div|span)[^\>]*style=\x22[^\x22]*background:url\([^\)]+\)[^\x22]*center;[^\>]*\>\s*<\/(?:div|span)>\s*</a>'
46 )
47 or regex.contains(body.html.raw,
48 '<(?:div|span)[^\>]*style="[^\"]*center;[^\"]*\"[^\>]*>\s*<a href=\"[^\>]+\>(?:.|\W)*<img src="[^\"]+">\s*</a>\s*<br>\s*<(?:div|span)[^\>]*style="[^\"]*display\s*:\s*none;[^\"]*\">'
49 )
50 )
51 and (
52 // where there is a span/div that is hidden with either  \x3b\x200c? or underscores repeating multiple times OR followed by a new metatag
53 regex.contains(body.html.raw,
54 '<(?:span|div)[^\>]*style=\x22[^\x22]*\s*(?:display\s*\x3a\s*none|visibility\s*\x3a\s*hidden)\x3b[^\x22]*\x22(?:\s*\w+=\"\w+\")*>\s*(?:<\/?[^\>]+>\s*)*(?:(?:_|[\pCc\pCf\pCs]* \x3b\s*[\pCc\pCf\pCs]*){3,}|\s+\<meta |\s+\<center )'
55 )
56 or
57 // a custom css value is used to hide the body
58 // unable to use capture groups to capture the custom html tag to apply the hidden style
59 // instead we use [A-Za-z] to catch a single char.
60 regex.contains(body.html.raw,
61 'style\s+[^\>]*type\s*\x3d\s*\"text/css\"[^\>]*>\s*[^\<]*[A-Za-z]\s*\{[^\}]*(?:display\s*\x3a\s*none|visibility\s*\x3a\s*hidden)[^\}]*\}[^\<]+\</style><[A-Za-z]>'
62 )
63 or
64 // the hidden span/div is before the body/meta
65 regex.contains(body.html.raw,
66 '<(?:span|div)[^\>]*style=\x22[^\x22]*\s*(?:display\s*\x3a\s*none|visibility\s*\x3a\s*hidden)\x3b[^\x22]*\x22(?:\s*\w+=\"\w+\")*>\s*\<(?:body|meta|head|(?:<?div[^\>]+\>\s*(?:[^\<]*|<[a-z]+>\s*)<\/div>\s*){2,})'
67 )
68 // the length of the inner text is greather than or equal to 10x more than the display text
69 // this attempts to generically cover multiple methods of hiding text
70 or (
71 length(body.html.inner_text) > 0
72 and (
73 length(body.html.inner_text) >= (length(body.html.display_text) * 10)
74 )
75 )
76 // used to push down or move content out of view
77 or (
78 sum([
79 regex.count(body.html.display_text, '[\r\n].?[\r\n]'),
80 regex.icount(body.html.raw, '(?:<br>(?:[^\<]|\s){0,2}){3}'),
81 regex.icount(body.html.raw, '(?:<blockquote>(?:[^\<]|\s){0,2}){3}'),
82 regex.icount(body.html.raw, '<div>(?:.|\s){0,2}<\/div>'),
83 regex.icount(body.html.raw, '<span>(?:.|\s){0,2}<\/span>'),
84 ]
85 ) > 40
86 )
87 )
88 )
89attack_types:
90 - "Spam"
91tactics_and_techniques:
92 - "Evasion"
93 - "Image as content"
94detection_methods:
95 - "Content analysis"
96 - "HTML analysis"
97 - "Sender analysis"
98id: "5de8861f-a343-521f-ac8c-b4b91e389a6e"