Detection rules › Sublime MQL

Attachment: EML file contains HTML attachment with login portal indicators

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

Attached EML file contains an HTML attachment with suspicious login indicators. Known credential theft technique.

Threat classification

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

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesEvasion, HTML smuggling

Event coverage

Rule body MQL

type.inbound

// exclude bounce backs & read receipts
and not strings.like(sender.email.local_part,
                     "*postmaster*",
                     "*mailer-daemon*",
                     "*administrator*"
)
and not regex.imatch(subject.subject, "(undeliverable|read:).*")
and not any(attachments, .content_type == "message/delivery-status")

// if the "References" is in the body of the message, it's probably a bounce
and not any(headers.references, strings.contains(body.html.display_text, .))
and (
  (length(headers.references) == 0 and headers.in_reply_to is null)
  or (
    not strings.istarts_with(subject.subject, "re:")
    and headers.in_reply_to is null
    and not any(headers.hops, strings.ilike(.signature.headers, "*:reply-to"))
  )
)
and any(attachments,
        (.content_type == "message/rfc822" or .file_extension in ('eml'))
        and any(file.explode(.),
                // suspicious strings found in javascript
                length(filter(.scan.javascript.strings,
                              strings.ilike(.,
                                            "*username*",
                                            "*login-form*",
                                            "*email-form*",
                                            "*Incorrect password. Please try again.*",
                                            "*Password Incomplete, please try again*"
                              )
                       )
                ) >= 3
                or (

                  // suspicious strings found outside of javascript, but binexplode'd file still of HTML type
                  .flavors.mime in~ ("text/html", "text/plain")
                  and 3 of (
                    any(.scan.strings.strings, strings.ilike(., "*username*")),
                    any(.scan.strings.strings, strings.ilike(., "*login-form*")),
                    any(.scan.strings.strings, strings.ilike(., "*email-form*")),
                    any(.scan.strings.strings,
                        strings.ilike(.,
                                      "*Incorrect password. Please try again.*"
                        )
                    ),
                    any(.scan.strings.strings,
                        strings.ilike(.,
                                      "*Password Incomplete, please try again*"
                        )
                    )
                  )
                )
                or 

                // Known phishing obfuscation
                2 of (
                  // Enter password
                  any(.scan.strings.strings,
                      strings.ilike(.,
                                    "*Enter passwor&#100*"
                      )
                  ),
                  // Forgotten my password
                  any(.scan.strings.strings,
                      strings.ilike(.,
                                    "*Forgotten my passwor&#100*"
                      )
                  ),
                  // Sign in
                  any(.scan.strings.strings,
                      strings.ilike(.,
                                    "*Sign i&#110*"
                      )
                  )
                )
        )
)

Detection logic

Scope: inbound message.

Attached EML file contains an HTML attachment with suspicious login indicators. Known credential theft technique.

  1. inbound message
  2. not:
    • sender.email.local_part matches any of 3 patterns
      • *postmaster*
      • *mailer-daemon*
      • *administrator*
  3. not:
    • subject.subject matches '(undeliverable|read:).*'
  4. not:
    • any of attachments where:
      • .content_type is 'message/delivery-status'
  5. not:
    • any of headers.references where:
      • strings.contains(body.html.display_text)
  6. any of:
    • all of:
      • length(headers.references) is 0
      • headers.in_reply_to is missing
    • all of:
      • not:
        • subject.subject starts with 're:'
      • headers.in_reply_to is missing
      • not:
        • any of headers.hops where:
          • .signature.headers matches '*:reply-to'
  7. any of attachments where all hold:
    • any of:
      • .content_type is 'message/rfc822'
      • .file_extension in ('eml')
    • any of file.explode(.) where any holds:
      • length(filter(.scan.javascript.strings, strings.ilike(., '*username*', '*login-form*', '*email-form*', '*Incorrect password. Please try again.*', '*Password Incomplete, please try again*'))) ≥ 3
      • all of:
        • .flavors.mime in ('text/html', 'text/plain')
        • at least 3 of:
          • any of .scan.strings.strings where:
            • . matches '*username*'
          • any of .scan.strings.strings where:
            • . matches '*login-form*'
          • any of .scan.strings.strings where:
            • . matches '*email-form*'
          • any of .scan.strings.strings where:
            • . matches '*Incorrect password. Please try again.*'
          • any of .scan.strings.strings where:
            • . matches '*Password Incomplete, please try again*'
      • at least 2 of:
        • any of .scan.strings.strings where:
          • . matches '*Enter passwor&#100*'
        • any of .scan.strings.strings where:
          • . matches '*Forgotten my passwor&#100*'
        • any of .scan.strings.strings where:
          • . matches '*Sign i&#110*'

Inspects: attachments[].content_type, attachments[].file_extension, body.html.display_text, headers.hops, headers.hops[].signature.headers, headers.in_reply_to, headers.references, sender.email.local_part, subject.subject, type.inbound. Sensors: file.explode, regex.imatch, strings.contains, strings.ilike, strings.istarts_with, strings.like.

Indicators matched (19)

FieldMatchValue
strings.likesubstring*postmaster*
strings.likesubstring*mailer-daemon*
strings.likesubstring*administrator*
regex.imatchregex(undeliverable|read:).*
attachments[].content_typeequalsmessage/delivery-status
strings.istarts_withprefixre:
strings.ilikesubstring*:reply-to
attachments[].content_typeequalsmessage/rfc822
attachments[].file_extensionmembereml
strings.ilikesubstring*username*
strings.ilikesubstring*login-form*
strings.ilikesubstring*email-form*
7 more
strings.ilikesubstring*Incorrect password. Please try again.*
strings.ilikesubstring*Password Incomplete, please try again*
file.explode(attachments[])[].flavors.mimemembertext/html
file.explode(attachments[])[].flavors.mimemembertext/plain
strings.ilikesubstring*Enter passwor&#100*
strings.ilikesubstring*Forgotten my passwor&#100*
strings.ilikesubstring*Sign i&#110*