Attachment: Suspicious PDF created with headless browser

Detects PDF documents containing a table of contents that were generated using HeadlessChrome, Chromium with Skia/PDF, or QT with empty metadata fields - common characteristics of automated malicious document creation.

Sublime rule (View on GitHub)

  1name: "Attachment: Suspicious PDF created with headless browser"
  2description: "Detects PDF documents containing a table of contents that were generated using HeadlessChrome, Chromium with Skia/PDF, or QT with empty metadata fields - common characteristics of automated malicious document creation."
  3type: "rule"
  4severity: "high"
  5source: |
  6  type.inbound
  7  and (
  8    // directly attached PDF
  9    any(filter(attachments, .file_type == "pdf"),
 10        (
 11          // table of contents detection
 12          (
 13            any(file.explode(.),
 14                strings.contains(.scan.ocr.raw, 'TABLE OF CONTEN')
 15            )
 16            // the Table of contents can be on another page
 17            and any(file.explode(.),
 18                    regex.icontains(.scan.ocr.raw,
 19                                    '(?:[\r\n]|^)+(?:\s*1\s*(?:\.|:))?\s*Introduction'
 20                    )
 21                    or strings.icontains(.scan.ocr.raw, 'marked in red')
 22            )
 23          )
 24          // heading of sections within observed documents
 25          or (
 26            any(file.explode(.),
 27                any(.scan.strings.strings,
 28                    any([
 29                          'Employee Acknowledgement',
 30                          'Document Summary',
 31                          'appraisal overview',
 32                          'accessing full appraisal',
 33                        ],
 34                        .. =~ .
 35                    )
 36                )
 37            )
 38          )
 39        )
 40        and (
 41          (
 42            (
 43              strings.icontains(beta.parse_exif(.).creator, 'HeadlessChrome')
 44              or strings.icontains(beta.parse_exif(.).creator, 'Chromium')
 45            )
 46            and strings.icontains(beta.parse_exif(.).producer, 'Skia/PDF')
 47          )
 48          or (
 49            any(beta.parse_exif(.).fields,
 50                .key == "Creator"
 51                and (.value == "" or strings.istarts_with(.value, 'wkhtmltopdf'))
 52            )
 53            and any(beta.parse_exif(.).fields,
 54                    .key == "Title"
 55                    and (
 56                      .value == ""
 57                      // company handbook
 58                      or .value in ('Company HandBook')
 59                      // appraisal themes
 60                      or strings.icontains(.value,
 61                                           'Employee Performance Appraisal'
 62                      )
 63                    )
 64            )
 65            and strings.istarts_with(beta.parse_exif(.).producer, 'QT ')
 66          )
 67        )
 68    )
 69    // or within an attached EML
 70    or any(filter(attachments,
 71                  .content_type == "message/rfc822" or .file_extension == "eml"
 72           ),
 73           any(filter(file.parse_eml(.).attachments, .file_type == "pdf"),
 74               (
 75                 // table of contents detection
 76                 (
 77                   any(file.explode(.),
 78                       strings.contains(.scan.ocr.raw, 'TABLE OF CONTEN')
 79                   )
 80                   // the Table of contents can be on another page
 81                   and any(file.explode(.),
 82                           regex.icontains(.scan.ocr.raw,
 83                                           '(?:[\r\n]|^)+(?:\s*1\s*(?:\.|:))?\s*Introduction'
 84                           )
 85                           or strings.icontains(.scan.ocr.raw, 'marked in red')
 86                   )
 87                 )
 88                 // heading of sections within observed documents
 89                 or (
 90                   any(file.explode(.),
 91                       any(.scan.strings.strings,
 92                           any([
 93                                 'Employee Acknowledgement',
 94                                 'Document Summary',
 95                                 'appraisal overview',
 96                                 'accessing full appraisal',
 97                               ],
 98                               .. =~ .
 99                           )
100                       )
101                   )
102                 )
103               )
104               and (
105                 (
106                   (
107                     strings.icontains(beta.parse_exif(.).creator,
108                                       'HeadlessChrome'
109                     )
110                     or strings.icontains(beta.parse_exif(.).creator, 'Chromium')
111                   )
112                   and strings.icontains(beta.parse_exif(.).producer, 'Skia/PDF')
113                 )
114                 or (
115                   any(beta.parse_exif(.).fields,
116                       .key == "Creator"
117                       and (
118                         .value == ""
119                         or strings.istarts_with(.value, 'wkhtmltopdf')
120                       )
121                   )
122                   and any(beta.parse_exif(.).fields,
123                           .key == "Title"
124                           and (
125                             .value == ""
126                             // company handbook
127                             or .value in ('Company HandBook')
128                             // appraisal themes
129                             or strings.icontains(.value,
130                                                  'Employee Performance Appraisal'
131                             )
132                           )
133                   )
134                   and strings.istarts_with(beta.parse_exif(.).producer, 'QT ')
135                 )
136               )
137           )
138    )
139  )  
140
141attack_types:
142  - "Credential Phishing"
143tactics_and_techniques:
144  - "Evasion"
145  - "PDF"
146detection_methods:
147  - "Content analysis"
148  - "Exif analysis"
149  - "File analysis"
150  - "Optical Character Recognition"
151id: "8f3108d7-e224-5bb0-81f4-e4f8506cfed3"
to-top