Detection rules › Sublime MQL

Sublime MQL rules: clickfunnels

ClickFunnels link infrastructure abuse

#
Severity
high
Type
rule
Source
github.com/sublime-security/sublime-rules

Email contains a ClickFunnels (mass mailing platform) tracking link but does not originate from ClickFunnels sending infrastructure. The myclickfunnels.com domain has been abused by threat actors to attempt credential phishing.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesFree email provider, Free subdomain host, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • attachments
  • body
  • body.links
  • headers
  • headers.domains
  • headers.hops
  • sender.email
  • subject
  • type

Rule body

type.inbound
and (
  (
    length(body.links) < 15
    and any(body.links, .href_url.domain.root_domain == "myclickfunnels.com")
  )
  or (
    length(attachments) <= 3
    and (
      any(attachments,
          (.file_type in $file_types_images or .file_type == "pdf")
          and any(file.explode(.),
                  .scan.qr.type is not null
                  and .scan.qr.url.domain.root_domain == "myclickfunnels.com"
                  // exclude images taken with mobile cameras and screenshots from android
                  and not any(.scan.exiftool.fields,
                              .key == "Model"
                              or (
                                .key == "Software"
                                and strings.starts_with(.value, "Android")
                              )
                  )
                  // exclude images taken with mobile cameras and screenshots from Apple
                  and not any(.scan.exiftool.fields,
                              .key == "DeviceManufacturer"
                              and .value == "Apple Computer Inc."
                  )
          )
      )
      or (
        length(attachments) == 0
        //
        // 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
        //
        and beta.parse_exif(file.message_screenshot()).image_height < 2000
        and beta.parse_exif(file.message_screenshot()).image_width < 2000
        and any(beta.scan_qr(file.message_screenshot()).items,
                .type is not null
                and .url.domain.root_domain == "myclickfunnels.com"
        )
      )
    )
  )
  or (
    length(attachments) <= 3
    and (
      any(attachments,
          (
            .file_type in ("pdf")
            or .file_extension in ("pdf", "eml")
            or .file_extension in $file_extensions_macros
            or (
              .content_type in ("message/rfc822") or .file_extension in ('eml')
            )
          )
          and any(file.explode(.),
                  any(.scan.url.urls,
                      .domain.root_domain == "myclickfunnels.com"
                  )
          )
      )
    )
  )
)
and not (
  any(headers.domains, strings.ends_with(.domain, "mailer.myclickfunnels.com"))
  or (
    (
      any(headers.hops,
          .index == 0
          and any(.authentication_results.dkim_details,
                  .domain == "mailer.myclickfunnels.com"
          )
      )
    )
    and any(distinct(headers.hops, .authentication_results.dmarc is not null),
            .index == 0
            and strings.ilike(.authentication_results.dmarc, "*pass")
    )
  )
)
// negating legit replies
and not (
  (
    strings.istarts_with(subject.subject, "RE:")
    or strings.istarts_with(subject.subject, "FW:")
    or strings.istarts_with(subject.subject, "FWD:")
    or strings.istarts_with(subject.subject, "Automatic reply:")
  )
  and (length(headers.references) > 0 and headers.in_reply_to is not null)
)
// negate highly trusted sender domains unless they fail DMARC authentication
and (
  (
    sender.email.domain.root_domain in $high_trust_sender_root_domains
    and (
      any(distinct(headers.hops, .authentication_results.dmarc is not null),
          strings.ilike(.authentication_results.dmarc, "*fail")
      )
    )
  )
  or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)

Detection logic

Scope: inbound message.

