Detection rules › Sublime MQL

Scam: Piano giveaway

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

This rule is designed to identify and mitigate a specific type of fraudulent activity commonly targeted at educational institutions. This rule operates by analyzing incoming email content for certain characteristics indicative of a scam involving the offer of a free piano, often framed within the context of downsizing or a giveaway.

Threat classification

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

CategoryValues
Attack typesBEC/Fraud
Tactics and techniquesFree email provider

Event coverage

Rule body MQL

length(body.links) < 10
and length(body.current_thread.text) < 2000
and (
  // body detection
  // be sure to update the attachment detection regexes too!
  (
    (
      // items and brands
      // Guitars
      regex.icontains(body.current_thread.text,
                      '(?:Gibson|Fender|Lowden|Martin|Taylor|Ibanez|Knaggs)\s*[^\r\n]{0,50}\s*guitar',
                      'guitar\s*[^\r\n]{0,50}\s*(?:Gibson|Fender|Lowden|Martin|Taylor|Ibanez|Knaggs)',
      )
      // Piano/Keyboards
      or regex.icontains(body.current_thread.text,
                         '(?:Yamaha|Kawai|Baldwin|Roland|Stei?nway(?: (?:&|and) Sons?)?|\d{4})\s*[^\r\n]{0,50}(?:baby.grand|piano|baby.grand.piano|keyboard)',
                         '(?:baby.grand|piano|baby.grand.piano|keyboard)\s*[^\r\n]{0,50}(?:Yamaha|Kawai|Baldwin|Roland|Stei?nway(?: (?:&|and) Sons?)?|\d{4})',
                         // strong indicators for generalized instrument
                         '(?:piano|keyboard)\s*[^\r\n]{0,50}(?:available|sale|rehome|gift)'
      )
      // Violins & Orchestral 
      or regex.icontains(body.current_thread.text,
                         '(?:Stradivarius|Guarneri|Yamaha|Stentor|Eastman|Cremona|Cecilio|Mendini)\s*[^\r\n]{0,50}(violin|viola|cello|celli)',
      )
      // brass/wind/woodwinds
      or regex.icontains(body.current_thread.text,
                         '(?:Bach|Yamaha|Selmer|Conn|King|Jupiter|Buffet Crampon |Pearl)\s*[^\r\n]{0,50}(trombone|trumpet|saxophone|clarinet|flute)'
      )

      // generic
      or strings.ilike(body.current_thread.text,
                       '* musical instruments *',
                       '* instrument as a gift*'
      )
    )
    and (
      // often a person is moving
      strings.ilike(body.current_thread.text,
                    '* downsizing *',
                    '* relocating *',
                    '* to relocate *',
                    '* relocation *',
                    '* moving *'
      )
      or strings.ilike(body.current_thread.text,
                       '* give away*',
                       '* generously offering *',
                       '*a loving home*',
                       '*a good home*',
                       '*find a new home *',
                       '*rehome these instruments *',
                       '* free donation*',
                       '*free*member of the music community*'
      )
      // generally someone died
      or regex.icontains(body.current_thread.text,
                         'inherited instruments',
                         'late (?:husband|father|dad|wife|mother|mom)',
                         '(?:husband|father|dad|wife|mother|mom)[^\r\n]{0,50}estate'
      )
      // passion/love for the item
      or strings.ilike(body.current_thread.text,
                       '* genuinely cherish*',
                       '* cherished possessions*',
                       '* passionate instrument*',
                       '* music lover*',
                       '* had a passion for music*',
                       '* appreciates music*',
                       "* special piece*",
                       "* a lot of meaning*",
                       "* profound sentimental*",
                       '* will cherish*',
                       '* passion for music*',
                       '* treasured items *'
      )
    )
    and (
      // it talks about a shipping fee upfront
      regex.icontains(body.current_thread.text,
                      'shipping (?:fee|cost|arrangement)',
                      '(?:responsible|pay) for shipping',
                      'no (?:local\s)?pick.?up',
                      '(?:local\s)?pick.?up.{0,50}not available',
                      'delivery only',
                      'moving company'
      )
      // recipient or someone they know might have an interest
      or strings.ilike(body.current_thread.text,
                       '* if you will take it *',
                       '* or have someone *',
                       '* indicate your interest *',
                       '* to someone you know *',
                       '* know someone who *',
                       '* someone you know would *',
                       '* someone who will *',
                       '* someone who truly *',
                       '* anyone you know *',
      )
      or regex.icontains(body.current_thread.text,
                         'if you[^\r\n]{0,20}(?:(?:might|will|would) be|are)[^\r\n]{0,20}interested',
                         '(?:any|some)one[^\r\n]{0,20}(is|will|would|might be)[^\r\n]{0,20}interested',
                         'who (?:will|would|might) appreciate',
      )
      or (
        // there's an email in the body 
        any(regex.extract(body.current_thread.text,
                          "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
            ),
            strings.parse_email(.full_match).domain.domain in $free_email_providers
            or strings.parse_email(.full_match).domain.root_domain in $free_email_providers
        )
        // reply-to doesn't match sender
        or (
          length(headers.reply_to) > 0
          and sender.email.email not in map(headers.reply_to, .email.email)
        )
        // there are no recipients
        or length(recipients.to) == 0
        // redirects to a phone number
        or regex.icontains(body.current_thread.text,
                           '(?:call|contact|text)[^\r\n]{0,50} at'
        )
        or regex.icontains(body.current_thread.text,
                           '(?:private|personal) (?:e-?)?mail'
        )
        or strings.icontains(body.current_thread.text, ' kindly ')
        or strings.icontains(body.current_thread.text, ' (kindly ')
      )
    )
  )
  or (
    any(filter(attachments, .size < 10000),
        (
          // items and brands
          // Guitars
          regex.icontains(file.parse_text(.).text,
                          '(?:Gibson|Fender|Lowden|Martin|Taylor|Ibanez|Knaggs)\s*[^\r\n]{0,50}\s*guitar',
                          'guitar\s*[^\r\n]{0,50}\s*(?:Gibson|Fender|Lowden|Martin|Taylor|Ibanez|Knaggs)',
          )
          // Piano/Keyboards
          or regex.icontains(file.parse_text(.).text,
                             '(?:Yamaha|Kawai|Baldwin|Roland|Stei?nway(?: (?:&|and) Sons?)?)\s*[^\r\n]{0,50}(?:baby.grand|piano|baby.grand.piano|keyboard)',
                             '(?:baby.grand|piano|baby.grand.piano|keyboard)\s*[^\r\n]{0,50}(?:Yamaha|Kawai|Baldwin|Roland|Stei?nway(?: (?:&|and) Sons?)?|\d{4})',
                             // strong indicators for generalized instrument
                             '(?:piano|keyboard)\s*[^\r\n]{0,50}(?:available|sale|rehome|gift)'
          )
          // Violins & Orchestral 
          or regex.icontains(file.parse_text(.).text,
                             '(?:Stradivarius|Guarneri|Yamaha|Stentor|Eastman|Cremona|Cecilio|Mendini)\s*[^\r\n]{0,50}(violin|viola|cello|celli)',
          )
          // brass/wind/woodwinds
          or regex.icontains(file.parse_text(.).text,
                             '(?:Bach|Yamaha|Selmer|Conn|King|Jupiter|Buffet Crampon |Pearl)\s*[^\r\n]{0,50}(trombone|trumpet|saxophone|clarinet|flute)'
          )

          // generic
          or strings.ilike(file.parse_text(.).text,
                           '* musical instruments *',
                           '* instrument as a gift*'
          )
        )
        and (
          // often a person is moving
          strings.ilike(file.parse_text(.).text,
                        '* downsizing *',
                        '* relocating *',
                        '* to relocate *',
                        '* relocation *',
          )
          or strings.ilike(file.parse_text(.).text,
                           '* give away*',
                           '* generously offering *',
                           '*a loving home*',
                           '*a good home*',
                           '*find a new home *',
                           '*rehome these instruments *',
                           '* free donation*',
                           '*free*member of the music community*'
          )
          // generally someone died
          or regex.icontains(file.parse_text(.).text,
                             'inherited instruments',
                             'late (?:husband|father|dad|wife|mother|mom)',
                             '(?:husband|father|dad|wife|mother|mom)[^\r\n]{0,50}estate'
          )
          // passion/love for the item/music
          or strings.ilike(file.parse_text(.).text,
                           '* genuinely cherish*',
                           '* cherished possessions*',
                           '* passionate instrument*',
                           '* music lover*',
                           '* had a passion for music*',
                           '* appreciates music*',
                           "* special piece*",
                           "* a lot of meaning*",
                           "* profound sentimental*",
                           '* will cherish*',
                           '* passion for music*',
                           '* treasured items *'
          )
        )
        and (
          // it talks about a shipping fee upfront
          regex.icontains(file.parse_text(.).text,
                          'shipping (?:fee|cost|arrangement)',
                          '(?:responsible|pay) for shipping',
                          'no (?:local\s)?pick.?up',
                          '(?:local\s)?pick.?up.{0,50}not available',
                          'delivery only',
                          'moving company'
          )
          or strings.ilike(file.parse_text(.).text,
                           '* if you will take it *',
                           '* or have someone *',
                           '* indicate your interest *',
                           '* to someone you know *',
                           '* know someone who *',
                           '* someone you know would *',
                           '* someone who will *',
                           '* anyone you know *',
          )
          or regex.icontains(file.parse_text(.).text,
                             'if you[^\r\n]{0,20}(?:(?:might|will|would) be|are)[^\r\n]{0,20}interested',
                             '(?:any|some)one[^\r\n]{0,20}(is|will|would|might be)[^\r\n]{0,20}interested',
                             'who (?:will|would|might) appreciate',
          )
          // there's an email in the body 
          or any(regex.extract(file.parse_text(.).text,
                               "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
                 ),
                 strings.parse_email(.full_match).domain.domain in $free_email_providers
                 or strings.parse_email(.full_match).domain.root_domain in $free_email_providers
          )

          // reply-to doesn't match sender
          or (
            length(headers.reply_to) > 0
            and sender.email.email not in map(headers.reply_to, .email.email)
          )
          // there are no recipients
          or length(recipients.to) == 0
          // redirects to a phone number
          or regex.icontains(file.parse_text(.).text,
                             '(?:call|contact|text)[^\r\n]{0,50} at'
          )
          or regex.icontains(file.parse_text(.).text,
                             '(?:private|personal) (?:e-?)?mail'
          )
          or strings.icontains(file.parse_text(.).text, ' kindly ')
          or strings.icontains(file.parse_text(.).text, ' (kindly ')
        )
    )
  )
)

