SIG: Suspicious File Delivery from Cloudflare Family Host

alert http $HOME_NET any → $EXTERNAL_NET any (msg:“LOCAL suspicious file delivery from targeted Cloudflare-family host”; flow:to_server,established; http.host; pcre:“/^(?:(?:[A-Za-z0-9-]+.)*trycloudflare.com|(?:[A-Za-z0-9-]+.)*pages.dev|(?:[A-Za-z0-9-]+.)*workers.dev|(?:[A-Za-z0-9-]+.)*r2.dev)$/i”; http.uri; pcre:“/.(?:wsf|py|js|jse|vbs|vbe|bat|cmd|ps1|hta|url)(?:$|[?#&])/i”; reference:url, The Unintentional Enabler: How Cloudflare Services are Abused for Credential Theft and Malware Distribution ; reference:url, Quick Tunnels · Cloudflare One docs ; classtype:trojan-activity; sid:1000001; rev:5;)

1 Like

Welcome @Pb-22 ! I reviewed your submitted rule and the provided references. If I understand the rule’s intention correctly, you’d like to alert on Cloudflare Key Services that are delivering a specific list of files.

The submitted rule does not have a category (https://tools.emergingthreats.net/docs/ETPro%20Rule%20Categories.pdf), but the other metadata, such as classtype:trojan-activity and the word “suspicious” , indicate you’d like these alerts to lead into investigation. With that said, I think HUNTING is an appropriate category. This category signals to rule users that they may enable/disable the rules based on their personal hunting interest.

I believe we can improve the rule’s overall performance by creating a new rule per host such that…

alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"ET HUNTING Suspicious File Hosted via Cloudflare Services (* .trycloudflare .com)"; flow:established,to_server; http.host; content:".trycloudflare.com"; endswith; reference:url,cofense.com/blog/how-cloudflare-services-are-abused-for-credential-theft-and-malware-distribution; reference:url,developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/trycloudflare/; classtype:trojan-activity; sid:1; rev:1;)

alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"ET HUNTING Suspicious File Hosted via Cloudflare Services (* .pages .dev)"; flow:established,to_server; http.host; content:".pages.dev"; endswith; reference:url,cofense.com/blog/how-cloudflare-services-are-abused-for-credential-theft-and-malware-distribution; reference:url,developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/trycloudflare/; classtype:trojan-activity; sid:2; rev:1;)

alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"ET HUNTING Suspicious File Hosted via Cloudflare Services (* .workers .dev)"; flow:established,to_server; http.host; content:".workers.dev"; endswith; reference:url,cofense.com/blog/how-cloudflare-services-are-abused-for-credential-theft-and-malware-distribution; reference:url,developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/trycloudflare/; classtype:trojan-activity; sid:3; rev:1;)

alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"ET HUNTING Suspicious File Hosted via Cloudflare Services (* .r2 .dev)"; flow:established,to_server; http.host; content:".r2.dev"; endswith; reference:url,cofense.com/blog/how-cloudflare-services-are-abused-for-credential-theft-and-malware-distribution; reference:url,developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/trycloudflare/; classtype:trojan-activity; sid:4; rev:1;)

Note that I didn’t add the second PCRE yet. Do you have any URL examples of what the second PCRE intends to match on? It would help me finish these rules and we can submit them to our ET Open Ruleset

Cheers,

:hotdog:

1 Like

@bingohotdog thank you for taking a look and for the helpful feedback.

HUNTING makes sense to me as the right category.

Yes, the intention was not to alert on the Cloudflare service host alone, but on requests to those targeted Cloudflare service families where the URI also looks like delivery of a suspicious file. The second PCRE was meant to match suspicious file extensions in the HTTP URI.

Examples of the URI paths I had in mind:

  • /payload.wsf

  • /stage.py

  • /dropper.js

  • /invoice.url

  • /run.vbs

  • /loader.hta

  • /update.ps1

  • /script.jse

  • /file.bat

  • /cmd.cmd

A few full example URLs:

  • hxxps://abc123.trycloudflare.com/payload.wsf

  • hxxps://login-helper.pages.dev/stage.py

  • hxxps://loader.workers.dev/dropper.js

  • hxxps://shortcut.workers.dev/invoice.url

The extension list I was working from was:
.wsf, .py, .js, .jse, .vbs, .vbe, .bat, .cmd, .ps1, .hta, and .url

So the intended logic was essentially:
targeted Cloudflare-family host + suspicious URI extension

I agree that splitting by host family is likely cleaner from a performance standpoint. I appreciate the guidance on that.

I have a test pcap with the different types as well, but unable to attach it here

1 Like

@bingohotdog thanks again for the guidance

I went ahead and tested the 4 rule approach locally with PCRE and they worked well.

I tested two simple PCAP variants:

  1. requests where the URI ends directly in one of the targeted extensions, for example:
  • /payload.wsf

  • /stage.py

  • /dropper.js

  • /run.ps1

  1. requests where the URI still ends in the targeted extension but is followed by normal query or fragment syntax, for example:
  • /payload.wsf?ref=mail

  • /stage.py?id=22&src=cdn

  • /dropper.js#section

