Attachment: QR code with credential phishing indicators

Detects messages with between 1-3 attachments containing a QR code with suspicious credential theft indicators, such as: LinkAnalysis credential phishing conclusion, decoded QR code url traverses suspicious infrastructure, the final destination is in URLhaus, decoded URL downloads a zip or executable, leverages URL shorteners, known QR abused openredirects, and more.

Sublime rule (View on GitHub)

  1name: "Attachment: QR code with credential phishing indicators"
  2description: |
  3    Detects messages with between 1-3 attachments containing a QR code with suspicious credential theft indicators, such as: LinkAnalysis credential phishing conclusion, decoded QR code url traverses suspicious infrastructure, the final destination is in URLhaus, decoded  URL downloads a zip or executable, leverages URL shorteners, known QR abused openredirects, and more. 
  4type: "rule"
  5severity: "medium"
  6source: |
  7  type.inbound
  8  and (
  9    1 <= length(attachments) < 3
 10    or (
 11      // if there are more than three attachments
 12      3 <= length(attachments) < 20
 13      // there are only pngs and pdf/docx
 14      and length(distinct(map(attachments, .file_extension))) == 2
 15      and all(distinct(map(attachments, .file_extension)),
 16              . in ('png', 'pdf', 'docx')
 17      )
 18      and (
 19        // multiple attachments mention common brands or other common common filenames
 20        (
 21          length(filter(attachments,
 22                        strings.icontains(.file_name, 'adobe')
 23                        or strings.icontains(.file_name, 'office')
 24                        or strings.icontains(.file_name, 'appstore')
 25                        or strings.icontains(.file_name, 'google')
 26                        or strings.icontains(.file_name, 'padlock')
 27                        or regex.icontains(.file_name, '\bdoc\b')
 28                 )
 29          ) > 3
 30        )
 31        // the attachment name contains the SLD of a recipient
 32        or any(filter(attachments, .file_extension in ('pdf', 'docx')),
 33               any(filter(recipients.to, .email.domain.valid),
 34                   strings.icontains(..file_name, .email.domain.sld)
 35               )
 36        )
 37      )
 38    )
 39  )
 40  
 41  // Inspects image attachments for QR codes
 42  and any(attachments,
 43          (
 44            .file_type in $file_types_images
 45            or .file_type == "pdf"
 46            or .file_extension in $file_extensions_macros
 47          )
 48          and (
 49            any(file.explode(.),
 50                .scan.qr.type == "url"
 51                and not .scan.qr.url.domain.domain == "geico.app.link"
 52                and (
 53                  // pass the QR URL to LinkAnalysis
 54                  any([ml.link_analysis(.scan.qr.url)],
 55                      .credphish.disposition == "phishing"
 56  
 57                      // any routing traverses via $suspicious_tld list
 58                      or any(.redirect_history, .domain.tld in $suspicious_tlds)
 59  
 60                      // effective destination in $suspicious_tld list
 61                      or .effective_url.domain.tld in $suspicious_tlds
 62  
 63                      // or the effective destination domain is in $abuse_ch_urlhaus_domains_trusted_reporters
 64                      or .effective_url.domain.root_domain in $abuse_ch_urlhaus_domains_trusted_reporters
 65  
 66                      // or any files downloaded are zips or executables
 67                      or any(.files_downloaded,
 68                             .file_extension in $file_extensions_common_archives
 69                             or .file_extension in $file_extensions_executables
 70                      )
 71                  )
 72                  or (
 73  
 74                    // or the QR code's root domain is a url_shortener
 75                    .scan.qr.url.domain.root_domain in $url_shorteners
 76                    or (
 77                      .scan.qr.url.domain.root_domain in $social_landing_hosts
 78                      and (
 79                        not (
 80                          any(ml.nlu_classifier(body.current_thread.text).intents,
 81                              .name == "benign"
 82                          )
 83                          or any(ml.nlu_classifier(body.current_thread.text).entities,
 84                                 .name == "disclaimer"
 85                          )
 86                        )
 87                        or not any(attachments,
 88                                   any(file.explode(.),
 89                                       any(ml.nlu_classifier(.scan.ocr.raw).intents,
 90                                           .name == "benign"
 91                                       )
 92                                   )
 93                        )
 94                        // the QR code contains the email address of a recipient
 95                        or (
 96                          any(filter(recipients.to, .email.domain.valid),
 97                              strings.icontains(..scan.qr.url.url, .email.email)
 98                          )
 99                        )
100                      )
101  
102                      // exclude google maps
103                      and not strings.starts_with(.scan.qr.url.url,
104                                                  'https://goo.gl/maps'
105                      )
106                      and not strings.starts_with(.scan.qr.url.url,
107                                                  'https://maps.app.goo.gl'
108                      )
109                    )
110                  )
111  
112                  // the QR code url is a bing open redirect
113                  or (
114                    .scan.qr.url.domain.root_domain == 'bing.com'
115                    and .scan.qr.url.path =~ '/ck/a'
116                  )
117                  // QR code contains non ascii chars
118                  or regex.contains(.scan.qr.url.url, '[^\x00-\x7F]')
119                  or (
120                    (
121                      // usap-dc open redirect
122                      .scan.qr.url.domain.root_domain == "usap-dc.org"
123                      and .scan.qr.url.path =~ "/tracker"
124                      and strings.starts_with(.scan.qr.url.query_params,
125                                              "type=dataset&url=http"
126                      )
127                    )
128                    // the QR code contains the email address of a recipient
129                    // allowing for base64 encoded variants
130                    or (
131                      any(filter(recipients.to, .email.domain.valid),
132                          strings.icontains(..scan.qr.url.url, .email.email)
133                          or any(strings.scan_base64(..scan.qr.url.url,
134                                                     ignore_padding=true
135                                 ),
136                                 strings.icontains(., ..email.email)
137                          )
138                          or any(strings.scan_base64(..scan.qr.url.fragment,
139                                                     ignore_padding=true
140                                 ),
141                                 strings.icontains(., ..email.email)
142                          )
143                      )
144                    )
145                  )
146                )
147            )
148          )
149  )
150  and (
151    (
152      profile.by_sender_email().prevalence in ("new", "outlier")
153      and not profile.by_sender_email().solicited
154    )
155    or (
156      profile.by_sender_email().any_messages_malicious_or_spam
157      and not profile.by_sender_email().any_messages_benign
158    )
159    or (
160      sender.email.domain.domain in $org_domains
161      and not coalesce(headers.auth_summary.dmarc.pass, false)
162    )
163  )
164  
165  // negate highly trusted sender domains unless they fail DMARC authentication
166  and (
167    (
168      sender.email.domain.root_domain in $high_trust_sender_root_domains
169      and not headers.auth_summary.dmarc.pass
170    )
171    or sender.email.domain.root_domain not in $high_trust_sender_root_domains
172  )  
173attack_types:
174  - "Credential Phishing"
175tactics_and_techniques:
176  - "QR code"
177  - "Social engineering"
178detection_methods:
179  - "Computer Vision"
180  - "Header analysis"
181  - "Natural Language Understanding"
182  - "QR code analysis"
183  - "Sender analysis"
184  - "URL analysis"
185  - "URL screenshot"
186id: "9f1681e1-8c15-5edd-9aaa-eb5af1729322"
to-top