Serverless Red Team Infrastructure: Part 1, Web Bugs

During a red team engagement, it is often beneficial to have the ability to quickly and programatically deploy infrastructure. To date, most existing literature has focussed on deploying the server orientated red team infrastructure using terraform; this principle complements this work well and we recommend diving in to the following resources if this is of interest:

However, in this post we will cover an alternate approach using AWS Lambda serverless computing.

Serverless Red Teaming Overview

Serverless was first introduced to me by @_xpn_ who was integrating it with pushover to monitor when users visited his phishing site during an engagement. After seeing how well it worked, I quickly recognised how powerful the concept was and how there were many use cases where we could use it.

As a concept, serverless computing is best described by Amazon:

“Serverless computing allows you to build and run applications and services without thinking about servers. Serverless applications don’t require you to provision, scale, and manage any servers. You can build them for nearly any type of application or backend service, and everything required to run and scale your application with high availability is handled for you.”

As red teamers, this provides a highly attractive proposition for certain components of the red team infrastructure as we no longer need to worry about provisioning, building or configuring servers. Indeed, serverless means you can programatically create new services as and when we need them in minutes and if a particular campaign becomes tainted, you can simply rinse and repeat to create new, unattributable infrastructure.

AWS Lambda also brings two key advantages; firstly when you deploy an application you automatically receive a SSL certificate from Amazon’s Root CA:

Secondly, the default domain (although custom domains are supported) is categorised in most cases as Technology/Internet by many proxy services:

However, during an operation, we’re very cautious about how client data is stored both at rest and in transit. A key operational rule for us is that our C2 systems are always hosted from our on-premise servers and although we use cloud services extensively (primarily as redirectors), we avoid storing any sensitive data in the cloud. This theory is discussed in part in @malcomvetter’s “Responsible Red Teams” post. This design decision may be evident in how some of the tooling we describe is implemented.

Serverless Web Bugs

During the reconnaissance phase of an engagement, we invest a large portion of our time in understanding our client’s environment. Part of this includes using web bugs to track when users receive an e-mail and click on a link, as well as to enumerate the client-side software on the user’s endpoint.

AWS Lambda provides the perfect platform to implement this and as such we have implemented several Lambda functions to perform this kind of tracking, as well as client-side enumeration, storing the results inside an Amazon Relation Database Service. The application we developed to do this, unimaginatively called lambda-webbugs, can be found on the MDSec ActiveBreach GitHub page.

When using serverless, a YAML configuration file (serverless.yml) is used to define the service; the functions exposed by lambda-webbugs are defined inside the “functions” block of which there are 3, “ping”, “enum” and “info”. Each of these are mapped to a python method using the “handler” key, for example the “ping” function is mapped to the ping(event, context) method inside the file:

– http:
path: collect/ping
method: get[/code]

The HTTP path that is exposed by the function is defined by the “path” key, in the above example the function is accessed by the URL /webbug/collect/ping, where the webbug directory is defined by the “stage” key.

The 3 functions exposed by the application are as follows:

  • /webbug/collect/ping: records that a user has visited the URL, it accepts a “token” and a “step” query parameter. The token is a unique ID used to track the user, while the “step” is used to distinguish between phases of your campaign. For example, “step=1” may refer to the user opening the email, while “step=2” may refer to the phishing page being opened and “step=3” may be a callback from opening an attachment; you may use these as you see fit. The results of the callbacks are stored inside an RDS database in the “webbug” table and include the user’s IP and User-Agent.
  • /webbug/collect/enum: renders a visually blank HTML form that executes the enumeration JavaScript and posts the results to the “info” endpoint. This function accepts a “token” query parameter.
  • /webbug/collect/info: receives the results from the enum function and stores them inside and RDS database. This function accepts the “token”, “sw” and “intip” query parameters.

For this simple proof of concept, we used the PluginDetect library to enumerate the client-side plugins.

Real World Illustration

To illustrate how this can be used in a real reconnaissance campaign, let’s walk through the steps of how it may be used.

Firstly, you will need to install Serverless. On MacOS the fastest way to do this is with homebrew (brew install serverless). Once that is done, configure Serverless to use your AWS account by setting the AWS_SECRET_ACCESS_KEY and AWS_ACCESS_KEY_ID variables.

Next setup an RDS instance in AWS and configure the credentials and host in the the script.

Once your RDS instance is up and running update the VPC: configuration block with the securityGroupIds and subnetIds corresponding to your RDS instance so that they are deployed to the same VPC, meaning that they can directly communicate without reconfiguring the security groups. From this point simply use the “serverless deploy” command to deploy the lambda-webbugs scripts to Lamba:

This has now deployed our 3 functions in to Lamba which can be accessed through the URLs listed under endpoints.

During a reconnaissance campaign you may want to check whether your user is receiving the e-mail, you can use the ping function to do this by embedding something like the following inside a HTML e-mail:

[code]<img src=“” />[/code]

You’ll likely want to uniquely assign a token to each user you phish so you can track them efficiently, then the step parameter can be used to indicate that this callback occurred as of the result of an e-mail. When the e-mail is opened, the mail client will attempt to download the image and initiate the HTTP request, causing a log entry to be added to our RDS database inside the webbug table:

Let’s assume our phishing e-mail contains a lure to coerce the user in to visiting a web page under our control to perform further enumeration, we can track the click by embedding a similar IMG tag, this time using “step=2” so we can follow how far the user travelled down the journey.

Within the same page, include a hidden iframe that again submits a request to the enum function which will cause the client-side software plugins to be enumerated. Note, you’ll need to pull out the token and reinsert it to the iframe link; this is quite trivial to do in JavaScript so we won’t cover it here:

[code]<iframe src=”” style=”width:0; height:0; border:0; border:none” />[/code]

The enumeration will cause a post request to the collector function which will insert the results in to RDS, as shown below:

As our database is cloud hosted, we opt to store no sensitive data inside it with all users identified by a UUID. Having the results inside a database is extremely handy as you’re then able to display, organise and search them as you need, the rest is left as an exercise for the reader.

Note, for opsec purposes you may also want to use a custom domain for your Lamba functions, this is described in Amazon’s documentation so will not be covered here.

This blog post was written by Dominic Chell.


written by

Dominic Chell

Ready to engage
with MDSec?

Copyright 2020 MDSec