Email contains a ClickFunnels (mass mailing platform) tracking link but does not originate from ClickFunnels sending infrastructure. The myclickfunnels.com domain has been abused by threat actors to attempt credential phishing.

  1. inbound message
  2. any of:
    • all of:
      • length(body.links) < 15
      • any of body.links where:
        • .href_url.domain.root_domain is 'myclickfunnels.com'
    • all of:
      • length(attachments) ≤ 3
      • any of:
        • any of attachments where all hold:
          • any of:
            • .file_type in $file_types_images
            • .file_type is 'pdf'
          • any of file.explode(.) where all hold:
            • .scan.qr.type is set
            • .scan.qr.url.domain.root_domain is 'myclickfunnels.com'
            • not:
              • any of .scan.exiftool.fields where any holds:
                • .key is 'Model'
                • all of:
                  • .key is 'Software'
                  • .value starts with 'Android'
            • not:
              • any of .scan.exiftool.fields where all hold:
                • .key is 'DeviceManufacturer'
                • .value is 'Apple Computer Inc.'
        • all of:
          • length(attachments) is 0
          • beta.parse_exif(file.message_screenshot()).image_height < 2000
          • beta.parse_exif(file.message_screenshot()).image_width < 2000
          • any of beta.scan_qr(file.message_screenshot()).items where all hold:
            • .type is set
            • .url.domain.root_domain is 'myclickfunnels.com'
    • all of:
      • length(attachments) ≤ 3
      • any of attachments where all hold:
        • any of:
          • .file_type in ('pdf')
          • .file_extension in ('pdf', 'eml')
          • .file_extension in $file_extensions_macros
          • any of:
            • .content_type in ('message/rfc822')
            • .file_extension in ('eml')
        • any of file.explode(.) where:
          • any of .scan.url.urls where:
            • .domain.root_domain is 'myclickfunnels.com'
  3. none of:
    • any of headers.domains where:
      • .domain ends with 'mailer.myclickfunnels.com'
    • all of:
      • any of headers.hops where all hold:
        • .index is 0
        • any of .authentication_results.dkim_details where:
          • .domain is 'mailer.myclickfunnels.com'
      • any of distinct(headers.hops) where all hold:
        • .index is 0
        • .authentication_results.dmarc matches '*pass'
  4. not:
    • all of:
      • subject.subject starts with any of 4 patterns
        • RE:
        • FW:
        • FWD:
        • Automatic reply:
      • all of:
        • length(headers.references) > 0
        • headers.in_reply_to is set
  5. any of:
    • all of:
      • sender.email.domain.root_domain in $high_trust_sender_root_domains
      • any of distinct(headers.hops) where:
        • .authentication_results.dmarc matches '*fail'
    • sender.email.domain.root_domain not in $high_trust_sender_root_domains

Inspects: attachments[].content_type, attachments[].file_extension, attachments[].file_type, body.links, body.links[].href_url.domain.root_domain, headers.domains, headers.domains[].domain, headers.hops, headers.hops[].authentication_results.dkim_details, headers.hops[].authentication_results.dkim_details[].domain, headers.hops[].authentication_results.dmarc, headers.hops[].index, headers.in_reply_to, headers.references, sender.email.domain.root_domain, subject.subject, type.inbound. Sensors: beta.parse_exif, beta.scan_qr, file.explode, file.message_screenshot, strings.ends_with, strings.ilike, strings.istarts_with, strings.starts_with. Reference lists: $file_extensions_macros, $file_types_images, $high_trust_sender_root_domains.

Indicators matched (10)

