Detection rules › Sublime MQL

Link: Multistage landing - Microsoft Forms abuse

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

The detection rule matches on message groups which make use of Microsoft Forms as a landing page. The landing page contains links which are newly registered, use free file or subdomain hosts, URL shorteners or when visited are phishing pages, lead to a captcha or redirect to a top website.

Threat classification

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

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesImpersonation: Brand, Social engineering

Event coverage

Rule body MQL

type.inbound
and any(filter(body.links, .href_url.domain.domain == "forms.office.com"),
        // avoid doing Link Analysis if the display-text has strong indications of phishing
        (
          // replace confusables - observed ITW
          regex.icontains(strings.replace_confusables(.display_text),
                          'review|proposal|document|efax|restore|[o0]pen|secure|messaging|reset|account|verify|login|notification|alert|urgent|immediate|access|support|\bupdate\b|download|attachment|service|payment|remittance|invoice'
          )
          and not regex.icontains(strings.replace_confusables(.display_text),
                                  'customer service'
          )
          // add confidence to these strings by using profile.by_sender()
          and (
            not profile.by_sender().solicited
            and profile.by_sender().prevalence in ('new', 'outlier')
          )
        )
        or 
        // look at the final_dom.raw
        // if the page has been taken down, match
        strings.icontains(ml.link_analysis(., mode="aggressive").final_dom.raw,
                          'This form was blocked due to privacy or safety concerns.'
        )
        // this error has been shown before with the text "Phishing form from content scan. Inner Message: This form has been flagged for potential phishing."
        or any(ml.link_analysis(., mode="aggressive").additional_responses,
               strings.icontains(.json["error"]["message"], "phishing")
        )
        // or MS thinks there are phishing keywords
        or any(ml.link_analysis(., mode="aggressive").additional_responses,
               any(.json["form"]["questions"],
                   .["subtitleHasPhishingKeywords"] == true
               )
               or any(.json["form"]["questions"],
                      .["titleHasPhishingKeywords"] == true
               )
               or any(.json["form"]["descriptiveQuestions"],
                      .["titleHasPhishingKeywords"] == true
               )
               or any(.json["form"]["descriptiveQuestions"],
                      .["titleHasPhishingKeywords"] == true
               )
        )
        // this logic checks for three abnormal cases
        // 1) no questions
        // 2) questions, but no inputs
        // 3) a bunch of new lines (used to push down the submit button of the form)
        // AND 
        // // there is one or two links that isn't "standard" on the form
        or (
          (
            // 1) doesn't contain any sections or questions
            any(ml.link_analysis(., mode="aggressive").additional_responses,
                length(.json["form"]["descriptiveQuestions"]) == 0
                and length(.json["form"]["questions"]) == 0
            )
            or 
            // 2) Contains a form section header, but no actual inputs
            // possible question types are .Choice, .TextField, .Rating, .DateTime, .Ranking, .MatrixChoiceGroup, .MatrixChoice, and .NPS
            any(ml.link_analysis(., mode="aggressive").additional_responses,
                length(.json["form"]["descriptiveQuestions"]) > 0
                and length(.json["form"]["questions"]) == 0
            )
            or 
            // 3) a bunch of new lines (used to push down the submit button of the form)
            (
              strings.icount(ml.link_analysis(., mode="aggressive").final_dom.raw,
                             '<br><br>'
              ) > 20
              or strings.icount(ml.link_analysis(., mode="aggressive").final_dom.raw,
                                '\n\n'
              ) > 20
              or strings.icount(ml.link_analysis(., mode="aggressive").final_dom.raw,
                                '<span><span>'
              ) > 20
              or any(ml.link_analysis(., mode="aggressive").additional_responses,
                     any(.json["form"]["questions"],
                         strings.icount(.["formsProRTQuestionTitle"],
                                        '<br><br>'
                         ) > 20
                         or strings.icount(.["formsProRTQuestionTitle"], '\n\n') > 20
                         or strings.icount(.["formsProRTQuestionTitle"],
                                           '<span><span>'
                         ) > 20
                     )
              )
            )
          )
          // AND 
          and 
          // there is one or two links to another page
          0 < length(filter(ml.link_analysis(.).final_dom.links,
                            not (
                              (
                                (
                                  .display_text =~ "Privacy and cookies"
                                  or .display_text =~ "terms of use"
                                  or .display_text =~ "report abuse"
                                )
                                and .href_url.domain.root_domain =~ 'microsoft.com'
                              )
                              or .href_url.domain.root_domain =~ sender.email.domain.root_domain
                              or (
                                .href_url.domain.tld == "ms"
                                // Microsoft does not own the .ms TLD, this checks to ensure it is one of their domains
                                and (
                                  network.whois(.href_url.domain).registrant_company == "Microsoft Corporation"
                                  or strings.ilike(network.whois(.href_url.domain
                                                   ).registrar_name,
                                                   "*MarkMonitor*",
                                                   "*CSC Corporate*",
                                                   "*com laude*"
                                  )
                                )
                              )
                            )
                     )
          ) <= 2
          and (
            not strings.contains(ml.link_analysis(., mode="aggressive").final_dom.raw,
                                 'role="progressbar" aria-label="Page 1 of '
            )
            or any(ml.link_analysis(., mode="aggressive").additional_responses,
                   .json["form"]["progressBarEnabled"] == false
            )
          )
        )
)

Detection logic

Scope: inbound message.

