Xero infrastructure abuse

Identifies messages that resemble credential theft, originating from Xero. Xero infrastrcture abuse has been observed recently to send phishing attacks.

Sublime rule (View on GitHub)

  1name: "Xero infrastructure abuse"
  2description: "Identifies messages that resemble credential theft, originating from Xero. Xero infrastrcture abuse has been observed recently to send phishing attacks."
  3type: "rule"
  4severity: "medium"
  5source: |
  6  type.inbound
  7  and sender.email.email == "messaging-service@post.xero.com"
  8  and 
  9  // there are external links (not org or xero domains)
 10  length(filter(body.links,
 11                .href_url.domain.domain not in $org_domains
 12                and .href_url.domain.root_domain not in ("xero.com", )
 13         )
 14  ) > 0
 15  and (
 16    any(ml.nlu_classifier(body.current_thread.text).intents,
 17        .name == "cred_theft" and .confidence == "high"
 18    )
 19    // subject match when cred_theft doesn't match
 20    // high confidence observed subject intros in the format of "Urgent Thing: ..."
 21    or regex.icontains(subject.subject,
 22                       '^(?:(?:Final|Last)?\s*Warning|(?:Final|Last|Legal|Critical|Content Violation)?\s*(?:Alert|Noti(?:ce|fication))|Appeal Required|Time.Sensitive|Critical.Alert|Important|Copyright Issue)\s*:\s*'
 23    )
 24    or any(ml.logo_detect(file.message_screenshot()).brands,
 25           .name in ("Facebook", "Meta", "Instagram")
 26           and .confidence in ("medium", "high")
 27    )
 28    // any of the links are for newly registered domains
 29    or any(filter(body.links,
 30                  .href_url.domain.domain not in $org_domains
 31                  and .href_url.domain.root_domain not in ("xero.com")
 32           ),
 33           network.whois(.href_url.domain).days_old < 30
 34    )
 35    or (
 36      any(ml.nlu_classifier(body.current_thread.text).topics,
 37          .name in ("B2B Cold Outreach", "Professional and Career Development")
 38          and .confidence != "low"
 39      )
 40    )
 41    // sender display name or subject contains confusables
 42    or (
 43      sender.display_name != strings.replace_confusables(sender.display_name)
 44      or subject.subject != strings.replace_confusables(subject.subject)
 45    )
 46    // IP pool appears to be tagged by Xero via Mailgun
 47    // https://help.mailgun.com/hc/en-us/articles/360052184214-IP-Pools
 48    or any(headers.hops,
 49           any(.fields,
 50               .name == "X-Mailgun-Sending-Ip-Pool-Name"
 51               and .value == "High Risk Pool"
 52           )
 53    )
 54  )
 55  and (
 56    ( // sender domain matches no body domains
 57      length(body.links) > 0
 58      and all(body.links,
 59              .href_url.domain.root_domain not in ("xero.com", )
 60              or .href_url.domain.root_domain is null
 61      )
 62    )
 63    // link contains email address
 64    or any(recipients.to,
 65           .email.domain.valid
 66           and any(body.links,
 67                   strings.icontains(.href_url.url, ..email.email)
 68                   or any(beta.scan_base64(.href_url.url,
 69                                           format="url",
 70                                           ignore_padding=true
 71                          ),
 72                          strings.icontains(., ...email.email)
 73                   )
 74                   or any(beta.scan_base64(.href_url.fragment,
 75                                           ignore_padding=true
 76                          ),
 77                          strings.icontains(., ...email.email)
 78                   )
 79                   // cloudflare turnstile or phishing warning page
 80                   or strings.icontains(ml.link_analysis(., mode="aggressive").final_dom.display_text,
 81                                        "cloudflare"
 82                   )
 83           )
 84    )
 85    or regex.icontains(subject.subject, "termination.*notice")
 86    or any(ml.nlu_classifier(body.current_thread.text).entities,
 87           .name in ("sender", "org")
 88           and regex.icontains(.text, 'Recruitment|staffing|\bhr\b')
 89    )
 90  )  
 91attack_types:
 92  - "Credential Phishing"
 93tactics_and_techniques:
 94  - "Evasion"
 95  - "Social engineering"
 96detection_methods:
 97  - "Content analysis"
 98  - "Header analysis"
 99  - "Natural Language Understanding"
100  - "URL analysis"
101id: "918c4bd3-987f-5f69-bb46-9465a0b87837"
to-top