Link: Display Text Matches Subject Line

Message with short body text contains a single link where the display text matches the subject line. The link is deceptive and the recipient patterns are unusual, such as the recipient's address appearing in the body or undisclosed recipients being used.

Sublime rule (View on GitHub)

 1name: "Link: Display Text Matches Subject Line"
 2description: "Message with short body text contains a single link where the display text matches the subject line. The link is deceptive and the recipient patterns are unusual, such as the recipient's address appearing in the body or undisclosed recipients being used."
 3type: "rule"
 4severity: "medium"
 5source: |
 6  type.inbound
 7  
 8  // short body
 9  and length(body.current_thread.text) < 1500
10  
11  // suspicious recipient patterns
12  and (
13    // recipient email is contained within the body
14    (
15      length(recipients.to) == 1
16      and all(recipients.to,
17              strings.icontains(body.current_thread.text, .email.email)
18      )
19    )
20    // the sender is the recipient
21    or sender.email.email in map(recipients.to, .email.email)
22    // none of the recipients are valid (generally undisclosed recipients)
23    or not all(recipients.to, .email.domain.valid)
24  )
25  // few overall links
26  and length(body.links) < 10
27  // none of the links are unsubscribe links
28  and not any(body.links,
29              strings.icontains(.display_text, 'unsub')
30              or strings.icontains(.href_url.url, 'unsub')
31              or strings.icontains(.display_text, 'optout')
32              or strings.icontains(.href_url.url, 'optout')
33              or strings.icontains(.display_text, 'subscription')
34              // google confidential email use the subject as a link
35              or .href_url.domain.domain == "confidential-mail.google.com"
36  )
37  
38  // even fewer links which are
39  and 0 < length(filter(body.links,
40                        // not related to the sender domain
41                        .href_url.domain.root_domain != sender.email.domain.root_domain
42                        // not related to the recipient domain
43                        and not any(recipients.to,
44                                    .email.domain.root_domain == ..href_url.domain.root_domain
45                        )
46                        // filter out links common in signatures
47                        and not .href_url.domain.root_domain in (
48                          "facebook.com",
49                          "instagram.com",
50                          'twitter.com',
51                          'x.com'
52                        )
53                        // do not contain a display_text (TP samples have the display_text of the subject)
54                        // // this removes domains found in signatures
55                        and .display_text is not null
56                        // not the aka.ms in warning banners
57                        and not .href_url.domain.domain == "aka.ms"
58                 )
59  ) <= 3
60  
61  // exactly one link with display text that matches the subject
62  and length(filter(body.links, subject.subject =~ .display_text)) == 1
63  and (
64    // the link with the display_text of the subject
65    any(filter(body.links, subject.subject =~ .display_text),
66        // when visited is phishing
67        ml.link_analysis(.).credphish.disposition == "phishing"
68        or ml.link_analysis(.).final_dom.display_text == "Verify you are human"
69    )
70    // or the body is cred_theft
71    or any(ml.nlu_classifier(body.current_thread.text).intents,
72           .name == "cred_theft"
73    )
74  )
75  
76  // the display text of a link is the subject
77  and subject.subject in map(body.links, .display_text)
78  
79  // exclude common in signup links/password resets which are observed in links all the time
80  and not (
81    strings.icontains(subject.subject, 'confirm')
82    or strings.icontains(subject.subject, 'activate')
83    or strings.icontains(subject.subject, 'reset')
84    or strings.icontains(subject.subject, 'unlock')
85    or strings.icontains(subject.subject, 'login')
86    or strings.icontains(subject.subject, 'log in')
87  )  
88attack_types:
89  - "BEC/Fraud"
90  - "Credential Phishing"
91tactics_and_techniques:
92  - "Social engineering"
93  - "Evasion"
94detection_methods:
95  - "Header analysis"
96  - "Content analysis"
97  - "Natural Language Understanding"
98  - "URL analysis"
99id: "ba722cf0-b94e-55d2-b29a-df6fab80a164"
to-top