I’ll be starting a new job at CU Boulder soon. One of my responsibilities will be to teach an information security management class to business school students. I don’t know whether there will be a lab available where I can host VMs for students to do vulnerability assessments on, and I can’t just distribute OVAs for this because of how easy it would be to boot into root. So I want to host vulnerable servers on something like AWS. Obvious problem is that vulnerable servers are… vulnerable. I don’t want the boxes to be pwned before the students can start playing with them. So for the last day or so I learned about taking vulnerable VMs and launching them into a VPN on AWS. This post documents what I learned.
Went like this:
- create a VPC on AWS
- configure OpenVPN community on an Ubuntu AMI
- make a vulnerable virtual image
- Export the appliance and convert it to an AMI
- launch 1-to-many instances of your vulnerable AMIs into the VPN
Create a VPC
I created a new VPC intended just for vulnerable servers + the OpenVPN server. I created two subnets: one default public, where I put the openVPN server, and another default private, where all the violator instances were launched.
In my config:
- vpc with subnet
18.104.22.168/16. Your CIDR just has to be different from whatever VPCs you already have.
- created a new internet gateway, attached it to the new VPC
- Two subnets, named one ‘vulnerable-public’ and the other ‘vulnerable-private’, CIDR’s
- Edited the route table for the public subnet to include the new internet gateway: Destination
<the gateway>. This will allow OpenVPN to access the interwebs.
- While in the VPC Dashboard, check your Network ACLs, and make sure that your inbound rules allow all traffic. Also check your default security group for your new VPC, and change the source to
0.0.0.0/0. (I don’t use the default for the openvpn server, just for the instances launched into the private-only subnet).
Now I’ll admit something: that last step took me late into the night. I must have kept looking over the Source error in the security rule, I could not figure out why I couldn’t ssh into my openvpn server. I’m pretty certain the security group stuff here is the same as it is on the ec2 dashboard page. Note to self though, if no connectivity, it’s almost certaintly security group stuff somewhere.
Note 9/26/2017: Looks like the default nowadays is for the ACLs to allow all inbound/outbound traffic by default.
It’s important to note that your vulnerable VMs will not have access to the internet. For that, you would need a NAT Gateway. VPC has a handy wizard which will set that up for you, but I don’t need my vulnerable VMs to have internet access.
Configure OpenVPN community on an Ubuntu AMI
Now from the EC2 dashboard. I created a new micro instance from an official ubuntu 16.04 AWS AMI.
During the launch config:
- Change Network to the new VPC
- Change Subnet to your public one
- Click through to configure the security group. I created one that matches the one created by the official (but paid) OpenVPN Access Server marketplace AMI. That security group does this:
Custom UPD | 1194 | 0.0.0.0/0
Custom TCP | 943 | 0.0.0.0/0
HTTPS | 0.0.0.0(not necessary for the community version though)
SSH | 0.0.0.0/0
- Create a new keypair, download the pem, and if on Windows, use puttygen to load it and save the private .ppk file.
Aaaand launch and then ssh in, following the
sudo when not root.
Note: if you get an error about ‘unable to resolve host’ when you try sudo, then add
/etc/hosts localhost entry.
apt-get update -y && apt-get upgrade -y apt-get install openvpn easy-rsa cd /etc/openvpn/ mkdir easy-rsa cp -r /usr/share/easy-rsa/* /etc/openvpn/easy-rsa/ vim vars # edit parameters at bottom to whatever su - cd /etc/openvpn/easy-rsa . ./vars ./clean-all ./build-ca ./build-key-server server # I didn't set a password ./build-key client # I didn't set a password. ./build-dh cd keys cp ca.crt server.crt server.key client.key client.crt dh2048.pem /etc/openvpn exit # to leave root openvpn --genkey --secret secret.key cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz /etc/openvpn/ gzip -d /etc/openvpn/server.conf.gz vim server.conf
- push the CIDR for your entire VPC. In my case,
push "route 22.214.171.124 255.255.0.0"
- change tls-auth line to be
tls-auth secret.key 0
duplicate-cn(Important!). This allows multiple clients to connect using the same certificate, which is our situation
client-to-clientto let metasploit exploits connect back to listeners on kali
vim /etc/sysctl.conf, uncomment
sysctl -p iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
-shere should be the CIDR that you set in the
serverdirective in server.conf, not your VPC CIDR.
- also put that
iptablesline into in
Now test that you can launch the server.
openvpn --config /etc/openvpn/server.conf # to test that everything is working openvpn --daemon --config /etc/openvpn/server.conf # when ready
- note that if you restart your instance, openvpn will launch as a service (e.g.,
service openvpn start, so you won’t be able to run the last two commands unless you shut it down via
service openvpn stop
Now, get your
client.conf prepared for distribution to the kali boxes.
Whatever you name your client conf, don’t put it in
/etc/openvpn with a
*.conf extension. If you do,
service openvpn start will run it, as well as your
server.conf in that directory. That will make your box both a server and a client to itself, which leads to bad times and headaches.
cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf /etc/openvpn/client.conf.for-kali
- Set your open vpn public server ip in
remote ... 1194. Add elastic ip to your openvpn aws instance when ready so that you don’t have to keep changing this every time you start/stop your vpn instance.
- Add your secret.key contents inside a
<tls-auth>block, and also add
key-direction 1after. See my redacted client.conf below. See here for a discussion of inline certs.
Do not put any
route statements in
client.conf. Let the server do the pushing.
scp or whatever your client.conf down off the server, and try connecting while your openvpn server is running. On Kali, just run
openvpn client.conf. Then to test that it’s all working, run
ifconfig and look for a
tun interface. Try pinging the openvpn host, in my case, 10.8.0.1.
route on Kali, and confirm that you have a
destination entry for your vpn CIDR – in my case,
10.8.0.0 10.8.0.x 255.255.255.0, where
x is the ip of the destination gateway for your
tun interface (viewable in
On Windows, with the OpenVPN community GUI, you can just rename your
client.ovpn and import that into the tool, then connect.
Full conf files
Make a vulnerable virtual image, then export it
I skipped this step, but here you’d create a VM however you like, making it nice and vulnerable. Then you export your image into a format that AWS likes. There are several acceptable formats for AWS mentioned in the docs, OVA included. In VirtualBox, you can export a VM as an OVA using
File > Export Appliance....
The important thing to note here is that only certain OSes are compatible with AWS’s AMI format. Thankfully, the list is long.
Letting the vulnerable VMs talk back to connected VPN clients
If you want to be able to run metasploit shell exploits, the vulnerable VMs need to have a route to the connected VPN clients (to the attack machines). This is because metasploit launches listeners, then executes payloads on victim machines that reach out to the listener. The solution I came up with for doing this is to put each of the vulnerable VMs on the VPN, too, but to change their client.conf a bit.
- Install openvpn to your image.
- Change client.conf
remotedirective to point to the private ip address of your openvpn instance, not the public one (remember, the instances in the private network don’t have internet connectivity)
- Add two more lines to
client.confthat goes on the vulnerable vms (do not put these in the client.conf that Kali uses!):
route-nopull(this blocks the vpn connection from clobbering the private network route that already exists for your VPC via the ‘push route’ statements, in my case, 126.96.36.199/16.
route 10.8.0.0 255.255.255.0(Set your vpn server’s
serverdirective CIDR network here. This lets the vulnerable servers talk to clients on the VPN network, when combined with the
client-to-clientdirective in server.conf)
- This route statement is necessary because we said
route-nopull, which otherwise would have set the
- This route statement is necessary because we said
/etc/defaults/openvpn on the vulnerable vms and add a line for
AUTOSTART="client", then put your edited client.conf in /etc/openvpn. With it there, it should be automatically started on boot.
If you forgot to do this step before you imported your VM image into AWS, you can edit one of your launched images, then make a new AMI image based on that running instance. Faster than reuploading the whole thing to S3.
Convert your image to an AMI
You’ll need the AWS CLI. Download it, and then give it your root credentials by running
aws configure so that you can follow the next steps.
The process for creating an AMI involves:
- uploading your
.ovato an S3 bucket,
- creating an IAM
VM Import Service Role,
- invoking the magic spells in the aws console to import the image from S3 into an AMI.
Note: upload your
.ova into the S3 bucket in the region where you want your
openvpn server to run. When you run the commands to convert the
.ova into an AMI, the bucket region will determine in which region the AMI ends up.
If you import it into the wrong region, you can copy your AMI to a different region thusly
Docs here. First follow these steps for creating a VM Import Service Role. Then, upload the VM image file to S3 (I used the browser interface to upload). Then follow the last step to initiate the import transfer.
Went smoothly for me, although the actual import (the last step) took 10+ minutes. When you create your own AMI, AWS launches a copy of your instance appliance and then takes a snapshot of it. That snapshot will be associated with your new AMI, and is not deletable unless you first unregister your AMI. So be aware, you’ll be paying for the storage of that snapshot as long as you have the AMI. Note that your AMI will only show up in the view for the region where you deployed it.
Note: When you convert your
.ova into an AMI, any network interface that it used to have are replaced with one that will work with EC2. The new network interface should
automatically obtain a private ip in the subnet that it’s launched in when it starts up.
Note 9/26/2017: When I used the aws cli on Linux, I had to run
sudo ntpdate time.nist.gov before the s3 commands would work.
Launch a gazillion Violators
- Launch them into the correct
Network, and for the
Subnet, into the private subnet so that they don’t get a public ip.
- “Proceed without a keypair”
- Change to a security group setting that allows “All Traffic” inbound.
- You can launch multiple at once at “Step 3: Configure Instance Details” > “Number of instances”
Try pinging their ips from a client that’s connected to the VPN. Then try exploiting them. Important: In
LHOST, use kali’s vpn ip address from
but you can target the private-ip address of the vulnerable vms (the
172. addresses for me – you don’t need to target or know the vulnerable vm’s vpn tun0
three six times if great success.
client-to-client is enabled, students can theoretically attack other students’ kali instances if they’re both connected to the vpn at the same time.
Kali doesn’t have a listening ssh server by default, so known-password isn’t a vector. (They’ll likely not have changed the password from what it
was when you distributed VM instances to them…)