Detection rules › Sublime MQL

Impersonation: SharePoint reply header anomaly

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

Detects messages with SharePoint reply headers that lack standard reply characteristics and contain inconsistencies in thread elements and recipient patterns

Threat classification

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

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesSocial engineering, Impersonation: Brand, Evasion, Spoofing

Event coverage

Rule body MQL

type.inbound
// appears to be a reply 
and strings.istarts_with(headers.in_reply_to, '<Share-')
and strings.ends_with(headers.in_reply_to, '@odspnotify>')
and any([body.current_thread.text, body.plain.raw],
        strings.ilike(.,
                      "*shared a file with you*",
                      "*shared with you*",
                      "*invited you to access a file*",
                      "*received a document*",
                      "*shared a document*",
                      "*shared a new document*",
                      "*shared this document*"
        )
)
and ( // but lacks other reply elements
  not (
    strings.istarts_with(subject.subject, "RE:")
    or strings.istarts_with(subject.subject, "RES:")
    or strings.istarts_with(subject.subject, "R:")
    or strings.istarts_with(subject.subject, "ODG:")
    or strings.istarts_with(subject.subject,
                            "答复:"
    ) // response
    or strings.istarts_with(subject.subject,
                            "回复:"
    ) // reply
    or strings.istarts_with(subject.subject, "AW:")
    or strings.istarts_with(subject.subject, "TR:")
    or strings.istarts_with(subject.subject, "FWD:")
    or strings.istarts_with(subject.subject, "Resposta automática:")
    or strings.istarts_with(subject.subject, "Automatische Antwort:")
    or strings.istarts_with(subject.subject, "Autosvar:")
    or regex.icontains(subject.subject,
                       '^(?:(?:\[[^\]]+\]\s?|EXT(?:ERNAL)?\s?){0,3}|[[:punct:]]{0,3}\w+[[:punct:]]{0,3}\s)(?:r[ev]|fwd?|tr|aw|automat(ic|ed) reply)\s?:'
    )
  )
  // the sender is the recipient 
  // or the recipients are hidden
  or (
    (
      sender.email.email in map(recipients.to, .email.email)
      and sum([
                length(recipients.bcc),
                length(recipients.to),
                length(recipients.cc)
              ]
      ) == 1
    )
    or length(recipients.to) == 0
    or all(recipients.to, .email.email is null or .email.email == "")
  )
)

// lack a previous thread with sharepoint stuff
and not any([body.current_thread.text, body.html.display_text, body.plain.raw],
            3 of (
              strings.icontains(., "from:"),
              strings.icontains(., "to:"),
              strings.icontains(., "sent:"),
              strings.icontains(., "date:"),
              strings.icontains(., "cc:"),
              strings.icontains(., "subject:")
            )
            and regex.icontains(.,
                                '(?:from|to|sent|date|cc|subject|wrote):.*shared with you',
                                '(?:from|to|sent|date|cc|subject|wrote):.*shared the folder .* with you',
                                '(?:from|to|sent|date|cc|subject|wrote):.*invited you to view a file',
            )
)

// negate bouncebacks and undeliverables
and not any(attachments,
            .content_type in (
              "message/global-delivery-status",
              "message/delivery-status"
            )
)

Detection logic

Scope: inbound message.

