Building a Kali Box with Vagrant+Ansible (Part Two)

In Part One of this tutorial (https://terasq.io/2019/03/building-kali-with-vagrant-ansible-p1/), we created a simple Vagrantfile and playbook.yml file to provision a Kali Light box and install a couple of pieces of software.

In Part Two, I will go over some additional Vagrant and Ansible options that will enable us to create a more customized Kali box.

NOTE: This tutorial is built using the offensive-security/kali-linux-light base box because it is lightweight, but you could just as easily do all of the same things using the full offensive-security/kali-linux base box. The main difference is that many of the Ansible apt tasks are unnecessary, as the software comes pre-installed.

Advanced Machine Settings

First, let’s take a look at the Vagrantfile we built in Part One:

Vagrant.configure("2") do |config|
config.vm.box = "offensive-security/kali-linux-light"
config.vm.network "public_network"

config.vm.provision "ansible_local" do |ansible|
ansible.playbook = "playbook.yml"
end
end

Pretty simple. It’s provisioning a machine using the Kali Light base box from Offensive Security, setting up a public network, and running our Ansible playbook. This means that it is using whatever settings are specified by the base box (2048 MB of memory, 8 MB of video memory, 2 processors).

That’s not bad, but for the sake of argument let’s assume we want to increase. The VirtualBox provider in Vagrant lets us customize all of those settings (and more).

First, we need to add a provider block to our Vagrantfile:

Vagrant.configure("2") do |config|
config.vm.box = "offensive-security/kali-linux-light"
config.vm.network "public_network"

config.vm.provider "virtualbox" do |v|
end


config.vm.provision "ansible_local" do |ansible|
ansible.playbook = "playbook.yml"
end
end

Next, we can add a few options. First, let’s give our machine a human-friendly name…

 v.name = "Kali Light"

…increase the system memory…

    v.memory = "4096"

…increase the number of processors to 4…

    v.cpus = 4

…and set the machine to headless…

    v.gui = false

Now our Vagrantfile looks like this:

Vagrant.configure("2") do |config|
config.vm.box = "offensive-security/kali-linux-light"
config.vm.network "public_network"

config.vm.provider "virtualbox" do |v|
v.name = "Kali Light"
v.memory = "4096"
v.cpus = 2
v.gui = false
end


config.vm.provision "ansible_local" do |ansible|
ansible.playbook = "playbook.yml"
end
end

More advanced settings can also be modified using the customize setting, along with the modifyvm directive (https://www.virtualbox.org/manual/ch08.html#vboxmanage-modifyvm):

    vb.customize ["modifyvm", :id, "--vram", "64"]

Advanced Playbooks

Next we’ll modify our playbook to include some customization options beyond just installing additional apt packages. Let’s take a look at the playbook.yml we built in Part One:

- hosts: all
become: yes
tasks:
- name: Update repositories cache
apt:
update_cache: yes

- name: Install a list of packages
apt:
name: "{{ packages }}"
vars:
packages:
- dirb
- sqlmap

Not super exciting, but it gets the job done. Let’s make a couple of tweaks. We’ll specify a number of seconds our cache is valid, and we’ll add a line to the “Update repositories cache” task to also upgrade our installed packages.

Note that this will take quite a while, so you may want to comment this out until you’re finished testing.

  - name: Update repositories cache
apt:
update_cache: yes
cache_valid_time: 86400
upgrade: full

Next, let’s add some commonly used packages to our list of apt packages to install:

  - name: Install a list of packages
apt:
name: "{{ packages }}"
vars:
packages:
- dirb
- sqlmap
     - tmux
     - git
     - apache2
     - postgresql
     - metasploit-framework
     - tshark
     - john
     - hydra
     - aircrack-ng
     - nikto
     - wordlists

Easy. Now, let’s add a Bash alias for ls. This is really just an example that you can follow to add whatever aliases you prefer. The lineinfile play will check for a specific line in a file and, by default, add it if it’s missing.

   - name: Add bash aliases
    lineinfile:
      dest: /root/.bashrc
      line: "alias ls='ls --color=always -lah'"
      regex: "^alias ls="
      create: yes

Finally, let’s get everything set up and ready for Metasploit. This is a more complicated play that you could define in a separate playbook and then import, but that is a topic for another tutorial. For now, we’ll add three new plays to our existing playbook.yml:

   - name: Start service apache2, if not started
    service:
      name: apache2
      state: started

  - name: Start service postgresql, if not started
    service:
      name: postgresql
      state: started
      
  - name: Initialize msfdb
    shell: "{{ item }}"
    with_items:
    - "update-rc.d postgresql enable"
    - "msfdb init"
    - "touch /usr/share/metasploit-framework/.initialized"
    args:
creates: "/usr/share/metasploit-framework/.initialized"
warn: false

This starts the apache2 service, the postgresql service, and then runs a shell script that: 1) sets postgresql to start automatically, 2) runs the msfdb init script, and 3) creates the .initialized file within the MSF directory. This last step, in conjunction with the creates option will make the task idempotent (meaning, basically, that running it multiple times won’t break things).

Packaging

Summary of Vagrant Commands

Previously we were only using vagrant up, but there are additional commands that will come in handy, which you can see by typing vagrant at the command line:

  • vagrant destroy: stops and deletes all traces of the vagrant machine (does not delete the base box from the cache)
  • vagrant halt: stops the vagrant machine (gracefully if it can)
  • vagrant package: packages a running vagrant environment into a box
  • vagrant provision: provisions the vagrant machine (re-reruns the provisioning script, without undoing any prior provisioning)
  • vagrant reload: restarts vagrant machine, loads new Vagrantfile configuration
  • vagrant resume: resume a suspended vagrant machine
  • vagrant ssh: connects to machine via SSH
  • vagrant suspend: suspends the machine
  • vagrant up: starts and provisions the vagrant environment

We can continue to use vagrant to manage and access our machine, but we can also export the fully configured virtual appliance. Let’s use vagrant package to export our configured machine as a .box file:

vagrant package

We should see the following…

 ==> default: Attempting graceful shutdown of VM...
==> default: Clearing any previously set forwarded ports...
==> default: Exporting VM...
==> default: Compressing package to: /Users/ryanjo/git/kali-vagrant/pt2/package.box

Box files are tarballs (.tar.gz). We can see the contents with:

tar tf package.box
 ./vagrant_private_key
./box.ovf
./Vagrantfile
./box-disk001.vmdk

We can extract the box.ovf and box-disk001.vmdk…

tar xzf package.box box.ovf box-disk001.vmdk

…and then import the .ovf into VirtualBox on any machine:

Next Steps

In future posts, I’ll get into multi-machine configurations and how you can use them to create your own cyber range. Until next time, happy hacking!

Sample files from Part 2 can be found here: https://github.com/calypso15/kali-vagrant

Leave a Reply

Your email address will not be published. Required fields are marked *