// not high trust sender domains
and not (
  sender.email.domain.root_domain in $high_trust_sender_root_domains
  and headers.auth_summary.dmarc.pass
)
and not sender.email.domain.root_domain in (
  'ridleyacademy.com', // person provides piano lessons and offers to give a Roland baby-grand away
  'mountainpiano.com' // legitimate piano moving company in Denver 
)

Detection logic

This rule is designed to identify and mitigate a specific type of fraudulent activity commonly targeted at educational institutions. This rule operates by analyzing incoming email content for certain characteristics indicative of a scam involving the offer of a free piano, often framed within the context of downsizing or a giveaway.

  1. length(body.links) < 10
  2. length(body.current_thread.text) < 2000
  3. any of:
    • all of:
      • body.current_thread.text matches any of 9 patterns
        • (?:Gibson|Fender|Lowden|Martin|Taylor|Ibanez|Knaggs)\s*[^\r\n]{0,50}\s*guitar
        • guitar\s*[^\r\n]{0,50}\s*(?:Gibson|Fender|Lowden|Martin|Taylor|Ibanez|Knaggs)
        • (?:Yamaha|Kawai|Baldwin|Roland|Stei?nway(?: (?:&|and) Sons?)?|\d{4})\s*[^\r\n]{0,50}(?:baby.grand|piano|baby.grand.piano|keyboard)
        • (?:baby.grand|piano|baby.grand.piano|keyboard)\s*[^\r\n]{0,50}(?:Yamaha|Kawai|Baldwin|Roland|Stei?nway(?: (?:&|and) Sons?)?|\d{4})
        • (?:piano|keyboard)\s*[^\r\n]{0,50}(?:available|sale|rehome|gift)
        • (?:Stradivarius|Guarneri|Yamaha|Stentor|Eastman|Cremona|Cecilio|Mendini)\s*[^\r\n]{0,50}(violin|viola|cello|celli)
        • (?:Bach|Yamaha|Selmer|Conn|King|Jupiter|Buffet Crampon |Pearl)\s*[^\r\n]{0,50}(trombone|trumpet|saxophone|clarinet|flute)
        • * musical instruments *
        • * instrument as a gift*
      • body.current_thread.text matches any of 28 patterns
        • * downsizing *
        • * relocating *
        • * to relocate *
        • * relocation *
        • * moving *
        • * give away*
        • * generously offering *
        • *a loving home*
        • *a good home*
        • *find a new home *
        • *rehome these instruments *
        • * free donation*
        • *free*member of the music community*
        • inherited instruments
        • late (?:husband|father|dad|wife|mother|mom)
        • (?:husband|father|dad|wife|mother|mom)[^\r\n]{0,50}estate
        • * genuinely cherish*
        • * cherished possessions*
        • * passionate instrument*
        • * music lover*
        • * had a passion for music*
        • * appreciates music*
        • * special piece*
        • * a lot of meaning*
        • * profound sentimental*
        • * will cherish*
        • * passion for music*
        • * treasured items *
      • any of:
        • body.current_thread.text matches any of 6 patterns
          • shipping (?:fee|cost|arrangement)
          • (?:responsible|pay) for shipping
          • no (?:local\s)?pick.?up
          • (?:local\s)?pick.?up.{0,50}not available
          • delivery only
          • moving company
        • body.current_thread.text matches any of 9 patterns
          • * if you will take it *
          • * or have someone *
          • * indicate your interest *
          • * to someone you know *
          • * know someone who *
          • * someone you know would *
          • * someone who will *
          • * someone who truly *
          • * anyone you know *
        • body.current_thread.text matches any of 3 patterns
          • if you[^\r\n]{0,20}(?:(?:might|will|would) be|are)[^\r\n]{0,20}interested
          • (?:any|some)one[^\r\n]{0,20}(is|will|would|might be)[^\r\n]{0,20}interested
          • who (?:will|would|might) appreciate
        • any of:
          • any of regex.extract(body.current_thread.text) where any holds:
            • strings.parse_email(.full_match).domain.domain in $free_email_providers
            • strings.parse_email(.full_match).domain.root_domain in $free_email_providers
          • all of:
            • length(headers.reply_to) > 0
            • sender.email.email not in map(headers.reply_to, .email.email)
          • length(recipients.to) is 0
          • body.current_thread.text matches '(?:call|contact|text)[^\\r\\n]{0,50} at'
          • body.current_thread.text matches '(?:private|personal) (?:e-?)?mail'
          • body.current_thread.text contains ' kindly '
          • body.current_thread.text contains ' (kindly '
    • any of filter(attachments) where all hold:
      • file.parse_text(.).text matches any of 9 patterns
        • (?:Gibson|Fender|Lowden|Martin|Taylor|Ibanez|Knaggs)\s*[^\r\n]{0,50}\s*guitar
        • guitar\s*[^\r\n]{0,50}\s*(?:Gibson|Fender|Lowden|Martin|Taylor|Ibanez|Knaggs)
        • (?:Yamaha|Kawai|Baldwin|Roland|Stei?nway(?: (?:&|and) Sons?)?)\s*[^\r\n]{0,50}(?:baby.grand|piano|baby.grand.piano|keyboard)
        • (?:baby.grand|piano|baby.grand.piano|keyboard)\s*[^\r\n]{0,50}(?:Yamaha|Kawai|Baldwin|Roland|Stei?nway(?: (?:&|and) Sons?)?|\d{4})
        • (?:piano|keyboard)\s*[^\r\n]{0,50}(?:available|sale|rehome|gift)
        • (?:Stradivarius|Guarneri|Yamaha|Stentor|Eastman|Cremona|Cecilio|Mendini)\s*[^\r\n]{0,50}(violin|viola|cello|celli)
        • (?:Bach|Yamaha|Selmer|Conn|King|Jupiter|Buffet Crampon |Pearl)\s*[^\r\n]{0,50}(trombone|trumpet|saxophone|clarinet|flute)
        • * musical instruments *
        • * instrument as a gift*
      • file.parse_text(.).text matches any of 27 patterns
        • * downsizing *
        • * relocating *
        • * to relocate *
        • * relocation *
        • * give away*
        • * generously offering *
        • *a loving home*
        • *a good home*
        • *find a new home *
        • *rehome these instruments *
        • * free donation*
        • *free*member of the music community*
        • inherited instruments
        • late (?:husband|father|dad|wife|mother|mom)
        • (?:husband|father|dad|wife|mother|mom)[^\r\n]{0,50}estate
        • * genuinely cherish*
        • * cherished possessions*
        • * passionate instrument*
        • * music lover*
        • * had a passion for music*
        • * appreciates music*
        • * special piece*
        • * a lot of meaning*
        • * profound sentimental*
        • * will cherish*
        • * passion for music*
        • * treasured items *
      • any of:
        • file.parse_text(.).text matches any of 6 patterns
          • shipping (?:fee|cost|arrangement)
          • (?:responsible|pay) for shipping
          • no (?:local\s)?pick.?up
          • (?:local\s)?pick.?up.{0,50}not available
          • delivery only
          • moving company
        • file.parse_text(.).text matches any of 8 patterns
          • * if you will take it *
          • * or have someone *
          • * indicate your interest *
          • * to someone you know *
          • * know someone who *
          • * someone you know would *
          • * someone who will *
          • * anyone you know *
        • file.parse_text(.).text matches any of 3 patterns
          • if you[^\r\n]{0,20}(?:(?:might|will|would) be|are)[^\r\n]{0,20}interested
          • (?:any|some)one[^\r\n]{0,20}(is|will|would|might be)[^\r\n]{0,20}interested
          • who (?:will|would|might) appreciate
        • any of regex.extract(...) where any holds:
          • strings.parse_email(.full_match).domain.domain in $free_email_providers
          • strings.parse_email(.full_match).domain.root_domain in $free_email_providers
        • all of:
          • length(headers.reply_to) > 0
          • sender.email.email not in map(headers.reply_to, .email.email)
        • length(recipients.to) is 0
        • file.parse_text(.).text matches '(?:call|contact|text)[^\\r\\n]{0,50} at'
        • file.parse_text(.).text matches '(?:private|personal) (?:e-?)?mail'
        • file.parse_text(.).text contains ' kindly '
        • file.parse_text(.).text contains ' (kindly '
  4. not:
    • all of:
      • sender.email.domain.root_domain in $high_trust_sender_root_domains
      • headers.auth_summary.dmarc.pass
  5. not:
    • sender.email.domain.root_domain in ('ridleyacademy.com', 'mountainpiano.com')