In testing, the following URI PCRE behaved as intended for both the direct-ending cases and the query/fragment variants:

pcre:"/\.(?:wsf|py|js|jse|vbs|vbe|bat|cmd|ps1|hta|url)(?=$|[?#&])/i"

So the updated rules would be:

alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"ET HUNTING Suspicious File Hosted via Cloudflare Services (*.trycloudflare.com)"; flow:established,to_server; http.host; content:".trycloudflare.com"; endswith; http.uri; pcre:"/\.(?:wsf|py|js|jse|vbs|vbe|bat|cmd|ps1|hta|url)(?=$|[?#&])/i"; reference:url,cofense.com/blog/how-cloudflare-services-are-abused-for-credential-theft-and-malware-distribution; reference:url,developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/trycloudflare/; classtype:trojan-activity; sid:1; rev:2;)

alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"ET HUNTING Suspicious File Hosted via Cloudflare Services (*.pages.dev)"; flow:established,to_server; http.host; content:".pages.dev"; endswith; http.uri; pcre:"/\.(?:wsf|py|js|jse|vbs|vbe|bat|cmd|ps1|hta|url)(?=$|[?#&])/i"; reference:url,cofense.com/blog/how-cloudflare-services-are-abused-for-credential-theft-and-malware-distribution; reference:url,developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/trycloudflare/; classtype:trojan-activity; sid:2; rev:2;)

alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"ET HUNTING Suspicious File Hosted via Cloudflare Services (*.workers.dev)"; flow:established,to_server; http.host; content:".workers.dev"; endswith; http.uri; pcre:"/\.(?:wsf|py|js|jse|vbs|vbe|bat|cmd|ps1|hta|url)(?=$|[?#&])/i"; reference:url,cofense.com/blog/how-cloudflare-services-are-abused-for-credential-theft-and-malware-distribution; reference:url,developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/trycloudflare/; classtype:trojan-activity; sid:3; rev:2;)

alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"ET HUNTING Suspicious File Hosted via Cloudflare Services (*.r2.dev)"; flow:established,to_server; http.host; content:".r2.dev"; endswith; http.uri; pcre:"/\.(?:wsf|py|js|jse|vbs|vbe|bat|cmd|ps1|hta|url)(?=$|[?#&])/i"; reference:url,cofense.com/blog/how-cloudflare-services-are-abused-for-credential-theft-and-malware-distribution; reference:url,developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/trycloudflare/; classtype:trojan-activity; sid:4; rev:2;)

If this looks good, I would be glad to proceed.

1 Like

Yes, we can definitely go forward with this submission.

Thank you for the URI paths in the previous posts. The request for URI paths was motivated to improve the second PCRE performance, where possible. The second PCRE ``pcre:"/\.(?:wsf|py|js|jse|vbs|vbe|bat|cmd|ps1|hta|url)(?=$|[?#&])/i"; will match if

  • there exists a http.uri buffer
  • the http.uri buffer contains an extension content match, anywhere
  • the http.uri buffer may end after the extension content match OR may end in ?#&

We can improve performance by using more content and anchors. Let’s match on content:“.”, and then use this content match as an anchor for the extension matching >> content:“.”; pcre:”/^(?:wsf|py|js|jse|vbs|vbe|bat|cmd|ps1|hta|url)(?:$|[?#&])/Ri”. More about PCRE modifiers in this post, Handling False Positive Reports as A Rule Writer! Special Guests: PCREs, Dalton, Dalton’s Flowsynth

And so, I’ll release 4 rules for each domain with the updated PCRE e.g.

alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"ET HUNTING Suspicious File Hosted via Cloudflare Services (* .r2 .dev)"; flow:established,to_server; http.host; content:".r2.dev"; endswith; http.uri; content:"."; pcre:"/^(?:wsf|py|js|jse|vbs|vbe|bat|cmd|ps1|hta|url)(?:$|[?#&])/Ri"; reference:url,cofense.com/blog/how-cloudflare-services-are-abused-for-credential-theft-and-malware-distribution; reference:url,developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/trycloudflare/; classtype:trojan-activity; sid:4; rev:1;)

BTW, I do note we could continue improving the PCRE if we assumed the URI terminated at the extension match. I haven’t noticed any URI examples with fragments, Search - urlscan.io . However, that wasn’t the intention of your rules, so I didn’t add that modification!

Cheers! I’ll update this post when the production SIDs are out and give you thanks in our Daily Release post.

1 Like

See Ruleset Update Summary - 2026/04/09 - v11168 for published rules. Thanks!

1 Like

Males sense. Using content:"." with the relative PCRE is a nice improvement. Thanks!

2 Likes

Happy hunting! Let us know if you find anything interesting. :smiling_face_with_sunglasses:

1 Like