Running Powershell Empire in a Docker Container on Ubuntu 16.04

While reading The Hacker Playbook 3, one of the first steps you’ll need to do is to install Powershell Empire. I ran into problems with dependencies between the current version in Git, and the version of Python included with Ubuntu 16.04. Rather than thrash about in dependency hell, I decided I’d opt to use Docker. Using Docker gives you quite a few advantages, some of which are:

  • Easy updates
  • No dependency problems
  • Run multiple instances off the same config

There weren’t too many tutorials out there, so I decided to turn my notes into a blog post in hope that helps others.

Step 0: Do all-the-things as root

For the sake of saving me the time of making sure I preface everything with sudo, we’re just going to elevate our shell to root. Once you get things wrapped up, the most secure way to do things would be to give your normal user access to docker, or just preface your docker commands with sudo. For now though,

sudo -i

Step 1: Install Docker

There’s not a lot to this one, just:

apt install jq

We install jq as well so that we can parse json on the command line for some handy one-liners later in the post.

Step 2: Pull or Build the Image

You can opt to build your own image from the Empire source code, but that’s outside of the scope of this post. Instead, we’ll pull a copy from the global registry:

docker pull empireproject/empire

Step 3: Create a Volume

Now, we’re going to create a docker volume to store the configuration of Empire. If you don’t do this, every time you create a new container, you’ll have to redo the configuration steps. By creating a volume, you are separating the data used by the container from the container itself, allowing it to persist no matter what happens to the container(s) you build. For more on volumes, consult the official Docker docs on them

docker volume create empire-data

You can also create a symlink to the volume in a more handy place, like /opt/. The following will do just that:

mkdir -p /opt/Empire/ && ln -s $(docker volume inspect empire-data \ 
| jq -r .[0].Mountpoint) /opt/Empire/data

Step 4: Create a Container from the Image

Now, we’re going to create our first container from the image. Run this as root:

docker run -it --name empire -v empire-data:/opt/Empire/data \
 -p 443:443 --entrypoint bash empireproject/empire

This command does the following:

  • Creates a container named ‘empire’
  • It mounts the volume named ‘empire-data’ (created in step 3 above) to the directory /opt/Empire/data inside the container.
  • It binds port 443 (HTTPS) on our host to port 443 on the container. This is essentially a “port forward”.
  • It sets the entrypoint to be bash. This means that when we run the container, it will drop us into a bash shell rather than an Empire shell. I found there was a need to run the various scripts and otherwise interact with the container outside the Empire shell and this makes it easy. If you omit the entrypoint argument, you’ll be dropped straight into Empire’s interpreter.

At this point, you’re inside the container. Your current directory is /opt/Empire, to run Empire, just run ./empire to get into the interpreter. When you’re finished, exit the Empire interpreter, and then type exit one more time to exit the container. Note that unlike virtual machines, your container stops running the instant you exit it.

To start the container back up again, you can run:

docker start -ai empire


At this point, you have a single container named ‘empire’ that you can use for all of your C2 needs. Note that if you want to check out an upgraded version, you can just pull down the new image, and run a new container with a different name (e.g. empire-new) to test with. You can create separate volumes to manage separate data sets as well.

Justin Ellison Written by:

Justin works as an InfoSec professional in the retail sector.

comments powered by Disqus