Inspects: attachments[].size, body.current_thread.text, body.links, headers.auth_summary.dmarc.pass, headers.reply_to, headers.reply_to[].email.email, recipients.to, sender.email.domain.root_domain, sender.email.email. Sensors: file.parse_text, regex.extract, regex.icontains, strings.icontains, strings.ilike, strings.parse_email. Reference lists: $free_email_providers, $high_trust_sender_root_domains.

Indicators matched (63)

FieldMatchValue
regex.icontainsregex(?:Gibson|Fender|Lowden|Martin|Taylor|Ibanez|Knaggs)\s*[^\r\n]{0,50}\s*guitar
regex.icontainsregexguitar\s*[^\r\n]{0,50}\s*(?:Gibson|Fender|Lowden|Martin|Taylor|Ibanez|Knaggs)
regex.icontainsregex(?:Yamaha|Kawai|Baldwin|Roland|Stei?nway(?: (?:&|and) Sons?)?|\d{4})\s*[^\r\n]{0,50}(?:baby.grand|piano|baby.grand.piano|keyboard)
regex.icontainsregex(?:baby.grand|piano|baby.grand.piano|keyboard)\s*[^\r\n]{0,50}(?:Yamaha|Kawai|Baldwin|Roland|Stei?nway(?: (?:&|and) Sons?)?|\d{4})
regex.icontainsregex(?:piano|keyboard)\s*[^\r\n]{0,50}(?:available|sale|rehome|gift)
regex.icontainsregex(?:Stradivarius|Guarneri|Yamaha|Stentor|Eastman|Cremona|Cecilio|Mendini)\s*[^\r\n]{0,50}(violin|viola|cello|celli)
regex.icontainsregex(?:Bach|Yamaha|Selmer|Conn|King|Jupiter|Buffet Crampon |Pearl)\s*[^\r\n]{0,50}(trombone|trumpet|saxophone|clarinet|flute)
strings.ilikesubstring* musical instruments *
strings.ilikesubstring* instrument as a gift*
strings.ilikesubstring* downsizing *
strings.ilikesubstring* relocating *
strings.ilikesubstring* to relocate *
51 more
strings.ilikesubstring* relocation *
strings.ilikesubstring* moving *
strings.ilikesubstring* give away*
strings.ilikesubstring* generously offering *
strings.ilikesubstring*a loving home*
strings.ilikesubstring*a good home*
strings.ilikesubstring*find a new home *
strings.ilikesubstring*rehome these instruments *
strings.ilikesubstring* free donation*
strings.ilikesubstring*free*member of the music community*
regex.icontainsregexinherited instruments
regex.icontainsregexlate (?:husband|father|dad|wife|mother|mom)
regex.icontainsregex(?:husband|father|dad|wife|mother|mom)[^\r\n]{0,50}estate
strings.ilikesubstring* genuinely cherish*
strings.ilikesubstring* cherished possessions*
strings.ilikesubstring* passionate instrument*
strings.ilikesubstring* music lover*
strings.ilikesubstring* had a passion for music*
strings.ilikesubstring* appreciates music*
strings.ilikesubstring* special piece*
strings.ilikesubstring* a lot of meaning*
strings.ilikesubstring* profound sentimental*
strings.ilikesubstring* will cherish*
strings.ilikesubstring* passion for music*
strings.ilikesubstring* treasured items *
regex.icontainsregexshipping (?:fee|cost|arrangement)
regex.icontainsregex(?:responsible|pay) for shipping
regex.icontainsregexno (?:local\s)?pick.?up
regex.icontainsregex(?:local\s)?pick.?up.{0,50}not available
regex.icontainsregexdelivery only
regex.icontainsregexmoving company
strings.ilikesubstring* if you will take it *
strings.ilikesubstring* or have someone *
strings.ilikesubstring* indicate your interest *
strings.ilikesubstring* to someone you know *
strings.ilikesubstring* know someone who *
strings.ilikesubstring* someone you know would *
strings.ilikesubstring* someone who will *
strings.ilikesubstring* someone who truly *
strings.ilikesubstring* anyone you know *
regex.icontainsregexif you[^\r\n]{0,20}(?:(?:might|will|would) be|are)[^\r\n]{0,20}interested
regex.icontainsregex(?:any|some)one[^\r\n]{0,20}(is|will|would|might be)[^\r\n]{0,20}interested
regex.icontainsregexwho (?:will|would|might) appreciate
regex.extractregex[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}
regex.icontainsregex(?:call|contact|text)[^\r\n]{0,50} at
regex.icontainsregex(?:private|personal) (?:e-?)?mail
strings.icontainssubstring kindly
strings.icontainssubstring (kindly
regex.icontainsregex(?:Yamaha|Kawai|Baldwin|Roland|Stei?nway(?: (?:&|and) Sons?)?)\s*[^\r\n]{0,50}(?:baby.grand|piano|baby.grand.piano|keyboard)
sender.email.domain.root_domainmemberridleyacademy.com
sender.email.domain.root_domainmembermountainpiano.com