Infra Automation Primer (Red Team Edition)

Cedric Owens
Red Teaming with a Blue Team Mentality
9 min readFeb 26, 2021

The areas of responsibility for internal red teams include many different aspects, ranging from tool development to operations planning and execution to infrastructure standup/maintenance and everything in between. As an internal red teamer, I believe there are opportunities for automation that will allow teams to more efficiently operate by handling some of the routine and repetitive tasks. I do not believe that red team functions as a whole can be automated — there are too many factors that require human intervention/insight/experience. This article will instead look at some practical examples of how red teams can automate infrastructure standup.

Infrastructure Needs

Infrastructure, infrastructure infrastructure! In order to effectively simulate/emulate an external threat, red teams will need the ability to stand up servers for phishing, command and control, redirectors, etc. Given that these needs typically exist across all operations where a red team is emulating/simulating a threat actor, this presents opportunities for automation.

Below is a diagram that conveys a quick overview on redirectors:

example of using Apache mod_rewrite as a redirector

There are other methods/tools for redirectors as well (ex: socat). In this post I am focusing on mod_rewrite since it has become one of my personal favorites for redirectors. Essentially having a redirector in front of a firewalled and protected C2 server ensures that only the redirector can access the C2 server and also helps with operational resilience because operators do not have to worry about rebuilding the C2 server again in the event that blue team finds and blocks domains. To get back up and running only spin up a new redirector with a different domain and grant that new redirector access to the C2 server and you are good to go. Apache mod_rewrite is very useful for this in that it contains rewrite conditions and rewrite rules to execute based on those conditions. Additionally, mod_rewrite is able to serve as a proxy with the ProxyPass and ProxyPassReverse settings. An example is below:

Sample mod_rewrite with user-agent filtering

In the example above, mod_rewrite has a single rewrite condition with two sets of rewrite rules. The condition checks for a user agent string that includes Mozilla followed by anything up through /Firefox/10.0. Each web request is checked for that condition and if that condition is met, mod_rewrite will then send the web request to http://10.10.10.10 along with the request uri. If the condition is not met, mod_rewrite will respond with a 404 Not Found. The ProxyPassReverse entry allows the mod_rewrite server to essentially be a transparent proxy between the client and the back-end C2 server.

Let’s look at another mod_rewrite example, but this time using https:

The https example includes a few more lines for ssl configurations and also includes the certificate and key files. This example is for a letsencrypt certificate, which by default uses the /etc/letsencrypt/live/[domain]/cert.pem and privkey.pem file paths respectively. One other thing I added to the mod_rewrite ssl example above is an additional rewrite condition for an http Authorization token (ex: bearer token). In the simple example above, it’s checking for an Authorization token value that starts with the string Bearer in addition to the user agent check. If both of these checks pass then the traffic is routed to the back end C2 server (in this example that would be https://10.10.10.10) along with the request URI. The [NC] flag tells mod_rewrite to ignore case when checking the user agent and the [P] flag tells mod_rewrite to pass the url via mod_proxy to the back end server when enforcing the rewrite rule.

Another look with slightly more details of a basic mod_rewrite setup end-to-end is below:

sample mod_rewrite flow/setup

Not pictured in the diagram above…but red teams would also need a phishing server from which to send phishing emails.

Below is a common example of how the phishing server might be set up:

sample phishing server setup

There are certainly some opportunities for automation in the diagrams above. For starters, you could automate the standup of the redirector, back end C2 server, and phishing server.

At a high level, automation steps for the redirector would include:

  • stand up the host
  • configure firewall rules
  • install apache2
  • enable the necessary apache2 modules (ex: a2enmod rewrite proxy proxy_http ssl proxy_connect)
  • install and run certbot for your domain (for ssl redirectors)
  • configure key apache files (ex: 000-default.conf, apache2.conf, .htaccess)

At a high level, automation steps for the back-end c2 server would include:

  • stand up the host
  • configure firewall rules
  • installing docker or docker compose (depending on how you plan to run your C2)
  • installing your C2

At a high level, automation steps for the phishing server would include:

  • stand up the host
  • configure firewall rules
  • install docker and docker-compose (depending on how you plan to run it)
  • install whatever dependencies your phishing server needs (ex: go)
  • install the phishing server

How

Next we will look at examples of how you can automate the items above. There are several different ways to do this (ex: pulumi, ansible playbooks, terraform scripts, writing your own scripts that make the API calls at the providers, etc.). I will not cover all these methods, but will instead highlight the methods that I have used and enjoy using. I personally am a fan of using bash + terraform to accomplish my automation in the following way:

  • bash script: Captures key inputs from the user needed by the terraform script (ex: ssh key pairs, API token, where the operator will need to login for admin access from, etc.); bash will then take these inputs, replace variable placeholders in the terraform scripts, and run the terraform scripts

====> Here is an example bash script that captures input for passing on to terraform for the Linode provider:

echo “=====>Enter the name you want to call your Linode redirector”
read linodeName
echo “=====>Enter the src IP that you will ssh into your redirector infra from (i.e., terraform will set up a firewall only allowing ssh/admin access in from this src IP”
read adminIP
echo “=====>Enter the IP address of the backend C2 server that the redirector will sit in front of (only the redirector will have access to ports 443 and/or 80 on this host)”
read c2IP
echo “=====>Enter your Linode Personal Access Token”
read linodeToken
echo “=====>Enter the local path to the ssh public key you want to load onto this host for ssh access (ex: ~/.ssh/id_rsa.pub)”
read pubKey
echo “=====>Enter the local path to the ssh private key that you want Terraform to use to ssh into this Linode host (ex: ~/.ssh/id_rsa)”
read privKey
echo “=====>Enter the domain name for your redirector. AFTER THE SCRIPT RUNS, BE SURE TO SET UP DNS RECORDS TO POINT TO THIS REDIRECTOR’S IP ADDRESS”
read domain
echo “=====>Enter the user agent string that you want the redirector to use to allow access to your back end C2 (i.e., the unique user agent in your C2 agent)”
read uAgent
echo “=====>Do you have an authorization token (ex: bearer token) that you want to use for redirecting? (Y/N)”
read authAns
if [[ (“$authAns” == “Y”) || (“$authAns” == “y”) ]];then
echo “=====>Enter the first few characters of the auth string that are consistent (ex: for a token with Bearer [random] you would enter Bearer here)”
read authString
sed -i -e “s/startofauthstring/$authString/g” 000-default.conf
sed -i -e “s/startofauthstring/$authString/g” htaccess
else
sed -i -e ‘20d’ 000-default.conf
sed -i -e ‘10d’ htaccess
fi
sed -i -e “s/myc2–1/$linodeName/g” init.tf
sed -i -e ‘s|publickeyhere|’”$pubKey”’|g’ init.tf
sed -i -e ‘s|privatekeyhere|’”$privKey”’|g’ init.tf
sed -i -e “s/127.0.0.1/$adminIP/g” init.tf
sed -i -e “s/10.0.0.0/$c2IP/g” init.tf
sed -i -e “s/mylinodetoken/$linodeToken/g” init.tf
sed -i -e “s/domainhere/$domain/g” init.tf
sed -i -e “s/domainhere/$domain/g” 000-default.conf
sed -i -e ‘s|useragenthere|’”$uAgent”’|g’ 000-default.conf
sed -i -e “s/c2IPhere/$c2IP/g” 000-default.conf
sed -i -e “s/domainhere/$domain/g” htaccess
sed -i -e ‘s|useragenthere|’”$uAgent”’|g’ htaccess
sed -i -e “s/c2IPhere/$c2IP/g” htaccess
terraform init
echo “====>Running terraform plan for the new redirector…”
terraform plan
echo “====>Applying the terraform plan…”
terraform apply

You can see in the example above how bash captures config info from the user, performs replacements in the local files (init.tf is the terraform config file and the other files are the local versions of the apache config files that we will need on the newly stood up redirector: 000-default.conf and htaccess (is renamed to .htaccess when it is uploaded to the redirector). Then the bash script runs terraform.

  • terraform: Stands the hosts up in the specified provider and runs inline commands to configure the host (ex: installs software, configures firewall rules, etc.)

====> Here is an example terraform script that stands up a mod_rewrite redirector after it is modified by the bash script above:

terraform { 
required_providers {
linode = {
source = “linode/linode”
version = “1.14.3” } }}
provider “linode” {
token = “mylinodetoken”
}
resource “linode_instance” “myc2–1” {
image = “linode/ubuntu20.04”
label = “myc2–1”
region = “us-east”
type = “g6-nanode-1”
authorized_keys = [chomp(file(“publickeyhere”))]
connection {
host = self.ip_address
user = “root”
type = “ssh”
private_key = chomp(file(“privatekeyhere”))
timeout = “2m”
}
provisioner “file” {
source = “000-default.conf”
destination = “/root/000-default.conf”
}
provisioner “file” {
source = “apache2.conf”
destination = “/root/apache2.conf”
} provisioner “file” {
source = “htaccess”
destination = “/root/.htaccess”
}
provisioner “remote-exec” {
inline = [
“sudo apt-get update -y && sudo apt-get upgrade -y”,
“sudo apt-get -y install ufw”,
“sudo ufw default allow outgoing”,
“sudo ufw allow from 127.0.0.1 to any port 22”,
“sudo ufw allow 80”,
“sudo ufw allow 443”,
“sudo ufw — force enable”,
“sudo apt-get install apache2 -y”,
“sudo a2enmod rewrite proxy proxy_http ssl proxy_connect”,
“sudo a2ensite default-ssl.conf”,
“sudo apt-get install -y software-properties-common”,
“sudo add-apt-repository universe”,
“sudo apt install -y certbot && sudo apt install -y python3-certbot-apache”,
“sudo certbot -n -d www.domainhere,domainhere — apache — register-unsafely-without-email — agree-tos — no-redirect”,
“sudo mv /root/000-default.conf /etc/apache2/sites-available/000-default.conf",
“sudo mv /root/apache2.conf /etc/apache2/apache2.conf”,
“sudo mv /root/.htaccess /var/www/html/.htaccess”,
“sudo ufw deny 80”,
“sudo service apache2 restart”,
“sudo apt-get install git”,
]
}
}

The terraform script above is for the Linode provider and takes the ssh key pair along with linode api token, stands up the redirector, and then runs inline commands to configure the redirector (apache2, certbot, etc). You can also see the examples of provisioner scripts above that I leverage to copy apache config files from my local directory with all of the custom information for my domain and mod_rewrite rules and copy it to the newly built redirector.

I personally like this method and it has worked well for me so far. Below are some examples of the automation I have stood up so far. Reminder: the automation included in this post will leverage the built in root account to configure and stand up the redirector. It is recommended that you login, create a local user with sudo and then simply restart apache so that you are not running apache as the root user on your redirector.

Links to my scripts for mod_rewrite and host standup automation. You can apply the same approach to other providers (ex: AWS or GCP) since I leveraged Linode and DigitalOcean in the examples below:

  • Bash + terraform scripts to stand up gophish, evilginx2, or C2 servers in Linode:
  • Bash + terraform scripts to stand up gophish, evilginx2, or c2 servers in DigitalOcean:
  • Bash + terraform scripts to stand up ssl or http mod_rewrite redirectors in DigitalOcean or Linode. I was able to handle the apache configs via terraform by having a local copy of 000-default.conf, apache2.conf, and htaccess with variable placeholders, having my bash script replace the variables with the input added by the user at runtime, and having terraform upload these modified files as provisioners to the newly stood up server:

While this is not the end-all for red team infra automation, this is a good start and will certainly save some time as it relates to infrastructure automation. There are definitely opportunities to build and improve upon automation to save even more time. Happy automating!

--

--

Cedric Owens
Red Teaming with a Blue Team Mentality

Red teamer with blue team roots🤓👨🏽‍💻 Twitter: @cedowens