Introducing Axiom - The Dynamic Pwnstation Orchestrator
In this article, I’m going to discuss my new tool Axiom, a few of the concepts around the project, and some potential use cases. I’ve tried to build Axiom to be as extendable as possible so that power users can really use this new tool as an abstraction to use cloud computing systems into their workflows.
The repository can be found below:
Before we get into this article, if you like this creation and you appreciate the time I’ve spent developing it and refining it to give it away, please use my Digital Ocean Referral link if you’re new to DigitalOcean, this key has a $100 of free credit along with it, that’s enough to run 4 droplets for 4 months! https://m.do.co/c/bd80643300bd
If you already have an account, you can always buy me a coffee at:
If you’re like me, you might already have a hacking VPS setup, and it will have an array of tools. It might also have a very messy scattering of different nmap files, masscan files, and general enumeration stuff. Hacking VPS’s are usually for catching shells, running port scans and hosting malware/c2.
Now the problem with this is:
- If you’re hacking and scanning a lot, you can get IP Blacklisted / Burned
- Your budget is probably not a lot more than $5-$20 a month, so your VPS won’t be particularly powerful
- You don’t need it a lot of the time, necessarily, you only really need it for the odd scan and shell catch, but you certainly don’t need it to run 24/7
- You might want to give somebody access, like a coworker, but want to remove it later
Until now, you could solve this problem only by spending months building an automation setup and learning all the new technologies to automate the deployment of cloud instances to do exactly what you need.
The good news is, I’ve done this, and I’ve packaged it up so that you don’t have to (and hopefully we’ll work together and make it better)
Axiom High level
Axiom has three core concepts to consider. You have instances, boxes, and images.
An instance is a digital ocean droplet, it is an initialized VPS hosted in Digital Ocean. This has an IP address, it can be ssh’d into, it can be deleted whenever we want.
An image is a snapshot of a configured DigitalOcean droplet. Axiom uses a tool known as “packer” that will initialize a new DigitalOcean droplet, run a set of predefined scripts to install tools and configure the server, and then snapshot that instance so that we can use it again. This snapshot is universally known as an image.
A box is a backup-lite if you like. Inside
~/.axiom/boxes/backup-file.txt is a list of files that are to be included and excluded from backups. Simple configuration files such as vim configs, zsh history, zsh config, and the go binary directory are all backed up and restored through boxes. Inside this file also, there is wildcard “*” that specifies every file, and then a few exclusions are made (like cache directories).
Boxes are located at
~/.axiom/boxes/, and can be deleted by just deleting the folder. They can also be deleted with
axiom-boxes rm box .
Typical Axiom Workflow
At a high level, this is how a typical axiom workflow would work.
To install Axiom, you just have a few things you need to understand first. Axiom is just bash, and as such, it relies on other dependencies to actually work. This is one of the shortcomings of bash, but it is also it’s greatest strength. You can build something very quickly and publish it.
The key dependenices are
packer . The exact versions are on the GitHub, and they are important. If you use an old version of jq, packer or doctl, it could break the entire setup. Fzf is not strictly needed but it is recommended if you’re lazy.
The second thing you need to is clone the git repo into
~/.axiom/, this directory contains the entire axiom installation. Ever want to delete axiom? Just delete this directory and it’ll be gone!
The third thing you need to do is set up your axiom.json, this is the config file and is located in
~/.axiom/axiom.json. This file is auto-generated by the
The fourth thing you need to do is kick off your first packer build. To do this, just run
Now if you don’t want to install all this manually, you can run the one-liner, officially this is only supported on Ubuntu Desktop, Linux Mint, and Arch. However, it won’t get you the dependencies for Arch, you’ll have to get those yourself for now.
Just run this one-liner and let it do its thing. You’ll need a DigitalOcean Personal Access Token, you can generate that here:
bash <(curl -s https://raw.githubusercontent.com/pry0cc/axiom/master/interact/axiom-configure)
Once you have axiom installed and setup, you would initialize a new instance. Running
axiom-init will start a fresh instance. You’ll notice that it will auto-select a name and a number, this is taken from an array of historical scientists and some infosec people (easter egg :)). I have intentionally made these names short and with no special characters so that it is easy to type quickly.
When you initialize a new instance, Axiom will write the instance name to a ‘selection profile’, this is a JSON file inside
~/.axiom/profile.json, this makes it easier to perform other functions such as restoring or deployment.
Now your instance is live, you can do several things. The first thing you might want to do is connect to it. You can run
axiom-ssh colden14 (and replace colden14 with whatever your instance was named), and it will connect you to that instance. If you try and connect too soon after init, you might get a connection refused error, but don’t worry, just wait, sometimes it takes an extra 30 seconds or so to fully boot.
When you first SSH in, you’ll notice that you’re dropped into a ZSH prompt.
This first login will also show you your instances public IP, this can be helpful if you need to link to it.
Exploring the file system.
Once you’re connected to your new instance, you might want to take a little look around. Let’s explain what they are now:
- ~/hashes/ contains a set of tools that help you capture hashes, typically for catching NTLM hashes over the internet, responder, smbserver, etc
- ~/c2/ is empty by default, this is used for the installation of c2 with deployment profiles (to this shortly!)
- This directory has all your go binaries, this is in your $PATH by default and has a lot of goodies!
- This contains two of my most frequently used wordlists, Jason Haddix’s all.txt and SecLists
- This directory contains a few recon tools, DNS enumeration, email generation.
- This directory is also a placeholder directory, this is where you would put your work files, or the artifacts left over from your recon. This keeps the home directory nice and tidy. I’m also writing a few enumeration scripts that work with this “work” directory.
If you’ve run a few commands and made some files, it is recommended that you place them in ~/work/. The backup feature backs up your configuration and preferences. For example, if you have made some changes to your ZSH setup, such as a theme, it will be backed up. All you have to do to back up this instance using the
This script basically does a select rsync on the home directory, this includes some dotfiles. You can change which files get included in the backup/restore progress by editing
As we have backed up
colden14, these files will be present in
~/.axiom/boxes/colden14. If we want to see the files, interact and/or edit them, we can use the command
axiom-boxes cd colden14 to enter into that directory.
Now, we can safely kill the instance. To do so, we use the command
This may take a few moments, but when it is complete, our colden14 instance will be completely deleted. We are no longer being billed for this, and it has no presence on the internet any longer. Any data we had on that instance that we did not backup has now been lost forever. Nice.
Now, we can initialize and restore a new instance. I added in a cheeky bit of shorthand to help the process so you can use just one command.
axiom-init --restore=colden14 will do the heavy lifting for us.
Once this new instance
kilby19 is initialized, it will wait 65 seconds for all the services to come up, and then it will trigger the restoration of our backup.
Now that our
kilby19 has been restored with the
colden14 backup, we can connect to it and it will maintain our changes! How awesome is that!
If we wanted to, we could turn this into a one liner. Try this:
alias moto="axiom-init moto --restore=moto && axiom-ssh moto --tmux && axiom-backup moto && axiom-rm moto -f"
This will initialize an instance, called moto, restore from the last moto backup, ssh into moto, and then connect to a tmux session. Once your tmux session ends, aka you detach from it, it will run an axiom-backup against it and delete it. Next time you want to spin up and connect to moto, you just run
This is illustrative of the power of Axiom. You can script all sorts of operations around instances and refer to them by name (without having to care about their ports and IP’s).
Some of the more advanced commands are
If you recall earlier when you initialize a new machine it “remembers” the name of the last instance you spun up. As such, commands like
axiom-deploy allow you to omit the instance name and assume that you’re talking about the last server you spun up. If you don’t want to refer to the instance you just spun up, you can use
axiom-select name to change your profile selection.
To deploy a profile, you just need to run
axiom-deploy profilename and it will deploy whatever profile you specify, at the time of writing profiles include:
- OpenVPN Server
- Covenant C2 Platform
To deploy an OpenVPN Server, we can just run
This will connect to
kilby19, and run a set of commands to install and setup OpenVPN. As we’re all using the same base image, we can package these little scripts together so that they’re universal between all axiom users. If you’d like to write an axiom deployment profile, please refer to the
~/.axiom/profiles/openvpn/manifest.json to get an idea of how it works! Just copy the OpenVPN file and edit the manifest, and you’re off the races!
In the previous step, we deployed OpenVPN using a deployment profile with the
axiom-deploy openvpn command. But now we need to connect to it? To connect and route all your traffic through this instance, just run
axiom-vpn kilby19, of course replacing kilby19 with whatever your instance is called. This will download the client OpenVPN configuration and start openvpn client with it. It will ask for your sudo password to start.
axiom-boxes command is a utility that lets us manage our boxes. To first see what boxes we have available, run
For me, I have quite a few boxes. These are from previous backups and other machines I have used in the past. One of these is pry0cc-lazy, which is a public axiom box I maintain. pry0cc/lazy contains an enumeration script that empowers you to perform automated enumeration against a domain name.
This script is more of a PoC of what Axiom boxes are able of doing, but we’ll show it off now.
To pull a new box, use my example box, run the command
axiom-boxes get pry0cc/lazy.
This will clone my lazy box. Want to try it out? Just start a new instance and restore from it.
Once restored, initialized, and connected to, we can run the
lazy.sh <domain> and it will run our automated enumeration for us.
Once we’ve run that, we can exit and run
axiom-backup noyce20 on that instance, delete it, and inspect the results in
axiom-boxes cd noyce20
I’ve gone through a few cool things you can do to get set up and going! Hopefully, I explained everything satisfactorily here! If you have any questions, drop a comment and I’ll be happy to help! If you liked, this please share this article or whatever you feel like!