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(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 ) ) )
  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
  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"
   macro "any(filter(attachments,\n               .content_type == \"message/rfc822\" or .file_extension in ('eml')\n        ),\n        // inspect attachments in nested EML\n        any(file.parse_eml(.).attachments,\n            any(file.explode(.),\n                (\n                  regex.icontains(.scan.ocr.raw, 'scan|camera')\n                  and regex.icontains(.scan.ocr.raw, '\\bQR\\b|Q\\.R\\.|barcode')\n                )\n                or .scan.qr.type == \"url\" and .scan.qr.url.domain.valid\n            )\n        )\n        // inspect nested EML in body.current_thread\n        or (\n          regex.icontains(file.parse_eml(.).body.current_thread.text,\n                          'scan|camera'\n          )\n          and regex.icontains(file.parse_eml(.).body.current_thread.text,\n                              '\\bQR\\b|Q\\.R\\.|barcode'\n          )\n        )\n        // or there is a QR code found within the body of the nested body\n        or (\n          beta.scan_qr(file.html_screenshot(file.parse_eml(.).body.html)).found\n          and any(beta.scan_qr(file.html_screenshot(file.parse_eml(.).body.html)\n                  ).items,\n                  .type == \"url\" and .url.domain.valid\n          )\n        )\n)"

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 corpus 3 (mql 3)
  • salary
  • statement corpus 2 (mql 2)
  • 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 corpus 1212 (mql 1212)
field:"type.inbound" kind:eq value:"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"

Back to all Sublime MQL rules