Detects messages with SharePoint reply headers that lack standard reply characteristics and contain inconsistencies in thread elements and recipient patterns

  1. inbound message
  2. headers.in_reply_to starts with '<Share-'
  3. headers.in_reply_to ends with '@odspnotify>'
  4. any of [body.current_thread.text, body.plain.raw] where:
    • . matches any of 7 patterns
      • *shared a file with you*
      • *shared with you*
      • *invited you to access a file*
      • *received a document*
      • *shared a document*
      • *shared a new document*
      • *shared this document*
  5. any of:
    • none of:
      • subject.subject starts with 'RE:'
      • subject.subject starts with 'RES:'
      • subject.subject starts with 'R:'
      • subject.subject starts with 'ODG:'
      • subject.subject starts with '答复:'
      • subject.subject starts with '回复:'
      • subject.subject starts with 'AW:'
      • subject.subject starts with 'TR:'
      • subject.subject starts with 'FWD:'
      • subject.subject starts with 'Resposta automática:'
      • subject.subject starts with 'Automatische Antwort:'
      • subject.subject starts with 'Autosvar:'
      • subject.subject matches '^(?:(?:\\[[^\\]]+\\]\\s?|EXT(?:ERNAL)?\\s?){0,3}|[[:punct:]]{0,3}\\w+[[:punct:]]{0,3}\\s)(?:r[ev]|fwd?|tr|aw|automat(ic|ed) reply)\\s?:'
    • any of:
      • all of:
        • sender.email.email in map(recipients.to, .email.email)
        • sum([length(recipients.bcc), length(recipients.to), length(recipients.cc)]) is 1
      • length(recipients.to) is 0
      • all of recipients.to where any holds:
        • .email.email is missing
        • .email.email is ''
  6. not:
    • any of [body.current_thread.text, body.html.display_text, body.plain.raw] where all hold:
      • at least 3 of 6: . contains any of 6 patterns
        • from:
        • to:
        • sent:
        • date:
        • cc:
        • subject:
      • . matches any of 3 patterns
        • (?:from|to|sent|date|cc|subject|wrote):.*shared with you
        • (?:from|to|sent|date|cc|subject|wrote):.*shared the folder .* with you
        • (?:from|to|sent|date|cc|subject|wrote):.*invited you to view a file
  7. not:
    • any of attachments where:
      • .content_type in ('message/global-delivery-status', 'message/delivery-status')

Inspects: attachments[].content_type, body.current_thread.text, body.html.display_text, body.plain.raw, headers.in_reply_to, recipients.bcc, recipients.cc, recipients.to, recipients.to[].email.email, sender.email.email, subject.subject, type.inbound. Sensors: regex.icontains, strings.ends_with, strings.icontains, strings.ilike, strings.istarts_with.

Indicators matched (34)

FieldMatchValue
strings.istarts_withprefix<Share-
strings.ends_withsuffix@odspnotify>
strings.ilikesubstring*shared a file with you*
strings.ilikesubstring*shared with you*
strings.ilikesubstring*invited you to access a file*
strings.ilikesubstring*received a document*
strings.ilikesubstring*shared a document*
strings.ilikesubstring*shared a new document*
strings.ilikesubstring*shared this document*
strings.istarts_withprefixRE:
strings.istarts_withprefixRES:
strings.istarts_withprefixR:
22 more
strings.istarts_withprefixODG:
strings.istarts_withprefix答复:
strings.istarts_withprefix回复:
strings.istarts_withprefixAW:
strings.istarts_withprefixTR:
strings.istarts_withprefixFWD:
strings.istarts_withprefixResposta automática:
strings.istarts_withprefixAutomatische Antwort:
strings.istarts_withprefixAutosvar:
regex.icontainsregex^(?:(?:\[[^\]]+\]\s?|EXT(?:ERNAL)?\s?){0,3}|[[:punct:]]{0,3}\w+[[:punct:]]{0,3}\s)(?:r[ev]|fwd?|tr|aw|automat(ic|ed) reply)\s?:
recipients.to[].email.emailequals
strings.icontainssubstringfrom:
strings.icontainssubstringto:
strings.icontainssubstringsent:
strings.icontainssubstringdate:
strings.icontainssubstringcc:
strings.icontainssubstringsubject:
regex.icontainsregex(?:from|to|sent|date|cc|subject|wrote):.*shared with you
regex.icontainsregex(?:from|to|sent|date|cc|subject|wrote):.*shared the folder .* with you
regex.icontainsregex(?:from|to|sent|date|cc|subject|wrote):.*invited you to view a file
attachments[].content_typemembermessage/global-delivery-status
attachments[].content_typemembermessage/delivery-status