EXPLORE
← Back to Explore
sublimehighRule

Attachment: QR code with suspicious URL patterns in EML file

Detects EML attachments containing QR codes that link to URLs with suspicious patterns, including specific alphanumeric combinations in subdomains and paths, or special characters followed by encoded terminators. These patterns are commonly used to evade detection in credential theft attacks.

MITRE ATT&CK

defense-evasioninitial-access

Detection Query

type.inbound
and length(recipients.to) == 1
and recipients.to[0].email.domain.valid
and any(attachments,
        // Email Attachments
        any(file.parse_eml(.).attachments,
            (
              // looks for office docs in the attached eml
              .file_extension in $file_extensions_macros
              and any(file.explode(.),
                      .scan.qr.type == "url"
                      // QR code URL contains recipient's email (targeting indicator)
                      and any(recipients.to,
                              .email.domain.valid
                              and (
                                // Plaintext email address in URL
                                strings.icontains(..scan.qr.url.url,
                                                  .email.email
                                )
                                // OR base64 encoded email address
                                or any(strings.scan_base64(..scan.qr.url.url,
                                                           format="url",
                                                           ignore_padding=true
                                       ),
                                       strings.icontains(., ..email.email)
                                )
                              )
                      )
                      // a single path
                      and strings.count(.scan.qr.url.path, '/') == 2
                      and (
                        (
                          (
                            strings.contains(.scan.qr.url.path, '/$')
                            or strings.contains(.scan.qr.url.path, '/*')
                            or strings.contains(.scan.qr.url.path, '/#')
                          )
                          // subdomain should contain num{3}alpha or alphanum{3}
                          and regex.icontains(.scan.qr.url.domain.subdomain,
                                              '^(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)(?:$|\.)'
                          )
                          // url path should contain num{3}alpha or alphanum{3}
                          and regex.icontains(.scan.qr.url.path,
                                              '\/(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)\/'
                          )
                        )
                        or (
                          // special char in the path
                          (
                            strings.contains(.scan.qr.url.path, '!')
                            or strings.contains(.scan.qr.url.path, '@')
                          )
                          and (
                            strings.contains(.scan.qr.url.path, '/$')
                            or strings.contains(.scan.qr.url.path, '/*')
                            or strings.contains(.scan.qr.url.path, '/#')
                            // hex dollar sign
                            or strings.icontains(.scan.qr.url.path, '%24')
                            // hex star
                            or strings.icontains(.scan.qr.url.path, '%2A')
                            // hex pound
                            or strings.icontains(.scan.qr.url.path, '%23')
                          )
                          // ensure expected ordering
                          and regex.icontains(.scan.qr.url.url,
                                              '[!@].*(?:[$*]|%2[A43])'
                          )
                        )
                      )
              )
            )
            or (
              // looks for pdfs and images in the attached eml
              //
              // This rule makes use of a beta feature and is subject to change without notice
              // using the beta feature in custom rules is not suggested until it has been formally released
              //
              any(beta.scan_qr(.).items,
                  .type is not null
                  // a single path
                  and strings.count(.url.path, '/') == 2
                  and (
                    (
                      (
                        strings.contains(.url.path, '/$')
                        or strings.contains(.url.path, '/*')
                        or strings.contains(.url.path, '/#')
                      )
                      // subdomain should contain num{3}alpha or alphanum{3}
                      and regex.icontains(.url.domain.subdomain,
                                          '^(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)(?:$|\.)'
                      )
                      // url path should contain num{3}alpha or alphanum{3}
                      and regex.icontains(.url.path,
                                          '\/(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)\/'
                      )
                    )
                    or (
                      // special char in the path
                      (
                        strings.contains(.url.path, '!')
                        or strings.contains(.url.path, '@')
                      )
                      and (
                        strings.contains(.url.path, '/$')
                        or strings.contains(.url.path, '/*')
                        or strings.contains(.url.path, '/#')
                        // hex dollar sign
                        or strings.icontains(.url.path, '%24')
                        // hex star
                        or strings.icontains(.url.path, '%2A')
                        // hex pound
                        or strings.icontains(.url.path, '%23')
                      )
                      // ensure expected ordering
                      and regex.icontains(.url.url, '[!@].*(?:[$*]|%2[A43])')
                    )
                  )
              )
            )
        )
)

Data Sources

Email MessagesEmail HeadersEmail Attachments

Platforms

