Scam: Piano giveaway

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.

Sublime rule (View on GitHub)

  1name: "Scam: Piano giveaway"
  2description: "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."
  3type: "rule"
  4severity: "medium"
  5source: |
  6  length(body.links) < 10
  7  and length(body.current_thread.text) < 1500
  8  and (
  9    // body detection
 10    // be sure to update the attachment detection regexes too!
 11    (
 12      (
 13        // items and brands
 14        // Guitars
 15        regex.icontains(body.current_thread.text,
 16                        '(?:Gibson|Fender|Lowden|Martin|Taylor|Ibanez|Knaggs)\s*[^\r\n]{0,50}\s*guitar',
 17                        'guitar\s*[^\r\n]{0,50}\s*(?:Gibson|Fender|Lowden|Martin|Taylor|Ibanez|Knaggs)',
 18        )
 19        // Piano/Keyboards
 20        or regex.icontains(body.current_thread.text,
 21                           '(?:Yamaha|Kawai|Baldwin|Roland|Stei?nway(?: (?:&|and) Sons?)?|\d{4})\s*[^\r\n]{0,50}(?:baby.grand|piano|baby.grand.piano|keyboard)',
 22                           // strong indicators for generalized instrument
 23                           '(?:piano|keyboard)\s*[^\r\n]{0,50}(?:available|sale|rehome|gift)'
 24        )
 25        // Violins & Orchestral 
 26        or regex.icontains(body.current_thread.text,
 27                           '(?:Stradivarius|Guarneri|Yamaha|Stentor|Eastman|Cremona|Cecilio|Mendini)\s*[^\r\n]{0,50}(violin|viola|cello|celli)',
 28        )
 29        // brass/wind/woodwinds
 30        or regex.icontains(body.current_thread.text,
 31                           '(?:Bach|Yamaha|Selmer|Conn|King|Jupiter|Buffet Crampon |Pearl)\s*[^\r\n]{0,50}(trombone|trumpet|saxophone|clarinet|flute)'
 32        )
 33  
 34        // generic
 35        or strings.ilike(body.current_thread.text,
 36                         '* musical instruments *',
 37                         '* instrument as a gift*'
 38        )
 39      )
 40      and (
 41        // often a person is moving
 42        strings.ilike(body.current_thread.text,
 43                      '* downsizing *',
 44                      '* relocating *',
 45                      '* relocation *',
 46                      '* moving *'
 47        )
 48        or strings.ilike(body.current_thread.text,
 49                         '* give away*',
 50                         '* generously offering *',
 51                         '*a loving home*',
 52                         '*a good home*',
 53                         '*find a new home *',
 54                         '*rehome these instruments *',
 55                         '* free donation*',
 56                         '*free*member of the music community*'
 57        )
 58        // generally someone died
 59        or regex.icontains(body.current_thread.text,
 60                           'inherited instruments',
 61                           'late (?:husband|father|dad|wife|mother|mom)',
 62                           '(?:husband|father|dad|wife|mother|mom)[^\r\n]{0,50}estate'
 63        )
 64        // passion/love for the item
 65        or strings.ilike(body.current_thread.text,
 66                         '* genuinely cherish*',
 67                         '* cherished possessions*',
 68                         '* passionate instrument*',
 69                         '* music lover*',
 70                         '* had a passion for music*',
 71                         '* appreciates music*',
 72                         "* special piece*",
 73                         "* a lot of meaning*",
 74                         "* profound sentimental*",
 75                         '* will cherish*'
 76        )
 77      )
 78      and (
 79        // it talks about a shipping fee upfront
 80        regex.icontains(body.current_thread.text,
 81                        'shipping (?:fee|cost|arrangement)',
 82                        '(?:responsible|pay) for shipping',
 83                        'no (?:local\s)?pick.?up',
 84                        'delivery only',
 85                        'moving company'
 86        )
 87        // recipient or someone they know might have an interest
 88        or strings.ilike(body.current_thread.text,
 89                         '* if you will take it *',
 90                         '* or have someone *',
 91                         '* indicate your interest *',
 92                         '* to someone you know *',
 93                         '* know someone who *',
 94                         '* someone you know would *',
 95                         '* someone who will *',
 96                         '* someone who truly *',
 97                         '* anyone you know *',
 98        )
 99        or regex.icontains(body.current_thread.text,
100                           'if you[^\r\n]{0,20}(?:(?:might|will|would) be|are)[^\r\n]{0,20}interested',
101                           '(?:any|some)one[^\r\n]{0,20}(is|will|would|might be)[^\r\n]{0,20}interested',
102                           'who (?:will|would|might) appreciate',
103        )
104        or (
105          // there's an email in the body 
106          any(regex.extract(body.current_thread.text,
107                            "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
108              ),
109              strings.parse_email(.full_match).domain.domain in $free_email_providers
110              or strings.parse_email(.full_match).domain.root_domain in $free_email_providers
111          )
112          // reply-to doesn't match sender
113          or (
114            length(headers.reply_to) > 0
115            and sender.email.email not in map(headers.reply_to, .email.email)
116          )
117          // there are no recipients
118          or length(recipients.to) == 0
119          // redirects to a phone number
120          or regex.icontains(body.current_thread.text,
121                             '(?:call|contact|text)[^\r\n]{0,50} at'
122          )
123          or regex.icontains(body.current_thread.text,
124                             '(?:private|personal) (?:e-?)?mail'
125          )
126          or strings.icontains(body.current_thread.text, ' kindly ')
127        )
128      )
129    )
130    or (
131      any(filter(attachments, .size < 10000),
132          (
133            // items and brands
134            // Guitars
135            regex.icontains(file.parse_text(.).text,
136                            '(?:Gibson|Fender|Lowden|Martin|Taylor|Ibanez|Knaggs)\s*[^\r\n]{0,50}\s*guitar',
137                            'guitar\s*[^\r\n]{0,50}\s*(?:Gibson|Fender|Lowden|Martin|Taylor|Ibanez|Knaggs)',
138            )
139            // Piano/Keyboards
140            or regex.icontains(file.parse_text(.).text,
141                               '(?:Yamaha|Kawai|Baldwin|Roland|Stei?nway(?: (?:&|and) Sons?)?)\s*[^\r\n]{0,50}(?:baby.grand|piano|baby.grand.piano|keyboard)',
142                               // strong indicators for generalized instrument
143                               '(?:piano|keyboard)\s*[^\r\n]{0,50}(?:available|sale|rehome|gift)'
144            )
145            // Violins & Orchestral 
146            or regex.icontains(file.parse_text(.).text,
147                               '(?:Stradivarius|Guarneri|Yamaha|Stentor|Eastman|Cremona|Cecilio|Mendini)\s*[^\r\n]{0,50}(violin|viola|cello|celli)',
148            )
149            // brass/wind/woodwinds
150            or regex.icontains(file.parse_text(.).text,
151                               '(?:Bach|Yamaha|Selmer|Conn|King|Jupiter|Buffet Crampon |Pearl)\s*[^\r\n]{0,50}(trombone|trumpet|saxophone|clarinet|flute)'
152            )
153  
154            // generic
155            or strings.ilike(file.parse_text(.).text,
156                             '* musical instruments *',
157                             '* instrument as a gift*'
158            )
159          )
160          and (
161            // often a person is moving
162            strings.ilike(file.parse_text(.).text,
163                          '* downsizing *',
164                          '* relocating *',
165                          '* relocation *',
166                          '* moving *'
167            )
168            or strings.ilike(file.parse_text(.).text,
169                             '* give away*',
170                             '* generously offering *',
171                             '*a loving home*',
172                             '*a good home*',
173                             '*find a new home *',
174                             '*rehome these instruments *',
175                             '* free donation*',
176                             '*free*member of the music community*'
177            )
178            // generally someone died
179            or regex.icontains(file.parse_text(.).text,
180                               'inherited instruments',
181                               'late (?:husband|father|dad|wife|mother|mom)',
182                               '(?:husband|father|dad|wife|mother|mom)[^\r\n]{0,50}estate'
183            )
184            // passion/love for the item/music
185            or strings.ilike(file.parse_text(.).text,
186                             '* genuinely cherish*',
187                             '* cherished possessions*',
188                             '* passionate instrument*',
189                             '* music lover*',
190                             '* had a passion for music*',
191                             '* appreciates music*',
192                             "* special piece*",
193                             "* a lot of meaning*",
194                             "* profound sentimental*",
195                             '* will cherish*'
196            )
197          )
198          and (
199            // it talks about a shipping fee upfront
200            regex.icontains(file.parse_text(.).text,
201                            'shipping (?:fee|cost|arrangement)',
202                            '(?:responsible|pay) for shipping',
203                            'no (?:local\s)?pick.?up',
204                            'delivery only',
205                            'moving company'
206            )
207            or strings.ilike(file.parse_text(.).text,
208                             '* if you will take it *',
209                             '* or have someone *',
210                             '* indicate your interest *',
211                             '* to someone you know *',
212                             '* know someone who *',
213                             '* someone you know would *',
214                             '* someone who will *',
215                             '* anyone you know *',
216            )
217            or regex.icontains(file.parse_text(.).text,
218                               'if you[^\r\n]{0,20}(?:(?:might|will|would) be|are)[^\r\n]{0,20}interested',
219                               '(?:any|some)one[^\r\n]{0,20}(is|will|would|might be)[^\r\n]{0,20}interested',
220                               'who (?:will|would|might) appreciate',
221            )
222            // there's an email in the body 
223            or any(regex.extract(file.parse_text(.).text,
224                                 "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
225                   ),
226                   strings.parse_email(.full_match).domain.domain in $free_email_providers
227                   or strings.parse_email(.full_match).domain.root_domain in $free_email_providers
228            )
229  
230            // reply-to doesn't match sender
231            or (
232              length(headers.reply_to) > 0
233              and sender.email.email not in map(headers.reply_to, .email.email)
234            )
235            // there are no recipients
236            or length(recipients.to) == 0
237            // redirects to a phone number
238            or regex.icontains(file.parse_text(.).text,
239                               '(?:call|contact|text)[^\r\n]{0,50} at'
240            )
241            or regex.icontains(file.parse_text(.).text,
242                               '(?:private|personal) (?:e-?)?mail'
243            )
244            or strings.icontains(file.parse_text(.).text, ' kindly ')
245          )
246      )
247    )
248  )
249  
250  // not high trust sender domains
251  and not (
252    sender.email.domain.root_domain in $high_trust_sender_root_domains
253    and headers.auth_summary.dmarc.pass
254  )
255  and not sender.email.domain.root_domain in (
256    'ridleyacademy.com', // person provides piano lessons and offers to give a Roland baby-grand away
257    'mountainpiano.com' // legitimate piano moving company in Denver 
258  )  
259attack_types:
260  - "BEC/Fraud"
261tactics_and_techniques:
262  - "Free email provider"
263detection_methods:
264  - "Content analysis"
265  - "Natural Language Understanding"
266  - "Sender analysis"
267id: "1a91a203-b1fe-52b7-9f71-cecdbf5cdce0"
to-top