Brand impersonation: Internal Revenue Service

Detects messages from senders posing as the Internal Revenue Service by checking display name similarity and content indicators from body text and screenshots. Excludes legitimate IRS domains and authenticated senders.

Sublime rule (View on GitHub)

  1name: "Brand impersonation: Internal Revenue Service"
  2description: "Detects messages from senders posing as the Internal Revenue Service by checking display name similarity and content indicators from body text and screenshots. Excludes legitimate IRS domains and authenticated senders."
  3type: "rule"
  4severity: "high"
  5source: |
  6  type.inbound
  7  and (
  8    // display name contains IRS
  9    (
 10      strings.ilike(strings.replace_confusables(sender.display_name),
 11                    '*internal revenue service*'
 12      )
 13      or strings.like(strings.replace_confusables(sender.display_name), 'IRS*')
 14      or regex.icontains(strings.replace_confusables(sender.display_name),
 15                         '\birs.gov'
 16      )
 17      or regex.icontains(strings.replace_confusables(sender.display_name),
 18                         'internal.{0,5}revenue.{0,5}service'
 19      )
 20    )
 21  
 22    // levenshtein distance similar to IRS
 23    or strings.ilevenshtein(strings.replace_confusables(sender.display_name),
 24                            'internal revenue service'
 25    ) <= 1
 26    or (
 27      strings.like(strings.replace_confusables(subject.base), '*IRS*')
 28      and any(ml.nlu_classifier(body.current_thread.text).topics,
 29              .name == "Government Services" and .confidence != "low"
 30      )
 31    )
 32    or 2 of (
 33      strings.icontains(body.current_thread.text, "Internal Revenue Service"),
 34      strings.icontains(body.current_thread.text, "4228 Park Ave S"),
 35      strings.icontains(body.current_thread.text, "1111 Constitution Ave"),
 36      strings.icontains(body.current_thread.text, "New York, New York 10003"),
 37      strings.icontains(body.current_thread.text, "Washington, DC 20224")
 38    )
 39    or regex.icontains(body.current_thread.text,
 40                       '©\s*20[0-9]{2}\s*\s*Internal Revenue Service'
 41    )
 42  )
 43  and (
 44    (
 45      any(ml.nlu_classifier(body.current_thread.text).topics,
 46          .name in ("Security and Authentication", "Financial Communications")
 47          and .confidence == "high"
 48      )
 49      and not any(ml.nlu_classifier(body.current_thread.text).topics,
 50                  .name in (
 51                    "Advertising and Promotions",
 52                    "Newsletters and Digests",
 53                    "Political Mail",
 54                    "Events and Webinars"
 55                  )
 56                  and .confidence != "low"
 57      )
 58    )
 59    or (
 60      // OCR length is more than 2x the current_thread length
 61      // indicating that the body is mostly an image
 62      (
 63        (length(beta.ocr(file.message_screenshot()).text) + 0.0) / (
 64          length(body.current_thread.text) + 0.0
 65        )
 66      ) > 2
 67      and length(body.previous_threads) == 0
 68      and any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topics,
 69              .name in ("Security and Authentication", "Financial Communications")
 70              and .confidence == "high"
 71      )
 72      and not any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).topics,
 73                  .name in (
 74                    "Advertising and Promotions",
 75                    "Newsletters and Digests",
 76                    "Political Mail",
 77                    "Events and Webinars"
 78                  )
 79                  and .confidence != "low"
 80      )
 81    )
 82    or any(ml.nlu_classifier(body.current_thread.text).intents,
 83           .name == "cred_theft" and .confidence == "high"
 84    )
 85    or any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents,
 86           .name == "cred_theft" and .confidence == "high"
 87    )
 88  )
 89  and not (
 90    (
 91      length(body.current_thread.text) > 2500
 92      or any(headers.hops,
 93             any(.fields,
 94                 .name == 'List-Unsubscribe-Post'
 95                 and .value == 'List-Unsubscribe=One-Click'
 96             )
 97      )
 98    )
 99    and any(ml.nlu_classifier(body.current_thread.text).intents,
100            .name == "benign" and .confidence == "high"
101    )
102  )
103  
104  // and the sender is not in org_domains or from .gov domains and passes auth
105  and not (
106    sender.email.domain.root_domain in $org_domains
107    or (
108      (
109        sender.email.domain.root_domain in ("govdelivery.com", "ms-cpa.org")
110        or sender.email.domain.tld == "gov"
111      )
112      and headers.auth_summary.dmarc.pass
113    )
114  )
115  // and the sender is not from high trust sender root domains
116  and not (
117    sender.email.domain.root_domain in $high_trust_sender_root_domains
118    and coalesce(headers.auth_summary.dmarc.pass, false)
119  )  
120attack_types:
121  - "BEC/Fraud"
122  - "Credential Phishing"
123tactics_and_techniques:
124  - "Impersonation: Brand"
125  - "Social engineering"
126detection_methods:
127  - "Content analysis"
128  - "Natural Language Understanding"
129  - "Optical Character Recognition"
130  - "Sender analysis"
131id: "3c63f8e9-4bce-5ce3-b17d-1ae361b5782d"
to-top