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 .scan.qr.url.domain.root_domain in $social_landing_hosts
 77                    and (
 78                      not (
 79                        any(ml.nlu_classifier(body.current_thread.text).intents,
 80                            .name == "benign"
 81                        )
 82                        or any(ml.nlu_classifier(body.current_thread.text).entities,
 83                               .name == "disclaimer"
 84                        )
 85                      )
 86                      or not any(attachments,
 87                                 any(file.explode(.),
 88                                     any(ml.nlu_classifier(.scan.ocr.raw).intents,
 89                                         .name == "benign"
 90                                     )
 91                                 )
 92                      )
 93                      // the QR code contains the email address of a recipient
 94                      or (
 95                        any(filter(recipients.to, .email.domain.valid),
 96                            strings.icontains(..scan.qr.url.url, .email.email)
 97                        )
 98                      )
 99                    )
100  
101                    // exclude google maps
102                    and not strings.starts_with(.scan.qr.url.url,
103                                                'https://goo.gl/maps'
104                    )
105                    and not strings.starts_with(.scan.qr.url.url,
106                                                'https://maps.app.goo.gl'
107                    )
108                  )
109  
110                  // the QR code url is a bing open redirect
111                  or (
112                    .scan.qr.url.domain.root_domain == 'bing.com'
113                    and .scan.qr.url.path =~ '/ck/a'
114                  )
115                  // QR code contains non ascii chars
116                  or regex.contains(.scan.qr.url.url, '[^\x00-\x7F]')
117                  or (
118  
119                    // usap-dc open redirect
120                    .scan.qr.url.domain.root_domain == "usap-dc.org"
121                    and .scan.qr.url.path =~ "/tracker"
122                    and strings.starts_with(.scan.qr.url.query_params,
123                                            "type=dataset&url=http"
124                    )
125                    // the QR code contains the email address of a recipient
126                    // allowing for base64 encoded variants
127                    or (
128                      any(filter(recipients.to, .email.domain.valid),
129                          strings.icontains(..scan.qr.url.url, .email.email)
130                          or any(beta.scan_base64(..scan.qr.url.url,
131                                                  ignore_padding=true
132                                 ),
133                                 strings.icontains(., ..email.email)
134                          )
135                          or any(beta.scan_base64(..scan.qr.url.fragment,
136                                                  ignore_padding=true
137                                 ),
138                                 strings.icontains(., ..email.email)
139                          )
140                      )
141                    )
142                  )
143                )
144            )
145          )
146  )
147  and (
148    (
149      profile.by_sender_email().prevalence in ("new", "outlier")
150      and not profile.by_sender_email().solicited
151    )
152    or (
153      profile.by_sender_email().any_messages_malicious_or_spam
154      and not profile.by_sender_email().any_messages_benign
155    )
156    or (
157        sender.email.domain.domain in $org_domains
158        and not coalesce(headers.auth_summary.dmarc.pass, false)
159    )
160  )
161  
162  // negate highly trusted sender domains unless they fail DMARC authentication
163  and (
164    (
165      sender.email.domain.root_domain in $high_trust_sender_root_domains
166      and not headers.auth_summary.dmarc.pass
167    )
168    or sender.email.domain.root_domain not in $high_trust_sender_root_domains
169  )  
170attack_types:
171  - "Credential Phishing"
172tactics_and_techniques:
173  - "QR code"
174  - "Social engineering"
175detection_methods:
176  - "Computer Vision"
177  - "Header analysis"
178  - "Natural Language Understanding"
179  - "QR code analysis"
180  - "Sender analysis"
181  - "URL analysis"
182  - "URL screenshot"
183id: "9f1681e1-8c15-5edd-9aaa-eb5af1729322"
to-top