QR Code with suspicious indicators
This rule flags messages with QR codes in attachments when there are three or fewer attachments. If no attachments are present, the rule captures a screenshot of the message for analysis. Additional triggers include: sender's name containing the recipient's SLD, recipient's email mentioned in the body, an empty message body, a suspicious subject, or undisclosed recipients.
Sublime rule (View on GitHub)
1name: "QR Code with suspicious indicators"
2description: |
3 This rule flags messages with QR codes in attachments when there are three or fewer attachments. If no attachments are present, the rule captures a screenshot of the message for analysis. Additional triggers include: sender's name containing the recipient's SLD, recipient's email mentioned in the body, an empty message body, a suspicious subject, or undisclosed recipients.
4type: "rule"
5severity: "high"
6source: |
7 type.inbound
8 and (
9 (
10 length(attachments) <= 3
11 or (
12 any(attachments, length(ml.logo_detect(.).brands) > 0)
13 and length(attachments) <= 10
14 )
15 )
16 and (
17 any(attachments,
18 .file_type in $file_types_images
19 and any(file.explode(.),
20 .scan.qr.type is not null
21 and regex.contains(.scan.qr.data, '\.')
22 // exclude images taken with mobile cameras and screenshots from android
23 and not any(.scan.exiftool.fields,
24 .key == "Model"
25 or (
26 .key == "Software"
27 and strings.starts_with(.value, "Android")
28 )
29 )
30 // exclude images taken with mobile cameras and screenshots from Apple
31 and not any(.scan.exiftool.fields,
32 .key == "DeviceManufacturer"
33 and .value == "Apple Computer Inc."
34 )
35 and not (
36 .scan.exiftool.image_height > 3000
37 or .scan.exiftool.image_width > 3000
38 )
39 )
40 )
41 or (
42 length(attachments) == 0
43 and any(file.explode(beta.message_screenshot()),
44 .scan.exiftool.image_height < 2000
45 and .scan.exiftool.image_width < 2000
46 and .scan.qr.type is not null
47 and regex.contains(.scan.qr.data, '\.')
48 )
49 )
50 )
51 and (
52 any(recipients.to,
53 strings.icontains(sender.display_name, .email.domain.sld)
54 )
55 or length(body.current_thread.text) is null
56 or body.current_thread.text == ""
57 or regex.contains(subject.subject,
58 "(Authenticat(e|or|ion)|2fa|Multi.Factor|(qr|bar).code|action.require|alert|Att(n|ention):)"
59 )
60 or (any(recipients.to, strings.icontains(subject.subject, .display_name)))
61 or (
62 regex.icontains(subject.subject,
63 "termination.*notice",
64 "38417",
65 ":completed",
66 "[il1]{2}mit.*ma[il1]{2} ?bo?x",
67 "[il][il][il]egai[ -]",
68 "[li][li][li]ega[li] attempt",
69 "[ng]-?[io]n .*block",
70 "[ng]-?[io]n .*cancel",
71 "[ng]-?[io]n .*deactiv",
72 "[ng]-?[io]n .*disabl",
73 "action.*required",
74 "abandon.*package",
75 "about.your.account",
76 "acc(ou)?n?t (is )?on ho[li]d",
77 "acc(ou)?n?t.*terminat",
78 "acc(oun)?t.*[il1]{2}mitation",
79 "access.*limitation",
80 "account (will be )?block",
81 "account.*de-?activat",
82 "account.*locked",
83 "account.*re-verification",
84 "account.*security",
85 "account.*suspension",
86 "account.has.been",
87 "account.has.expired",
88 "account.will.be.blocked",
89 "account v[il]o[li]at",
90 "activity.*acc(oun)?t",
91 "almost.full",
92 "app[li]e.[il]d",
93 "authenticate.*account",
94 "been.*suspend",
95 "clos.*of.*account.*processed",
96 "confirm.your.account",
97 "courier.*able",
98 "deactivation.*in.*progress",
99 "delivery.*attempt.*failed",
100 "document.received",
101 "documented.*shared.*with.*you",
102 "dropbox.*document",
103 "e-?ma[il1]+ .{010}suspen",
104 "e-?ma[il1]{1} user",
105 "e-?ma[il1]{2} acc",
106 "e-?ma[il1]{2}.*up.?grade",
107 "e.?ma[il1]{2}.*server",
108 "e.?ma[il1]{2}.*suspend",
109 "email.update",
110 "faxed you",
111 "fraud(ulent)?.*charge",
112 "from.helpdesk",
113 "fu[il1]{2}.*ma[il1]+[ -]?box",
114 "has.been.*suspended",
115 "has.been.limited",
116 "have.locked",
117 "he[li]p ?desk upgrade",
118 "heipdesk",
119 "i[il]iega[il]",
120 "ii[il]ega[il]",
121 "incoming e?mail",
122 "incoming.*fax",
123 "lock.*security",
124 "ma[il1]{1}[ -]?box.*quo",
125 "ma[il1]{2}[ -]?box.*fu[il1]",
126 "ma[il1]{2}box.*[il1]{2}mit",
127 "ma[il1]{2}box stor",
128 "mail on.?hold",
129 "mail.*box.*migration",
130 "mail.*de-?activat",
131 "mail.update.required",
132 "mails.*pending",
133 "messages.*pending",
134 "missed.*shipping.*notification",
135 "missed.shipment.notification",
136 "must.update.your.account",
137 "new [sl][io]g?[nig][ -]?in from",
138 "new voice ?-?mail",
139 "notifications.*pending",
140 "office.*3.*6.*5.*suspend",
141 "office365",
142 "on google docs with you",
143 "online doc",
144 "password.*compromised",
145 "periodic maintenance",
146 "potential(ly)? unauthorized",
147 "refund not approved",
148 "report",
149 "revised.*policy",
150 "scam",
151 "scanned.?invoice",
152 "secured?.update",
153 "security breach",
154 "securlty",
155 "signed.*delivery",
156 "status of your .{314}? ?delivery",
157 "susp[il1]+c[il1]+ous.*act[il1]+v[il1]+ty",
158 "suspicious.*sign.*[io]n",
159 "suspicious.activit",
160 "temporar(il)?y deactivate",
161 "temporar[il1]{2}y disab[li]ed",
162 "temporarily.*lock",
163 "un-?usua[li].activity",
164 "unable.*deliver",
165 "unauthorized.*activit",
166 "unauthorized.device",
167 "undelivered message",
168 "unread.*doc",
169 "unusual.activity",
170 "upgrade.*account",
171 "upgrade.notice",
172 "urgent message",
173 "urgent.verification",
174 "v[il1]o[li1]at[il1]on security",
175 "va[il1]{1}date.*ma[il1]{2}[ -]?box",
176 "verification ?-?require",
177 "verification( )?-?need",
178 "verify.your?.account",
179 "web ?-?ma[il1]{2}",
180 "web[ -]?ma[il1]{2}",
181 "will.be.suspended",
182 "your (customer )?account .as",
183 "your.office.365",
184 "your.online.access"
185 )
186 or any($suspicious_subjects, strings.icontains(subject.subject, .))
187 or regex.icontains(sender.display_name,
188 "Admin",
189 "Administrator",
190 "Alert",
191 "Assistant",
192 "Billing",
193 "Benefits",
194 "Bonus",
195 "CEO",
196 "CFO",
197 "CIO",
198 "CTO",
199 "Chairman",
200 "Claim",
201 "Confirm",
202 "Critical",
203 "Customer Service",
204 "Deal",
205 "Discount",
206 "Director",
207 "Exclusive",
208 "Executive",
209 "Fax",
210 "Free",
211 "Gift",
212 "/bHR/b",
213 "Helpdesk",
214 "Human Resources",
215 "Immediate",
216 "Important",
217 "Info",
218 "Information",
219 "Invoice",
220 '\bIT\b',
221 "Legal",
222 "Lottery",
223 "Management",
224 "Manager",
225 "Member Services",
226 "Notification",
227 "Offer",
228 "Operations",
229 "Order",
230 "Partner",
231 "Payment",
232 "Payroll",
233 "President",
234 "Premium",
235 "Prize",
236 "Receipt",
237 "Refund",
238 "Registrar",
239 "Required",
240 "Reward",
241 "Sales",
242 "Secretary",
243 "Security",
244 "Service",
245 "Signature",
246 "Storage",
247 "Support",
248 "Sweepstakes",
249 "System",
250 "Tax",
251 "Tech Support",
252 "Update",
253 "Upgrade",
254 "Urgent",
255 "Validate",
256 "Verify",
257 "VIP",
258 "Webmaster",
259 "Winner",
260 )
261 )
262 or (
263 (
264 length(recipients.to) == 0
265 or all(recipients.to, .display_name == "Undisclosed recipients")
266 )
267 and length(recipients.cc) == 0
268 and length(recipients.bcc) == 0
269 )
270 or any(file.explode(beta.message_screenshot()),
271 (
272 .scan.qr.url.domain.tld in $suspicious_tlds
273 and .scan.qr.url.domain.root_domain != "app.link"
274 )
275 or
276 // linkanalysis phishing disposition
277 any([ml.link_analysis(.scan.qr.url)],
278 .credphish.disposition == "phishing"
279 )
280 )
281 or any(attachments,
282 .file_type in $file_types_images
283 and any(file.explode(.),
284 (
285 .scan.qr.url.domain.tld in $suspicious_tlds
286 and .scan.qr.url.domain.root_domain != "app.link"
287 )
288 and .scan.qr.url.domain.root_domain not in $org_domains
289 )
290 )
291 or sender.email.domain.tld in $suspicious_tlds
292 )
293 )
294
295 // sender profile is new or outlier
296 and (
297 (
298 profile.by_sender().prevalence in ("new", "outlier")
299 and not profile.by_sender().solicited
300 )
301 or (
302 profile.by_sender().any_messages_malicious_or_spam
303 and not profile.by_sender().any_false_positives
304 )
305 )
306
307 // negate highly trusted sender domains unless they fail DMARC authentication
308 and (
309 (
310 sender.email.domain.root_domain in $high_trust_sender_root_domains
311 and not headers.auth_summary.dmarc.pass
312 )
313 or sender.email.domain.root_domain not in $high_trust_sender_root_domains
314 )
315
316attack_types:
317 - "Credential Phishing"
318tactics_and_techniques:
319 - "QR code"
320 - "Social engineering"
321detection_methods:
322 - "Content analysis"
323 - "Header analysis"
324 - "Computer Vision"
325 - "Natural Language Understanding"
326 - "QR code analysis"
327 - "Sender analysis"
328 - "URL analysis"
329id: "04f5c34f-6518-512d-916c-4c2c2827c6a9"