1+ name : " Attachment: QR code with recipient targeting and special characters"
2+ description : " Detects messages with QR code in attachments containing special characters in the path that include the recipient's email address in either the URL path or fragment, potentially encoded in base64. The URLs have a simple path structure and may end with suspicious patterns."
3+ type : " rule"
4+ severity : " high"
5+ source : |
6+ type.inbound
7+ and length(recipients.to) == 1
8+ and recipients.to[0].email.domain.valid
9+ and any(attachments,
10+ (
11+ // Office documents
12+ .file_extension in $file_extensions_macros
13+ and any(file.explode(.),
14+ .scan.qr.type == "url"
15+ // QR code URL contains recipient's email (targeting indicator)
16+ and any(recipients.to,
17+ .email.domain.valid
18+ and (
19+ // Plaintext email address in URL
20+ strings.icontains(..scan.qr.url.url, .email.email)
21+ // OR base64 encoded email address
22+ or any(strings.scan_base64(..scan.qr.url.url,
23+ format="url",
24+ ignore_padding=true
25+ ),
26+ strings.icontains(., ..email.email)
27+ )
28+ )
29+ )
30+ // a single path
31+ and strings.count(.scan.qr.url.path, '/') == 2
32+ and (
33+ (
34+ (
35+ strings.contains(.scan.qr.url.path, '/$')
36+ or strings.contains(.scan.qr.url.path, '/*')
37+ or strings.contains(.scan.qr.url.path, '/#')
38+ )
39+ // subdomain should contain num{3}alpha or alphanum{3}
40+ and regex.icontains(.scan.qr.url.domain.subdomain,
41+ '^(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)$'
42+ )
43+ // url path should contain num{3}alpha or alphanum{3}
44+ and regex.icontains(.scan.qr.url.path,
45+ '\/(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)\/'
46+ )
47+ )
48+ or (
49+ // special char in the path
50+ (
51+ strings.contains(.scan.qr.url.path, '!')
52+ or strings.contains(.scan.qr.url.path, '@')
53+ )
54+ and (
55+ strings.contains(.scan.qr.url.path, '/$')
56+ or strings.contains(.scan.qr.url.path, '/*')
57+ or strings.contains(.scan.qr.url.path, '/#')
58+ // hex dollar sign
59+ or strings.icontains(.scan.qr.url.path, '%24')
60+ // hex star
61+ or strings.icontains(.scan.qr.url.path, '%2A')
62+ // hex pound
63+ or strings.icontains(.scan.qr.url.path, '%23')
64+ )
65+ // ensure expected ordering
66+ and regex.icontains(.scan.qr.url.url,
67+ '[!@].*(?:[$*]|%2[A43])'
68+ )
69+ )
70+ )
71+ )
72+ )
73+ or (
74+ // Email Attachments
75+ any(file.parse_eml(.).attachments,
76+ any(file.explode(.),
77+ .scan.qr.type == "url"
78+ // QR code URL contains recipient's email (targeting indicator)
79+ and any(recipients.to,
80+ .email.domain.valid
81+ and (
82+ // Plaintext email address in URL
83+ strings.icontains(..scan.qr.url.url, .email.email)
84+ // OR base64 encoded email address
85+ or any(strings.scan_base64(..scan.qr.url.url,
86+ format="url",
87+ ignore_padding=true
88+ ),
89+ strings.icontains(., ..email.email)
90+ )
91+ )
92+ )
93+ // a single path
94+ and strings.count(.scan.qr.url.path, '/') == 2
95+ and (
96+ (
97+ (
98+ strings.contains(.scan.qr.url.path, '/$')
99+ or strings.contains(.scan.qr.url.path, '/*')
100+ or strings.contains(.scan.qr.url.path, '/#')
101+ )
102+ // subdomain should contain num{3}alpha or alphanum{3}
103+ and regex.icontains(.scan.qr.url.domain.subdomain,
104+ '^(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)$'
105+ )
106+ // url path should contain num{3}alpha or alphanum{3}
107+ and regex.icontains(.scan.qr.url.path,
108+ '\/(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)\/'
109+ )
110+ )
111+ or (
112+ // special char in the path
113+ (
114+ strings.contains(.scan.qr.url.path, '!')
115+ or strings.contains(.scan.qr.url.path, '@')
116+ )
117+ and (
118+ strings.contains(.scan.qr.url.path, '/$')
119+ or strings.contains(.scan.qr.url.path, '/*')
120+ or strings.contains(.scan.qr.url.path, '/#')
121+ // hex dollar sign
122+ or strings.icontains(.scan.qr.url.path, '%24')
123+ // hex star
124+ or strings.icontains(.scan.qr.url.path, '%2A')
125+ // hex pound
126+ or strings.icontains(.scan.qr.url.path, '%23')
127+ )
128+ // ensure expected ordering
129+ and regex.icontains(.scan.qr.url.url,
130+ '[!@].*(?:[$*]|%2[A43])'
131+ )
132+ )
133+ )
134+ )
135+ )
136+ or (
137+ // pdf or images
138+ (
139+ .file_type == "pdf" or .file_type in $file_types_images
140+ )
141+ //
142+ // This rule makes use of a beta feature and is subject to change without notice
143+ // using the beta feature in custom rules is not suggested until it has been formally released
144+ //
145+ and any(beta.scan_qr(.).items,
146+ .type is not null
147+ // a single path
148+ and strings.count(.url.path, '/') == 2
149+ and (
150+ (
151+ (
152+ strings.contains(.url.path, '/$')
153+ or strings.contains(.url.path, '/*')
154+ or strings.contains(.url.path, '/#')
155+ )
156+ // subdomain should contain num{3}alpha or alphanum{3}
157+ and regex.icontains(.url.domain.subdomain,
158+ '^(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)$'
159+ )
160+ // url path should contain num{3}alpha or alphanum{3}
161+ and regex.icontains(.url.path,
162+ '\/(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)\/'
163+ )
164+ )
165+ or (
166+ // special char in the path
167+ (
168+ strings.contains(.url.path, '!')
169+ or strings.contains(.url.path, '@')
170+ )
171+ and (
172+ strings.contains(.url.path, '/$')
173+ or strings.contains(.url.path, '/*')
174+ or strings.contains(.url.path, '/#')
175+ // hex dollar sign
176+ or strings.icontains(.url.path, '%24')
177+ // hex star
178+ or strings.icontains(.url.path, '%2A')
179+ // hex pound
180+ or strings.icontains(.url.path, '%23')
181+ )
182+ // ensure expected ordering
183+ and regex.icontains(.url.url, '[!@].*(?:[$*]|%2[A43])')
184+ )
185+ )
186+ )
187+ )
188+ )
189+ )
190+ attack_types :
191+ - " Credential Phishing"
192+ tactics_and_techniques :
193+ - " QR code"
194+ - " Social engineering"
195+ - " Evasion"
196+ detection_methods :
197+ - " File analysis"
198+ - " QR code analysis"
199+ - " URL analysis"
200+ - " Computer Vision"
201+ id : " a4ebed09-6966-5b4c-8449-f066d65b4c99"
202+ og_id : " fc9e1c09-4691-5cde-94d1-ccd953f1b63a"
203+ testing_pr : 3998
204+ testing_sha : e2d76195bf62085228e261fec1c2d676d80e5fdd
0 commit comments