Recently, I had a chance to play with Cloudflare Workers. Workers provide a similar capability to other Function-as-a-Service (FaaS) offerings, like AWS’s Lambda or Azure’s Functions. Described by Cloudflare, in terms of what you can do with these Workers:
Anything and everything. You’re writing code, so the possibilities are infinite. Your Service Worker will intercept all HTTP requests destined for your domain, and can return any valid HTTP response. Your worker can make outgoing HTTP requests to any server on the public internet.
Reading Adam Chester’s Lambda Redirector blog, there were obvious applications for Cloudflare Workers to achieve a similar thing. Taking inbound requests from an implant and relaying this back to our infrastructure.
At the time, I wasn’t aware of this blog written by @MYZXCG (thanks to @ZephyFish for pointing it out). @MYZXCG’s blog covers the steps needed to setup Cobalt Strike to use an Nginx redirector, and to subsequently send traffic to this redirector using Cloudflare Workers. So as to not reinvent the wheel, this blog will focus on an alternative approach to the same task, with additional OpSec aspects which might be of interest.
A significant appeal of the Workers service is the ability to deploy our code under Cloudflare’s
workers.dev domain. There is the option to deploy Workers under a user-controlled domain, but this
workers.dev domain allows to effectively ‘domain front’ using the categorisation of Cloudflare’s catch-all domain.
While it would have been preferable to use the Serverless Framework to handle deployment and teardown of Workers, it seems that there is an outstanding issue with supporting deployment to the
As a result, we’ll use
wrangler to handle our deployment. This can be installed using
npm install -g @cloudflare/wrangler
Once installed, we need to configure the comand-line tool to use our Cloudflare credentials. You can use
wrangler login or take a premade API token and run a
wrangler config and paste it in.
To generate an API token, having created a Cloudflare account, navigate to the API tokens portal. For the purposes of this, we can use the
Edit Cloudflare Workers permissions template.
To get started, we’ll create and deploy a simple “Hello Worker” templated project (as documented here). To generate the template, run the following command:
wrangler generate helloworld
Before we can deploy this Worker, we’ll need to add our account ID to the generated
wrangler.toml file. You can easily retrieve your account ID by running a
We can then run a
wrangler publish command to deploy our “Hello Worker” function. If everything goes well, we should be returned a URL of the format
If we visit or curl this URL, we should get our “Hello worker!” output back - Success!
Creating a Redirector
To repurpose our simple project to redirect traffic, we need to edit the
index.js file. Firstly, we can set some environment variables to use in our main code.
- TS - The destination URL for our traffic, e.g. our Cobalt Strike team server or some other redirecting infrastructure (e.g. https://bad.stuff/).
- WORKER_ENDPOINT - The deployed endpoint for our Worker, we’ll use this to strip the URI path of received requests and send it on.
wrangler.toml file should look something like the below. Note,
[WORKER_NAME] is based on the
name field, so would just be
"helloworld" in this case:
index.js file can then be modified as below:
If we run a
wrangler publish now, we should have an endpoint that will take our requests and forward them onto a destination host. As we’re taking the request URI and appending that to the destination URL, we can customise our traffic profile as we see fit (i.e. using a malleable profile).
With our Cobalt Strike listener setup, we can launch a Beacon and get a callback to our Team Server. Great stuff.
One application of this could be to restrict redirected traffic based on a custom header (as outlined here). Any traffic not supplying this header would then be responded to with some suitably-benign response.
For this, we’ll add an additional environment variable,
HEADER_KEY to our variables block in
We can then modify our
index.js file as below. Note here we’re using a static
X-Custom-PSK header name, but you could pull that out as an environment variable too depending on your use case.
Browsing to this URL without providing our header value, we should receive our benign response.
We then need to ensure that our callback traffic includes the custom header in all our GET and POST requests. For Cobalt Strike, this can be achieved by adding the header to the
client blocks, as below (adapting @xpn’s profile from the Lambda redirector blog for simplicity).
As with most command-and-control (C2) channels, detection is a significant challenge. This is exacerbated by the fact that, in this configuration, we can adapt the Beacon malleable profile to fit whichever scenario we may choose.
In this blog specifically, we’re using Cloudflare’s
workers.dev domain, rather than a custom domain name. A valuable exercise may be to review an organisation’s existing traffic to this top-level domain, alerting or preventing access as appropriate.
Cloudflare Workers, much like other Function-as-a-Service offerings, present an alternative means of fronting command-and-control traffic. Deploying one (or many) Worker redirectors is trivial using deployment tools, such as