FieldMatchValue
body.links[].href_url.domain.root_domainequalsmyclickfunnels.com
attachments[].file_typeequalspdf
file.explode(attachments[])[].scan.qr.url.domain.root_domainequalsmyclickfunnels.com
beta.scan_qr(file.message_screenshot()).items[].url.domain.root_domainequalsmyclickfunnels.com
attachments[].file_typememberpdf
attachments[].file_extensionmemberpdf
attachments[].file_extensionmembereml
attachments[].content_typemembermessage/rfc822
file.explode(attachments[])[].scan.url.urls[].domain.root_domainequalsmyclickfunnels.com
strings.ilikesubstring*fail

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      or
        any(attachments)
          and
            any(file.explode(attachments))
              and
                not
                  any(file.explode(attachments).scan.exiftool.fields)
                    or
                      and
                        file.explode(attachments[])[].scan.exiftool.fields[].key eq "Software"
                        file.explode(attachments[])[].scan.exiftool.fields[].value starts_with "Android"
                      file.explode(attachments[])[].scan.exiftool.fields[].key eq "Model"
                not
                  any(file.explode(attachments).scan.exiftool.fields)
                    and
                      file.explode(attachments[])[].scan.exiftool.fields[].key eq "DeviceManufacturer"
                      file.explode(attachments[])[].scan.exiftool.fields[].value eq "Apple Computer Inc."
                file.explode(attachments[])[].scan.qr.type is_not_null
                file.explode(attachments[])[].scan.qr.url.domain.root_domain eq "myclickfunnels.com"
            or
              attachments.file_type eq "pdf"
               macro "attachments[].file_type in file_types_images"
        and
          any(beta.scan_qr(file.message_screenshot()).items)
            and
              beta.scan_qr(file.message_screenshot()).items.type is_not_null
              beta.scan_qr(file.message_screenshot()).items.url.domain.root_domain eq "myclickfunnels.com"
          attachments length_compare "0"
          beta.parse_exif func_call "beta.parse_exif(file.message_screenshot()).image_height < 2000"
          beta.parse_exif func_call "beta.parse_exif(file.message_screenshot()).image_width < 2000"
      attachments length_compare "3"
    and
      any(attachments)
        and
          any(file.explode(attachments))
            any(file.explode(attachments).scan.url.urls)
              file.explode(attachments).scan.url.urls.domain.root_domain eq "myclickfunnels.com"
          or
            attachments.content_type eq "message/rfc822"
            attachments.file_extension eq "eml"
            attachments.file_extension in ["eml", "pdf"]
            attachments.file_type eq "pdf"
             macro "attachments[].file_extension in file_extensions_macros"
      attachments length_compare "3"
    and
      any(body.links)
        body.links.href_url.domain.root_domain eq "myclickfunnels.com"
      body.links length_compare "15"
  not
    or
      and
        any(headers.hops)
          and
            any(headers.hops.authentication_results.dkim_details)
              headers.hops.authentication_results.dkim_details.domain eq "mailer.myclickfunnels.com"
            headers.hops.index eq "0"
        any(distinct(headers.hops))
          and
            distinct(headers.hops).authentication_results.dmarc ends_with "pass"
            distinct(headers.hops).index eq "0"
      any(headers.domains)
        headers.domains.domain ends_with "mailer.myclickfunnels.com"
  or
    and
      any(distinct(headers.hops))
        distinct(headers.hops).authentication_results.dmarc ends_with "fail"
       macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
     macro "sender.email.domain.root_domain not in high_trust_sender_root_domains"
  not
    and
      or
        subject.subject starts_with "Automatic reply:"
        subject.subject starts_with "FW:"
        subject.subject starts_with "FWD:"
        subject.subject starts_with "RE:"
      headers.in_reply_to is_not_null
      headers.references length_compare "0"
  type.inbound eq "true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
headers.hopsarray_any(no value, null check)excludes:headers.hops
distinct(headers.hops)array_any(no value, null check)excludes:distinct(headers.hops)
headers.domainsarray_any(no value, null check)excludes:headers.domains
subject.subjectstarts_withAutomatic reply:excludes:subject.subject field:"subject.subject" value:"Automatic reply:"
subject.subjectstarts_withFW:excludes:subject.subject field:"subject.subject" value:"FW:"
subject.subjectstarts_withFWD:excludes:subject.subject field:"subject.subject" value:"FWD:"
subject.subjectstarts_withRE:excludes:subject.subject field:"subject.subject" value:"RE:"
headers.in_reply_tois_not_null(no value, null check)excludes:headers.in_reply_to
headers.referenceslength_compare0excludes:headers.references field:"headers.references" value:"0"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"