Virtual machines are great for various purposes,
- run Kali to hack things, not risking your work/home machine to any adverse effects – if you pwn them, don't let them pwn you.
- research vulnerable software or OSes
- practice setting up things
- try out new OSes
I used to use VirtualBox for all of this. It's OK for light use only. Once, while teaching a workshop, I ran a bunch of vulnerable servers in a private network, bridged that network to a wifi AP, and routed that network's traffic to the internet through a pfsense running as guest, so students could pwn my boxes and use google at the same time. In principle this was a great idea but in practice, the virtualbox kernel driver crashed when the students nmapped and fuzzed my boxes.
I found out about ProxMox and have been happily using it for some time now.
Download the installer image, write it to a USB stick and install it. Give the proxmox computer a static IP in your production LAN. Proxmox only works with a static IP and can't be practically migrated to another address or subnet. Configure the domain name to match that of your pfsense setup.
ISO files are stored in
/var/lib/vz/template/iso/ on proxmox. To get the files there, either ssh to the box and run
wget in the directory, or
scp them over from another computer.
The web GUI can be used to create and interact with virtual machines with quite the same features as on VirtualBox.
You can convert all your trash PCs into a proxmox cluster. Refer to the documentation on how to create a cluster and add nodes to it.
I'm running Proxmox on a few PCs. I bought two used Lenovo S30 workstations with 8-core Xeons, one with 32gig and the other with 64gigs RAM, from workstation4u.de. I think they are a very cost effective way to build a platform able to host a few dozen VMs with reasonable performance.
It doesn't make sense to manually create and install a new VM every time I need a new server instance. Luckily, Proxmox supports
cloud-init. Cloud-init is used to automatically configure and provision a new VM based on a template.
The basic workflow to create a new cloud-init template is:
- create a new VM
- install it manually, configure any additional software you need in the template
- install, configure and enable
cloud-initon the VM
- convert the VM to a template
Preparing a Kali template
Create a new VM, call it eg.
kali-template, and start it with a recent enough Kali installation image. When installing it, also specify
kali-template as the hostname or anything that doesn't look like any of your production machines / VMs, to avoid confusion.
When creating the VM, create a disk just barely large enough to contain the OS. I've found 15G is fine for Kali. The partition table should look like this:
- primary 1, 512MB, used as
- primary 2, 1 or 2 gigs, used as swap
- primary 3, the rest, used as
Don't use LVM. Cloud-init can't resize an LVM volume. With
/ as the last partition on the disk, cloud-init will resize the root filesystem to fill the remaining space on the disk.
Now boot into the Kali when it's done installing, then install cloud-init by
apt-get install cloud-init ; systemctl enable cloud-init ; systemctl enable cloud-final.
Modify the kernel command line in
/etc/default/grub to read:
GRUB_CMDLINE_LINUX_DEFAULT="net.ifnames=0 biosdevname=0 console=tty1 console=ttyS0"
/etc/cloud/cloud.cfg.d/99_pve.cfg file to read:
datasource_list: [ ConfigDrive, NoCloud ]
Then replace the
/etc/cloud/cloud.cfg file with this one. I'm not sure it's done right, seems to work for me, YMMV. The differences to the original one that comes with the cloud-init package are:
- it configures the kali repositories on the guest instead of whatever is default (debian)
- default username is
- After first boot, when cloud-init is done configuring the guest, the machine reboots. This is because the guest sets its hostname after starting the network, and on first boot the hostname changes from that of the parent template to the value configured for the guest. Rebooting the guest after the first boot makes it available on the network with its actual name. (This is a hack – I found it easier to just reboot the box instead of hacking cloud-init to restart its network after the hostname has changed)
One more thing, enable ssh by
systemctl enable ssh.
Last, when the VM to be used as template is ready, it needs to be converted into a Proxmox template, by running
qm template [VMID]. This can't be undone. If you want to modify the template afterwards, either create a full clone of it when you need to change it, or clone the image before templating it and edit that, then convert into template, etc.
Preparing a Ubuntu or Debian template
The above steps apply, except
/etc/cloud/cloud.cfg is good as is except for the hostname hack. Append this to the end of that file:
power_state: delay: "now" mode: reboot message: fuck off timeout: 240 condition: True
Instantiating cloud images
I created this handy script to create new VMs off templates created as described above:
#!/bin/bash source=$1 target=$2 name=$3 sizeplus=$4 mem=$5 cores=$6 if [ -z ""$cores ] ; then echo usage: $0 sourceid targetid name +size mem cores echo example: $0 800 200 kali +20G 8192 8 exit fi qm clone $source $target --name $name qm set $target --ide2 local-lvm:cloudinit qm set $target --boot c --bootdisk scsi0 qm set $target --serial0 socket --vga serial0 qm set $target --sshkey /root/keys/id_rsa.pub qm set $target --ipconfig0 ip=dhcp qm set $target --cores $cores qm set $target --memory $mem qm resize $target scsi0 $sizeplus
I've saved that as
root's home directory. Note that the script excepts your pubkey to exist as
cloud.cfg file specifies your default username. If it's
john, and you named your box
pwnbox, you should be able to just
ssh john@pwnbox when it's done initializing and rebooting itself.
So, if I have a Kali template with id 816, and I want a new VM with id 510, I'm running
# ./createvm.sh 816 510 pwnbox +10G 8192 8
This creates a new VM called “pwnbox”, gives it 10 gigs more disk as what the template has, assigns it 8 gigs of ram and 8 cores. To run the new box, execute
qm start 510. After a while it will be available as
pwnbox in the lan. (My pfSense has DNS Resolver configured so it resolves DHCP leases by their hostname). The script above configures the guest to use serial terminal, so I can watch it boot by running
qm terminal 510.