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