Attachment: PDF with a suspicious string and single URL

Detects single-page PDF attachments containing suspicious language such as 'View Document' or 'View PDF' along with exactly one URL, commonly used in credential theft attacks.

Sublime rule (View on GitHub)

  1name: "Attachment: PDF with a suspicious string and single URL"
  2description: "Detects single-page PDF attachments containing suspicious language such as 'View Document' or 'View PDF' along with exactly one URL, commonly used in credential theft attacks."
  3type: "rule"
  4severity: "high"
  5source: |
  6  type.inbound
  7  and any(attachments,
  8          .file_type == "pdf"
  9          and (
 10            //
 11            // This rule makes use of a beta feature and is subject to change without notice
 12            // using the beta feature in custom rules is not suggested until it has been formally released
 13            //
 14            // a single page pdf
 15            beta.parse_exif(.).page_count == 1
 16            // in some cases the pdf might have an invalid xref table
 17            // so we can instead use the number of pages in the pdf scanner
 18            or (
 19              beta.parse_exif(.).page_count == 0
 20              and any(beta.parse_exif(.).fields,
 21                      .key == "Warning" and .value == "Invalid xref table"
 22              )
 23              and length(filter(file.explode(.),
 24                                strings.istarts_with(.file_name, 'pdf_2_png_')
 25                         )
 26              ) == 1
 27            )
 28          )
 29          and any(file.explode(.),
 30                  // the pdf contains specific suspicious wording
 31                  // these are exact matches when split on new lines extracted from the text of the PDF from the scanPDF scanner
 32                  any(.scan.strings.strings,
 33                      regex.icontains(.,
 34                                      // action!
 35                                      '^\s*(?:view documents?|view pdf|view presentation|preview new docusign|Download Secure PDF|VIEW DOCUMENT HERE|ACCESS DOCUMENT|REVIEW NEW SECURE DOCUMENT|OPEN SECURE VIEWER|DOWNLOAD RFP DOCUMENT|View Dashboard here|ACCESS SECURE DOCUMENTS|VIEW PROPOSAL DOCUMENTS|ACCESS / VIEW PROPOSAL DOCUMENT|Review & Sign Document|Open PDF|Access Document\(s\)|(?:P?RE)?VIEW SHARED DOCUMENT|New Secured Document|ACCESS SECURE RFP PORTAL|Please Review and Sign|Review and Validate|SECURE DOCUMENT|Open Document|View Details|Q!_Compensation/Salary Amendments\.pptx|PREVIEW DOCUMENT HERE|Download Tax Details Below:|Review and Sign Document|Review Document|Open Encrypted|OPEN DOCUMENT HERE|Click to read message|CLICK HERE TO VIEW DOCUMENTS|VIEW FULL DOCUMENT HERE|View Full Proposal)\s*$',
 36                                      // "secure fax"
 37                                      'View Secure Fax',
 38                                      // more fake errors
 39                                      'It seems there was an issue opening the document. Please view it online.',
 40                                      // fake adobe update
 41                                      'Update Adobe Viewer',
 42                                      // fake sharepoint wording
 43                                      'Learn more about messages protected by Microsoft',
 44                                      // fake encryption crap
 45                                      'This document is protected by 256-bit encryption.',
 46                                      // sent you a document
 47                                      '.*sent you a \S+ to review(?:\s*(?:and|&)\s*sign)$',
 48                                      '^You received a \S+ to review and sign$',
 49                                      // docusign
 50                                      '\s*DocuSign Contract Under Review\s*',
 51                                      'DOCUMENT PREVIEW',
 52                                      'PREVIEW DOCUMENT',
 53                                      'VIEW REMITTANCE COPY HERE',
 54                                      'shared a file with you',
 55                                      '(?:check your personal|view your) forecast',
 56                                      'full new state pension',
 57                                      'UN1TED STATES',
 58                                      'view secure documents'
 59                      )
 60                  )
 61                  // fake error messages
 62                  or (
 63                    'Error' in~ .scan.strings.strings
 64                    and any(.scan.strings.strings,
 65                            regex.icontains(., '^\s*(?:View Video)\s*$')
 66                    )
 67                  )
 68                  // really terse PDF with link
 69                  or (
 70                    length(.scan.strings.strings) == 1
 71                    and 'Some additional information here' in~ .scan.strings.strings
 72                  )
 73          )
 74          and any(file.explode(.),
 75                  .depth == 0
 76                  and (
 77                    length(filter(.scan.url.urls,
 78                                  // remove mailto: links
 79                                  not strings.istarts_with(.url, 'mailto:')
 80                                  and not strings.istarts_with(.url, 'email:')
 81                                  // remove links found in exiftool output producer/creator
 82                                  and not any([
 83                                                ..scan.exiftool.producer,
 84                                                ..scan.exiftool.creator
 85                                              ],
 86                                              . is not null
 87                                              and strings.icontains(.,
 88                                                                    ..domain.domain
 89                                              )
 90                                  )
 91                                  and not .domain.root_domain in ('pdf-tools.com')
 92                                  and not .url in (
 93                                    'https://gamma.app/?utm_source=made-with-gamma'
 94                                  )
 95                           )
 96                    ) == 1
 97                    or 
 98                    // there is only one unique domain
 99                    (
100                      length(distinct(filter(.scan.url.urls,
101                                             // remove mailto: links
102                                             not strings.istarts_with(.url,
103                                                                      'mailto:'
104                                             )
105                                             and not strings.istarts_with(.url,
106                                                                          'email:'
107                                             )
108                                             // remove links found in exiftool output producer/creator
109                                             and not any([
110                                                           ..scan.exiftool.producer,
111                                                           ..scan.exiftool.creator
112                                                         ],
113                                                         . is not null
114                                                         and strings.icontains(.,
115                                                                               ..domain.domain
116                                                         )
117                                             )
118                                             and not .domain.root_domain in (
119                                               'pdf-tools.com'
120                                             )
121                                             and not .url in (
122                                               'https://gamma.app/?utm_source=made-with-gamma'
123                                             )
124                                      ),
125                                      .domain.domain
126                             )
127                      ) == 1
128                      // all of them are in self_service
129                      and all(distinct(filter(.scan.url.urls,
130                                              // remove mailto: links
131                                              not strings.istarts_with(.url,
132                                                                       'mailto:'
133                                              )
134                                              and not strings.istarts_with(.url,
135                                                                           'email:'
136                                              )
137                                              // remove links found in exiftool output producer/creator
138                                              and not any([
139                                                            ..scan.exiftool.producer,
140                                                            ..scan.exiftool.creator
141                                                          ],
142                                                          . is not null
143                                                          and strings.icontains(.,
144                                                                                ..domain.domain
145                                                          )
146                                              )
147                                              and not .domain.root_domain in (
148                                                'pdf-tools.com'
149                                              )
150                                              and not .url in (
151                                                'https://gamma.app/?utm_source=made-with-gamma'
152                                              )
153                                       ),
154                                       .domain.domain
155                              ),
156                              .domain.domain in $self_service_creation_platform_domains
157                              or .domain.root_domain in $self_service_creation_platform_domains
158                      )
159                    )
160                  )
161          )
162  )  
163attack_types:
164  - "Credential Phishing"
165tactics_and_techniques:
166  - "PDF"
167  - "Social engineering"
168  - "Evasion"
169detection_methods:
170  - "Content analysis"
171  - "File analysis"
172  - "URL analysis"
173  - "Exif analysis"
174id: "3bdbb7ad-ca08-546a-ac20-309bef95779a"
to-top