Detection rules › Sublime MQL

Sublime MQL rules: comp

Compensation review with QR code in attached EML

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

Detects inbound messages containing compensation-related terms (salary, bonus, merit, etc.) combined with review/change language that include EML attachments containing QR codes or barcodes in scanned documents.

Threat classification

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

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesQR code, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • attachments
  • headers
  • headers.auth_summary
  • headers.domains
  • sender.email
  • subject
  • type

Rule body

type.inbound

// the subject contains pay related items
and (
  strings.icontains(subject.subject, 'salary')
  or regex.icontains(subject.subject, 'comp(?:liance|ensation|\b)')
  or strings.icontains(subject.subject, 'remuneration')
  or regex.icontains(subject.subject, '\bpay(?:roll|\b)')
  or strings.icontains(subject.subject, 'bonus')
  or strings.icontains(subject.subject, 'incentive')
  or strings.icontains(subject.subject, 'merit')
  or strings.icontains(subject.subject, 'handbook')
  or strings.icontains(subject.subject, 'benefits')
)
// subjects include review/updates/changes
and (
  strings.icontains(subject.subject, 'review')
  or strings.icontains(subject.subject, 'Summary')
  or strings.icontains(subject.subject, 'evaluation')
  or regex.icontains(subject.subject, 'eval\b')
  or strings.icontains(subject.subject, 'assessment')
  or strings.icontains(subject.subject, 'appraisal')
  or strings.icontains(subject.subject, 'feedback')
  or strings.icontains(subject.subject, 'performance')
  or strings.icontains(subject.subject, 'adjustment')
  or strings.icontains(subject.subject, 'statement')
  or strings.icontains(subject.subject, 'increase')
  or strings.icontains(subject.subject, 'raise')
  or strings.icontains(subject.subject, 'change')
  or strings.icontains(subject.subject, 'modification')
  or strings.icontains(subject.subject, 'distribution')
  or strings.icontains(subject.subject, 'Disbursement')
  or regex.icontains(subject.subject, 'revis(?:ed|ion)')
  or regex.icontains(subject.subject, 'amend(?:ed|ment)')
  or strings.icontains(subject.subject, 'update')
)
and any(filter(attachments,
               .content_type == "message/rfc822" or .file_extension in ('eml')
        ),
        // inspect attachments in nested EML
        any(file.parse_eml(.).attachments,
            any(file.explode(.),
                (
                  regex.icontains(.scan.ocr.raw, 'scan|camera')
                  and regex.icontains(.scan.ocr.raw, '\bQR\b|Q\.R\.|barcode')
                )
                or .scan.qr.type == "url" and .scan.qr.url.domain.valid
            )
        )
        // inspect nested EML in body.current_thread
        or (
          regex.icontains(file.parse_eml(.).body.current_thread.text,
                          'scan|camera'
          )
          and regex.icontains(file.parse_eml(.).body.current_thread.text,
                              '\bQR\b|Q\.R\.|barcode'
          )
        )
        // or there is a QR code found within the body of the nested body
        or (
          beta.scan_qr(file.html_screenshot(file.parse_eml(.).body.html)).found
          and any(beta.scan_qr(file.html_screenshot(file.parse_eml(.).body.html)
                  ).items,
                  .type == "url" and .url.domain.valid
          )
        )
)

// negate instances where proofpoint sends a review of a reported message via analyzer 
and not (
  sender.email.email == "analyzer@analyzer.securityeducation.com"
  and any(headers.domains, .root_domain == "pphosted.com")
  and headers.auth_summary.spf.pass
  and headers.auth_summary.dmarc.pass
)

Detection logic

Scope: inbound message.

