Detection rules › Sublime MQL

Link: Tycoon2FA phishing kit (non-exhaustive)

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

Detects links utilizing the Tycoon2FA phishing kit, identified by specific DOM structure patterns and CDN characteristics, combined with suspicious domain indicators such as free subdomain hosts or suspicious TLDs. As the Tycoon2FA kit is evolving, this rule will not detect all variants of Tycoon2FA phishing, and is designed to compliment existing and future detections.

Threat classification

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

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesFree subdomain host, Evasion, Credential Phishing

Event coverage

Rule body MQL

type.inbound
and length(body.current_thread.links) < 10
and any(body.current_thread.links,
        // initial suspicious link check
        (
          .href_url.domain.root_domain in $free_subdomain_hosts
          or .href_url.domain.tld in $suspicious_tlds
          or any(recipients.to,
                 strings.icontains(..href_url.url, .email.email)
                 and .email.domain.valid
          )
        )

        // known Tycoon pattern (benign on its own, but a good confirming indicator when coupled with additional logic)
        and any(ml.link_analysis(.).unique_urls_accessed,
                .path in ("/cdn-cgi/rum")
        )

        // begin CAPTCHA options
        and (
          // Grid "CAPTCHA"
          (
            length(distinct(map(html.xpath(ml.link_analysis(.).final_dom,
                                           '//*/@class'
                                ).nodes,
                                .raw
                            ),
                            .
                   )
            ) == 5
            and all(distinct(map(html.xpath(ml.link_analysis(.).final_dom,
                                            '//*/@class'
                                 ).nodes,
                                 .raw
                             ),
                             .
                    ),
                    . in ("card", "title", "hint", "grid", "dot")
            )
          )
          // Unsplash image selection "CAPTCHA"
          or (
            any(distinct(map(html.xpath(ml.link_analysis(.).final_dom,
                                        '//*/@class'
                             ).nodes,
                             .raw
                         ),
                         .
                ),
                . in (
                  "captcha-container",
                  "puzzle-piece drag-hint",
                  "puzzle-image"
                )
            )
            or length(filter(ml.link_analysis(.).unique_urls_accessed,
                             .domain.domain == "images.unsplash.com"
                      )
            ) > 4
            or any(file.explode(ml.link_analysis(.).final_dom),
                   length(filter(.scan.javascript.identifiers,
                                 strings.icontains(., "puzzle")
                          )
                   ) > 3
            )
            or strings.ilike(ml.link_analysis(.).final_dom.raw,
                             "*Please align the puzzle correctly*",
                             "*Verified! You may proceed*",
                             "*Human Check*",
                             "*needs to review the security of your connection before proceeding.*"
            )
          )
          
          // Randomized image domain CAPTCHA
          // all image URL domains accessed are unique from each other
          or (
            length(filter(ml.link_analysis(.).unique_urls_accessed,
                          any([".jpg", ".png", ".jpeg"],
                              strings.ends_with(..path, .)
                          )
                   )
            ) == length(distinct(filter(ml.link_analysis(.).unique_urls_accessed,
                                        any([".jpg", ".png", ".jpeg"],
                                            strings.ends_with(..path, .)
                                        )
                                 ),
                                 .domain.root_domain
                        )
            )
            and length(filter(ml.link_analysis(.).unique_urls_accessed,
                              any([".jpg", ".png", ".jpeg"],
                                  strings.ends_with(..path, .)
                              )
                       )
            ) > 4
          )

          // Reoccuring form pattern
          or length(html.xpath(ml.link_analysis(.).final_dom,
                               "//form[@method='POST']//input[@name='zone' and @type='hidden']"
                    ).nodes
          ) == 1
        )
)

Detection logic

Scope: inbound message.

Detects links utilizing the Tycoon2FA phishing kit, identified by specific DOM structure patterns and CDN characteristics, combined with suspicious domain indicators such as free subdomain hosts or suspicious TLDs. As the Tycoon2FA kit is evolving, this rule will not detect all variants of Tycoon2FA phishing, and is designed to compliment existing and future detections.

  1. inbound message
  2. length(body.current_thread.links) < 10
  3. any of body.current_thread.links where all hold:
    • any of:
      • .href_url.domain.root_domain in $free_subdomain_hosts
      • .href_url.domain.tld in $suspicious_tlds
      • any of recipients.to where all hold:
        • strings.icontains(.href_url.url)
        • .email.domain.valid
    • any of ml.link_analysis(.).unique_urls_accessed where:
      • .path in ('/cdn-cgi/rum')
    • any of:
      • all of:
        • length(distinct(map(html.xpath(ml.link_analysis(.).final_dom, '//*/@class').nodes, .raw), .)) is 5
        • all of distinct(...) where:
          • . in ('card', 'title', 'hint', 'grid', 'dot')
      • any of:
        • any of distinct(...) where:
          • . in ('captcha-container', 'puzzle-piece drag-hint', 'puzzle-image')
        • length(filter(ml.link_analysis(.).unique_urls_accessed, .domain.domain == 'images.unsplash.com')) > 4
        • any of file.explode(...) where:
          • length(filter(.scan.javascript.identifiers, strings.icontains(., 'puzzle'))) > 3
        • ml.link_analysis(.).final_dom.raw matches any of 4 patterns
          • *Please align the puzzle correctly*
          • *Verified! You may proceed*
          • *Human Check*
          • *needs to review the security of your connection before proceeding.*
      • all of:
        • length(filter(ml.link_analysis(.).unique_urls_accessed, any(['.jpg', '.png', '.jpeg'], strings.ends_with(..path, .)))) is length(distinct(filter(ml.link_analysis(.).unique_urls_accessed, any(['.jpg', '.png', '.jpeg'], strings.ends_with(..path, .))), .domain.root_domain))
        • length(filter(ml.link_analysis(.).unique_urls_accessed, any(['.jpg', '.png', '.jpeg'], strings.ends_with(..path, .)))) > 4
      • length(html.xpath(ml.link_analysis(.).final_dom, "//form[@method='POST']//input[@name='zone' and @type='hidden']").nodes) is 1

Inspects: body.current_thread.links, body.current_thread.links[].href_url.domain.root_domain, body.current_thread.links[].href_url.domain.tld, body.current_thread.links[].href_url.url, recipients.to, recipients.to[].email.domain.valid, recipients.to[].email.email, type.inbound. Sensors: file.explode, html.xpath, ml.link_analysis, strings.ends_with, strings.icontains, strings.ilike. Reference lists: $free_subdomain_hosts, $suspicious_tlds.

Indicators matched (15)

FieldMatchValue
ml.link_analysis(body.current_thread.links[]).unique_urls_accessed[].pathmember/cdn-cgi/rum
distinct(...)[]membercard
distinct(...)[]membertitle
distinct(...)[]memberhint
distinct(...)[]membergrid
distinct(...)[]memberdot
distinct(...)[]membercaptcha-container
distinct(...)[]memberpuzzle-piece drag-hint
distinct(...)[]memberpuzzle-image
ml.link_analysis(body.current_thread.links[]).unique_urls_accessed[].domain.domainequalsimages.unsplash.com
strings.icontainssubstringpuzzle
strings.ilikesubstring*Please align the puzzle correctly*
3 more
strings.ilikesubstring*Verified! You may proceed*
strings.ilikesubstring*Human Check*
strings.ilikesubstring*needs to review the security of your connection before proceeding.*