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        or any(filter(attachments, .file_extension in ('pdf', 'docx')),
 32               any(recipients.to,
 33                   strings.icontains(..file_name, .email.domain.sld)
 34               )
 35        )
 36      )
 37    )
 38  )
 39  
 40  // Inspects image attachments for QR codes
 41  and any(attachments,
 42          (
 43            .file_type in $file_types_images
 44            or .file_type == "pdf"
 45            or .file_extension in $file_extensions_macros
 46          )
 47          and (
 48            any(file.explode(.),
 49                .scan.qr.type == "url"
 50                and not .scan.qr.url.domain.domain == "geico.app.link"
 51                and (
 52                  // pass the QR URL to LinkAnalysis
 53                  any([ml.link_analysis(.scan.qr.url)],
 54                      .credphish.disposition == "phishing"
 55  
 56                      // any routing traverses via $suspicious_tld list
 57                      or any(.redirect_history, .domain.tld in $suspicious_tlds)
 58  
 59                      // effective destination in $suspicious_tld list
 60                      or .effective_url.domain.tld in $suspicious_tlds
 61  
 62                      // or the effective destination domain is in $abuse_ch_urlhaus_domains_trusted_reporters
 63                      or .effective_url.domain.root_domain in $abuse_ch_urlhaus_domains_trusted_reporters
 64  
 65                      // or any files downloaded are zips or executables
 66                      or any(.files_downloaded,
 67                             .file_extension in $file_extensions_common_archives
 68                             or .file_extension in $file_extensions_executables
 69                      )
 70                  )
 71                  or (
 72  
 73                    // or the QR code's root domain is a url_shortener
 74                    .scan.qr.url.domain.root_domain in $url_shorteners
 75                    and (
 76                      not (
 77                        any(ml.nlu_classifier(body.current_thread.text).intents,
 78                            .name == "benign"
 79                        )
 80                        or any(ml.nlu_classifier(body.current_thread.text).entities,
 81                               .name == "disclaimer"
 82                        )
 83                      )
 84                      or not any(attachments,
 85                                 any(file.explode(.),
 86                                     any(ml.nlu_classifier(.scan.ocr.raw).intents,
 87                                         .name == "benign"
 88                                     )
 89                                 )
 90                      )
 91                      or (
 92                        any(recipients.to,
 93                            strings.icontains(..scan.qr.url.url, .email.email)
 94                        )
 95                      )
 96                    )
 97  
 98                    // exclude google maps
 99                    and not strings.starts_with(.scan.qr.url.url,
100                                                'https://goo.gl/maps'
101                    )
102                    and not strings.starts_with(.scan.qr.url.url,
103                                                'https://maps.app.goo.gl'
104                    )
105                  )
106  
107                  // the QR code url is a bing open redirect
108                  or (
109                    .scan.qr.url.domain.root_domain == 'bing.com'
110                    and .scan.qr.url.path =~ '/ck/a'
111                  )
112                  // QR code contains non ascii chars
113                  or regex.contains(.scan.qr.url.url, '[^\x00-\x7F]')
114                  or (
115  
116                    // usap-dc open redirect
117                    .scan.qr.url.domain.root_domain == "usap-dc.org"
118                    and .scan.qr.url.path =~ "/tracker"
119                    and strings.starts_with(.scan.qr.url.query_params,
120                                            "type=dataset&url=http"
121                    )
122                    or (
123                      any(recipients.to,
124                          strings.icontains(..scan.qr.url.url, .email.email)
125                          or any(beta.scan_base64(..scan.qr.url.url,
126                                                  ignore_padding=true
127                                 ),
128                                 strings.icontains(., ..email.email)
129                          )
130                          or any(beta.scan_base64(..scan.qr.url.fragment,
131                                                  ignore_padding=true
132                                 ),
133                                 strings.icontains(., ..email.email)
134                          )
135                      )
136                    )
137                  )
138                )
139            )
140          )
141  )
142  and (
143    (
144      profile.by_sender().prevalence in ("new", "outlier")
145      and not profile.by_sender().solicited
146    )
147    or (
148      profile.by_sender().any_messages_malicious_or_spam
149      and not profile.by_sender().any_false_positives
150    )
151    or (
152        sender.email.domain.domain in $org_domains
153        and not headers.auth_summary.dmarc.pass
154    )
155  )
156  
157  // negate highly trusted sender domains unless they fail DMARC authentication
158  and (
159    (
160      sender.email.domain.root_domain in $high_trust_sender_root_domains
161      and not headers.auth_summary.dmarc.pass
162    )
163    or sender.email.domain.root_domain not in $high_trust_sender_root_domains
164  )  
165attack_types:
166  - "Credential Phishing"
167tactics_and_techniques:
168  - "QR code"
169  - "Social engineering"
170detection_methods:
171  - "Computer Vision"
172  - "Header analysis"
173  - "Natural Language Understanding"
174  - "QR code analysis"
175  - "Sender analysis"
176  - "URL analysis"
177  - "URL screenshot"
178id: "9f1681e1-8c15-5edd-9aaa-eb5af1729322"
to-top