Detects inbound messages containing compensation-related terms (salary, bonus, merit, etc.) combined with review/change language that include EML attachments containing QR codes or barcodes in scanned documents.

  1. inbound message
  2. any of:
    • subject.subject contains 'salary'
    • subject.subject matches 'comp(?:liance|ensation|\\b)'
    • subject.subject contains 'remuneration'
    • subject.subject matches '\\bpay(?:roll|\\b)'
    • subject.subject contains 'bonus'
    • subject.subject contains 'incentive'
    • subject.subject contains 'merit'
    • subject.subject contains 'handbook'
    • subject.subject contains 'benefits'
  3. any of:
    • subject.subject contains 'review'
    • subject.subject contains 'Summary'
    • subject.subject contains 'evaluation'
    • subject.subject matches 'eval\\b'
    • subject.subject contains 'assessment'
    • subject.subject contains 'appraisal'
    • subject.subject contains 'feedback'
    • subject.subject contains 'performance'
    • subject.subject contains 'adjustment'
    • subject.subject contains 'statement'
    • subject.subject contains 'increase'
    • subject.subject contains 'raise'
    • subject.subject contains 'change'
    • subject.subject contains 'modification'
    • subject.subject contains 'distribution'
    • subject.subject contains 'Disbursement'
    • subject.subject matches 'revis(?:ed|ion)'
    • subject.subject matches 'amend(?:ed|ment)'
    • subject.subject contains 'update'
  4. any of filter(attachments) where any holds:
    • any of file.parse_eml(.).attachments where:
      • any of file.explode(.) where any holds:
        • all of:
          • .scan.ocr.raw matches 'scan|camera'
          • .scan.ocr.raw matches '\\bQR\\b|Q\\.R\\.|barcode'
        • all of:
          • .scan.qr.type is 'url'
          • .scan.qr.url.domain.valid
    • all of:
      • file.parse_eml(.).body.current_thread.text matches 'scan|camera'
      • file.parse_eml(.).body.current_thread.text matches '\\bQR\\b|Q\\.R\\.|barcode'
    • all of:
      • beta.scan_qr(file.html_screenshot(file.parse_eml(.).body.html)).found
      • any of beta.scan_qr(file.html_screenshot(file.parse_eml(.).body.html)).items where all hold:
        • .type is 'url'
        • .url.domain.valid
  5. not:
    • all of:
      • sender.email.email is 'analyzer@analyzer.securityeducation.com'
      • any of headers.domains where:
        • .root_domain is 'pphosted.com'
      • headers.auth_summary.spf.pass
      • headers.auth_summary.dmarc.pass

Inspects: attachments[].content_type, attachments[].file_extension, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, headers.domains, headers.domains[].root_domain, sender.email.email, subject.subject, type.inbound. Sensors: beta.scan_qr, file.explode, file.html_screenshot, file.parse_eml, regex.icontains, strings.icontains.

Indicators matched (34)

FieldMatchValue
strings.icontainssubstringsalary
regex.icontainsregexcomp(?:liance|ensation|\b)
strings.icontainssubstringremuneration
regex.icontainsregex\bpay(?:roll|\b)
strings.icontainssubstringbonus
strings.icontainssubstringincentive
strings.icontainssubstringmerit
strings.icontainssubstringhandbook
strings.icontainssubstringbenefits
strings.icontainssubstringreview
strings.icontainssubstringSummary
strings.icontainssubstringevaluation
22 more
regex.icontainsregexeval\b
strings.icontainssubstringassessment
strings.icontainssubstringappraisal
strings.icontainssubstringfeedback
strings.icontainssubstringperformance
strings.icontainssubstringadjustment
strings.icontainssubstringstatement
strings.icontainssubstringincrease
strings.icontainssubstringraise
strings.icontainssubstringchange
strings.icontainssubstringmodification
strings.icontainssubstringdistribution
strings.icontainssubstringDisbursement
regex.icontainsregexrevis(?:ed|ion)
regex.icontainsregexamend(?:ed|ment)
strings.icontainssubstringupdate
attachments[].content_typeequalsmessage/rfc822
attachments[].file_extensionmembereml
regex.icontainsregexscan|camera
regex.icontainsregex\bQR\b|Q\.R\.|barcode
file.explode(file.parse_eml(filter(attachments)[]).attachments[])[].scan.qr.typeequalsurl
beta.scan_qr(file.html_screenshot(file.parse_eml(filter(attachments)[]).body.html)).items[].typeequalsurl

Stages and Predicates

Stage 1: mql_rule

