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