email
Raw Content
name: "Attachment: QR code with suspicious URL patterns in EML file"
description: "Detects EML attachments containing QR codes that link to URLs with suspicious patterns, including specific alphanumeric combinations in subdomains and paths, or special characters followed by encoded terminators. These patterns are commonly used to evade detection in credential theft attacks."
type: "rule"
severity: "high"
source: |
  type.inbound
  and length(recipients.to) == 1
  and recipients.to[0].email.domain.valid
  and any(attachments,
          // Email Attachments
          any(file.parse_eml(.).attachments,
              (
                // looks for office docs in the attached eml
                .file_extension in $file_extensions_macros
                and any(file.explode(.),
                        .scan.qr.type == "url"
                        // QR code URL contains recipient's email (targeting indicator)
                        and any(recipients.to,
                                .email.domain.valid
                                and (
                                  // Plaintext email address in URL
                                  strings.icontains(..scan.qr.url.url,
                                                    .email.email
                                  )
                                  // OR base64 encoded email address
                                  or any(strings.scan_base64(..scan.qr.url.url,
                                                             format="url",
                                                             ignore_padding=true
                                         ),
                                         strings.icontains(., ..email.email)
                                  )
                                )
                        )
                        // a single path
                        and strings.count(.scan.qr.url.path, '/') == 2
                        and (
                          (
                            (
                              strings.contains(.scan.qr.url.path, '/$')
                              or strings.contains(.scan.qr.url.path, '/*')
                              or strings.contains(.scan.qr.url.path, '/#')
                            )
                            // subdomain should contain num{3}alpha or alphanum{3}
                            and regex.icontains(.scan.qr.url.domain.subdomain,
                                                '^(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)(?:$|\.)'
                            )
                            // url path should contain num{3}alpha or alphanum{3}
                            and regex.icontains(.scan.qr.url.path,
                                                '\/(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)\/'
                            )
                          )
                          or (
                            // special char in the path
                            (
                              strings.contains(.scan.qr.url.path, '!')
                              or strings.contains(.scan.qr.url.path, '@')
                            )
                            and (
                              strings.contains(.scan.qr.url.path, '/$')
                              or strings.contains(.scan.qr.url.path, '/*')
                              or strings.contains(.scan.qr.url.path, '/#')
                              // hex dollar sign
                              or strings.icontains(.scan.qr.url.path, '%24')
                              // hex star
                              or strings.icontains(.scan.qr.url.path, '%2A')
                              // hex pound
                              or strings.icontains(.scan.qr.url.path, '%23')
                            )
                            // ensure expected ordering
                            and regex.icontains(.scan.qr.url.url,
                                                '[!@].*(?:[$*]|%2[A43])'
                            )
                          )
                        )
                )
              )
              or (
                // looks for pdfs and images in the attached eml
                //
                // This rule makes use of a beta feature and is subject to change without notice
                // using the beta feature in custom rules is not suggested until it has been formally released
                //
                any(beta.scan_qr(.).items,
                    .type is not null
                    // a single path
                    and strings.count(.url.path, '/') == 2
                    and (
                      (
                        (
                          strings.contains(.url.path, '/$')
                          or strings.contains(.url.path, '/*')
                          or strings.contains(.url.path, '/#')
                        )
                        // subdomain should contain num{3}alpha or alphanum{3}
                        and regex.icontains(.url.domain.subdomain,
                                            '^(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)(?:$|\.)'
                        )
                        // url path should contain num{3}alpha or alphanum{3}
                        and regex.icontains(.url.path,
                                            '\/(?:[a-z]+[0-9]{3}|[0-9]{3}[a-z]+)\/'
                        )
                      )
                      or (
                        // special char in the path
                        (
                          strings.contains(.url.path, '!')
                          or strings.contains(.url.path, '@')
                        )
                        and (
                          strings.contains(.url.path, '/$')
                          or strings.contains(.url.path, '/*')
                          or strings.contains(.url.path, '/#')
                          // hex dollar sign
                          or strings.icontains(.url.path, '%24')
                          // hex star
                          or strings.icontains(.url.path, '%2A')
                          // hex pound
                          or strings.icontains(.url.path, '%23')
                        )
                        // ensure expected ordering
                        and regex.icontains(.url.url, '[!@].*(?:[$*]|%2[A43])')
                      )
                    )
                )
              )
          )
  )

attack_types:
  - "Credential Phishing"
tactics_and_techniques:
  - "QR code"
  - "Evasion"
  - "Social engineering"
detection_methods:
  - "Archive analysis"
  - "File analysis"
  - "QR code analysis"
  - "URL analysis"
id: "2289acd5-c3dc-58c2-81f6-4e1b0cc30064"