and
  any(filter(attachments))
    or
      any(file.parse_eml(filter(attachments)).attachments)
        any(file.explode(file.parse_eml(filter(attachments)).attachments))
          or
            and
              file.explode(file.parse_eml(filter(attachments)[]).attachments[])[].scan.ocr.raw regex_match "\\bQR\\b|Q\\.R\\.|barcode"
              file.explode(file.parse_eml(filter(attachments)[]).attachments[])[].scan.ocr.raw regex_match "scan|camera"
            and
              file.explode(file.parse_eml(filter(attachments)[]).attachments[])[].scan.qr.type eq "url"
              file.explode(file.parse_eml(filter(attachments)[]).attachments[])[].scan.qr.url.domain.valid eq "true"
      and
        any(beta.scan_qr(file.html_screenshot(file.parse_eml(filter(attachments)).body.html)).items)
          and
            beta.scan_qr(file.html_screenshot(file.parse_eml(filter(attachments)[]).body.html)).items[].type eq "url"
            beta.scan_qr(file.html_screenshot(file.parse_eml(filter(attachments)[]).body.html)).items[].url.domain.valid eq "true"
        beta.scan_qr func_call "beta.scan_qr(file.html_screenshot(file.parse_eml(filter(attachments)[]).body.html)).found"
      and
        file.parse_eml(filter(attachments)[]).body.current_thread.text regex_match "\\bQR\\b|Q\\.R\\.|barcode"
        file.parse_eml(filter(attachments)[]).body.current_thread.text regex_match "scan|camera"
  not
    and
      any(headers.domains)
        headers.domains.root_domain eq "pphosted.com"
      headers.auth_summary.dmarc.pass eq "true"
      headers.auth_summary.spf.pass eq "true"
      sender.email.email eq "analyzer@analyzer.securityeducation.com"
  or
    subject.subject contains "Disbursement"
    subject.subject contains "Summary"
    subject.subject contains "adjustment"
    subject.subject contains "appraisal"
    subject.subject contains "assessment"
    subject.subject contains "change"
    subject.subject contains "distribution"
    subject.subject contains "evaluation"
    subject.subject contains "feedback"
    subject.subject contains "increase"
    subject.subject contains "modification"
    subject.subject contains "performance"
    subject.subject contains "raise"
    subject.subject contains "review"
    subject.subject contains "statement"
    subject.subject contains "update"
    subject.subject regex_match "amend(?:ed|ment)"
    subject.subject regex_match "eval\\b"
    subject.subject regex_match "revis(?:ed|ion)"
  or
    subject.subject contains "benefits"
    subject.subject contains "bonus"
    subject.subject contains "handbook"
    subject.subject contains "incentive"
    subject.subject contains "merit"
    subject.subject contains "remuneration"
    subject.subject contains "salary"
    subject.subject regex_match "\\bpay(?:roll|\\b)"
    subject.subject regex_match "comp(?:liance|ensation|\\b)"
  type.inbound eq "true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
headers.domainsarray_any(no value, null check)excludes:headers.domains
headers.auth_summary.dmarc.passeqtrueexcludes:headers.auth_summary.dmarc.pass field:"headers.auth_summary.dmarc.pass" value:"true"
headers.auth_summary.spf.passeqtrueexcludes:headers.auth_summary.spf.pass field:"headers.auth_summary.spf.pass" value:"true"
sender.email.emaileqanalyzer@analyzer.securityeducation.comexcludes:sender.email.email field:"sender.email.email" value:"analyzer@analyzer.securityeducation.com"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
subject.subjectcontains
  • Disbursement
  • Summary
  • adjustment
  • appraisal
  • assessment
  • benefits
  • bonus
  • change
  • distribution
  • evaluation
  • feedback
  • handbook
  • incentive
  • increase
  • merit
  • modification
  • performance
  • raise
  • remuneration
  • review
  • salary
  • statement
  • update
field:"subject.subject" kind:contains
subject.subjectregex_match
  • \bpay(?:roll|\b)
  • amend(?:ed|ment)
  • comp(?:liance|ensation|\b)
  • eval\b
  • revis(?:ed|ion)
field:"subject.subject" kind:regex_match
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"