Attachment: HTML Attachment with Login Portal Indicators

Recursively scans files and archives to detect indicators of login portals implemented in HTML files. This is a known credential theft technique used by threat actors.

Sublime rule (View on GitHub)

  1name: "Attachment: HTML Attachment with Login Portal Indicators"
  2description: |
  3    Recursively scans files and archives to detect indicators of login portals implemented in HTML files. This is a known credential theft technique used by threat actors.
  4references:
  5  - "https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/html-file-attachments-still-a-threat/"
  6  - "https://app.any.run/tasks/6bd34bda-91ef-4d13-847c-81d7787dc763/"
  7  - "https://playground.sublimesecurity.com?id=6cd813e4-085b-4229-ad15-d2194cdbb91b"
  8type: "rule"
  9severity: "medium"
 10authors:
 11  - twitter: "ajpc500"
 12source: |
 13  type.inbound
 14  and any(attachments,
 15          (
 16            .file_extension in~ ("html", "htm", "shtml", "dhtml")
 17            or .file_extension in~ $file_extensions_common_archives
 18            or .file_type == "html"
 19          )
 20          and any(file.explode(.),
 21                  // suspicious strings found in javascript
 22                  (
 23                    length(filter(.scan.javascript.strings, strings.ilike(., "*password*", ))) >= 2
 24                    and 2 of (
 25                      any(.scan.javascript.strings, strings.ilike(., "*incorrect*")),
 26                      any(.scan.javascript.strings, strings.ilike(., "*invalid*")),
 27                      any(.scan.javascript.strings, strings.ilike(., "*login*")),
 28                      any(.scan.javascript.strings, regex.icontains(., "sign.in")),
 29                    )
 30                  )
 31                  or (
 32                    // suspicious strings found outside of javascript, but binexplode'd file still of HTML type
 33                    length(filter(.scan.strings.strings, strings.ilike(., "*password*", ))) >= 2
 34                    and 2 of (
 35                      any(.scan.strings.strings, strings.ilike(., "*incorrect*")),
 36                      any(.scan.strings.strings, strings.ilike(., "*invalid*")),
 37                      any(.scan.strings.strings, strings.ilike(., "*login*")),
 38                      any(.scan.strings.strings, strings.ilike(., "*<script>*")),
 39                      any(.scan.strings.strings, regex.icontains(., "sign.in")),
 40                      any(.scan.strings.strings,
 41                          regex.icontains(.,
 42                                          '<title>.[^<]+(Payment|Invoice|Statement|Login|Microsoft|Email|Excel)'
 43                          )
 44                      )
 45                    )
 46                  )
 47                  or
 48                  //Known phishing obfuscation
 49                  2 of (
 50                    // Enter password
 51                    any(.scan.strings.strings,
 52                        strings.ilike(.,
 53                                      "*&#69;&#110;&#116;&#101;&#114;&#32;&#112;&#97;&#115;&#115;&#119;&#111;&#114;&#100*"
 54                        )
 55                    ),
 56
 57                    // Forgotten my password
 58                    any(.scan.strings.strings,
 59                        strings.ilike(.,
 60                                      "*&#70;&#111;&#114;&#103;&#111;&#116;&#116;&#101;&#110;&#32;&#109;&#121;&#32;&#112;&#97;&#115;&#115;&#119;&#111;&#114;&#100*"
 61                        )
 62                    ),
 63
 64                    // Sign in
 65                    any(.scan.strings.strings,
 66                        strings.ilike(., "*&#83;&#105;&#103;&#110;&#32;&#105;&#110*")
 67                    )
 68                  )
 69          )
 70  )
 71
 72  and (
 73    (
 74      // exclude internal mailers where there is no SPF configured.
 75      // if the sender's root domain is an org domain, we
 76      // ensure there's an SPF pass
 77      // we use root_domain because it's typically subdomains that are misconfigured
 78      sender.email.domain.root_domain in $org_domains
 79      and headers.auth_summary.spf.pass
 80    )
 81    or sender.email.domain.root_domain not in $org_domains
 82  )
 83
 84  // negate highly trusted sender domains unless they fail DMARC authentication
 85  and (
 86    (
 87      sender.email.domain.root_domain in $high_trust_sender_root_domains
 88      and not headers.auth_summary.dmarc.pass
 89    )
 90    or sender.email.domain.root_domain not in $high_trust_sender_root_domains
 91  )
 92
 93  and (
 94    (
 95      not profile.by_sender().solicited
 96      and profile.by_sender().prevalence in ("new", "outlier")
 97    )
 98    or (
 99      profile.by_sender().any_messages_malicious_or_spam
100      and not profile.by_sender().any_false_positives
101    )
102  )  
103attack_types:
104  - "Credential Phishing"
105tactics_and_techniques:
106  - "HTML smuggling"
107  - "Scripting"
108detection_methods:
109  - "Archive analysis"
110  - "File analysis"
111  - "HTML analysis"
112  - "Javascript analysis"
113  - "Sender analysis"
114id: "3aabf4a7-fefa-5266-83fe-012002c9db4a"
to-top