The detection rule matches on message groups which make use of Microsoft Forms as a landing page. The landing page contains links which are newly registered, use free file or subdomain hosts, URL shorteners or when visited are phishing pages, lead to a captcha or redirect to a top website.

  1. inbound message
  2. any of filter(body.links) where any holds:
    • all of:
      • strings.replace_confusables(.display_text) matches 'review|proposal|document|efax|restore|[o0]pen|secure|messaging|reset|account|verify|login|notification|alert|urgent|immediate|access|support|\\bupdate\\b|download|attachment|service|payment|remittance|invoice'
      • not:
        • strings.replace_confusables(.display_text) matches 'customer service'
      • all of:
        • not:
          • profile.by_sender().solicited
        • profile.by_sender().prevalence in ('new', 'outlier')
    • ml.link_analysis(., mode='aggressive').final_dom.raw contains 'This form was blocked due to privacy or safety concerns.'
    • any of ml.link_analysis(., mode='aggressive').additional_responses where:
      • .json['error']['message'] contains 'phishing'
    • any of ml.link_analysis(., mode='aggressive').additional_responses where any holds:
      • any of .json['form']['questions'] where:
        • .['subtitleHasPhishingKeywords'] is True
      • any of .json['form']['questions'] where:
        • .['titleHasPhishingKeywords'] is True
      • any of .json['form']['descriptiveQuestions'] where:
        • .['titleHasPhishingKeywords'] is True
      • any of .json['form']['descriptiveQuestions'] where:
        • .['titleHasPhishingKeywords'] is True
    • all of:
      • any of:
        • any of ml.link_analysis(., mode='aggressive').additional_responses where all hold:
          • length(.json['form']['descriptiveQuestions']) is 0
          • length(.json['form']['questions']) is 0
        • any of ml.link_analysis(., mode='aggressive').additional_responses where all hold:
          • length(.json['form']['descriptiveQuestions']) > 0
          • length(.json['form']['questions']) is 0
        • any of:
          • strings.icount(ml.link_analysis(., mode='aggressive').final_dom.raw, '<br><br>') > 20
          • strings.icount(ml.link_analysis(., mode='aggressive').final_dom.raw, '\\n\\n') > 20
          • strings.icount(ml.link_analysis(., mode='aggressive').final_dom.raw, '<span><span>') > 20
          • any of ml.link_analysis(., mode='aggressive').additional_responses where:
            • any of .json['form']['questions'] where any holds:
              • strings.icount(.['formsProRTQuestionTitle'], '<br><br>') > 20
              • strings.icount(.['formsProRTQuestionTitle'], '\\n\\n') > 20
              • strings.icount(.['formsProRTQuestionTitle'], '<span><span>') > 20
      • all of:
        • length(filter(ml.link_analysis(.).final_dom.links, not .display_text =~ 'Privacy and cookies' or .display_text =~ 'terms of use' or .display_text =~ 'report abuse' and .href_url.domain.root_domain =~ 'microsoft.com' or .href_url.domain.root_domain =~ sender.email.domain.root_domain or .href_url.domain.tld == 'ms' and network.whois(.href_url.domain).registrant_company == 'Microsoft Corporation' or strings.ilike(network.whois(.href_url.domain).registrar_name, '*MarkMonitor*', '*CSC Corporate*', '*com laude*'))) > 0
        • length(filter(ml.link_analysis(.).final_dom.links, not .display_text =~ 'Privacy and cookies' or .display_text =~ 'terms of use' or .display_text =~ 'report abuse' and .href_url.domain.root_domain =~ 'microsoft.com' or .href_url.domain.root_domain =~ sender.email.domain.root_domain or .href_url.domain.tld == 'ms' and network.whois(.href_url.domain).registrant_company == 'Microsoft Corporation' or strings.ilike(network.whois(.href_url.domain).registrar_name, '*MarkMonitor*', '*CSC Corporate*', '*com laude*'))) ≤ 2
      • any of:
        • not:
          • ml.link_analysis(., mode='aggressive').final_dom.raw contains 'role="progressbar" aria-label="Page 1 of '
        • any of ml.link_analysis(., mode='aggressive').additional_responses where:
          • .json['form']['progressBarEnabled'] is False

Inspects: body.links, body.links[].href_url.domain.domain, sender.email.domain.root_domain, type.inbound. Sensors: ml.link_analysis, network.whois, profile.by_sender, regex.icontains, strings.contains, strings.icontains, strings.icount, strings.ilike, strings.replace_confusables.

Indicators matched (14)

FieldMatchValue
body.links[].href_url.domain.domainequalsforms.office.com
regex.icontainsregexreview|proposal|document|efax|restore|[o0]pen|secure|messaging|reset|account|verify|login|notification|alert|urgent|immediate|access|support|\bupdate\b|download|attachment|service|payment|remittance|invoice
regex.icontainsregexcustomer service
strings.icontainssubstringThis form was blocked due to privacy or safety concerns.
strings.icontainssubstringphishing
ml.link_analysis(filter(body.links)[]).final_dom.links[].display_textequalsPrivacy and cookies
ml.link_analysis(filter(body.links)[]).final_dom.links[].display_textequalsterms of use
ml.link_analysis(filter(body.links)[]).final_dom.links[].display_textequalsreport abuse
ml.link_analysis(filter(body.links)[]).final_dom.links[].href_url.domain.root_domainequalsmicrosoft.com
ml.link_analysis(filter(body.links)[]).final_dom.links[].href_url.domain.tldequalsms
strings.ilikesubstring*MarkMonitor*
strings.ilikesubstring*CSC Corporate*
2 more
strings.ilikesubstring*com laude*
strings.containssubstringrole="progressbar" aria-label="Page 1 of