How to configure PXE network booting for Kali Linux

I had this blog post in the pipeline for too long, so I am finally happy to publish this tutorial on how to setup PXE to network boot a Kali Linux live system.

Most mainboards allow to boot an operation system from the network. It can be useful when no operating system is installed on the device itself or when the operating system is broken. The Preboot Execution Environment (PXE) and your DHCP server can then communicate with each other and allow you to boot i.e. a live system to fix your computer.

For this whole setup to function properly, I assume that you have a linux-based gateway somewhere in your network with an own private IPv4 subnet. As I said before, the goal will be to boot a Kali live iso over the network on another computer.

My testbed

As I didn't have a separate system at hand, I decided to go with two VirtualBox VMs bridged together. For that, I created a dummy interface on my host system with the following commands:

$> sudo ip link add dummy type dummy
$> sudo ip link set dummy up
$> ip link
5: dummy: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
    link/ether c6:83:44:b9:dd:26 brd ff:ff:ff:ff:ff:ff

Afterwards I spun up two VMs and bridged them to the dummy interface:

  • A Server VM with two interfaces: 1x NAT + 1x Bridge
  • A Client VM with one interface: 1x Bridge

The Server VM boots a simple Debian 9 live iso, so that we start the configuration from scratch.

DHCP configuration

After the boot process has finished, the Server VM shows the following two interfaces:

$> sudo ip link
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:b5:3e:ca brd ff:ff:ff:ff:ff:ff
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:af:53:f1 brd ff:ff:ff:ff:ff:ff

The first one, enp0s3, is the NAT'ed interface, so that we can install software from the internet. The other one is the bridge to dummy over which the Client will boot kali.

PXE looks for a DHCP/BOOTP server on the network to get information about from where to boot. That means, we'll have to install and configure a DHCP server first :

$> sudo apt-get install isc-dhcp-server

We only want it to listen on the "internal" interface, so we need to adjust the configuration file in /etc/default/isc-dhcp-server accordingly.

$> sudo cat /etc/default/isc-dhcp-server | grep -v "#"
INTERFACESv4="enp0s8"
INTERFACESv6=""

And now we'll tell the DHCP server to serve a private subnet to our clients. I decided to use 192.168.5.0/24 here and the resulting /etc/dhcp/dhcpd.conf should look like this:

$> sudo cat /etc/dhcp/dhcpd.conf 
subnet 192.168.5.0 netmask 255.255.255.0 {
  range 192.168.5.10 192.168.5.100; #You can change this
  option domain-name-servers 8.8.8.8; #You can change this
  option domain-name "pxe.boot"; #You can change this
  option routers 192.168.5.1;
  default-lease-time 600;
  max-lease-time 7200;
  allow booting;
  filename "pxelinux.0";
}

The important bits here are the allow booting and filename "pxelinux.0" options which enable the network booting. The other ones can be different or adjusted by you depending on your setup. We'll see the pxelinux.0 again in a second.

TFTP configuration

Let's continue with the Trivial File Transfer Protocol (TFTP) daemon that we'll use to send the boot files and finally a filesystem over to the devices that would like to boot.

Install tftpd-hpa and restart the DHCP and TFTP server:

$> sudo apt-get install tftpd-hpa
$> sudo systemctl restart isc-dhcp-server tftpd-hpa

TFTP's configuration file is not long and does not need any changes:

$> cat /etc/default/tftpd-hpa
# /etc/default/tftpd-hpa

TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="--secure"

So far, so good: If you start up the "Client" VM, it should try to boot, but complain about missing files:

Boot configuration

The final step is to put the right files in the right location and the network boot should work :-)

As configured above, TFTP looks for files in the folder /srv/tftp. To keep everything clean and tidy, we'll create a separate folder for Kali and the PXE:

$> sudo mkdir /srv/tftp/kali /srv/tftp/pxelinux.cfg

Next, we have to create several files:

  • pxelinux.0
  • pxelinux.cfg/default
  • menu.cfg
  • vesamenu.c32

Download the pxelinux.0 and vesamenu.c32 files from Debian's repository. Both are needed to initiate and display the boot selection menu.

$> sudo wget https://cdn-aws.deb.debian.org/debian/dists/wheezy/main/installer-amd64/current/images/netboot/pxelinux.0 -O /srv/tftp/pxelinux.0
$> sudo wget https://cdn-aws.deb.debian.org/debian/dists/wheezy/main/installer-amd64/current/images/netboot/debian-installer/amd64/boot-screens/vesamenu.c32 -O /srv/tftp/vesamenu.c32

The file /srv/tftp/pxelinux.cfg/default should have the following content:

$> sudo cat pxelinux.cfg/default
include menu.cfg
default vesamenu.c32
prompt 0
timeout 0

We'll use menu.cfg to define what systems can be booted over the network. In our case we'll just have one entry pointing to our kali files:

$> sudo cat menu.cfg
default kali
label kali
        menu label kali
        menu default
        kernel kali/vmlinuz
        append initrd=kali/initrd.img boot=live components username=root hostname=kali-live fetch=tftp://192.168.5.1/kali/filesystem.squashfs

Trying to boot over the network should result in a simple looking boot menu with an option labelled kali:

But it still will fail to boot, because it won't find the referenced kali/vmlinuz, kali/initrd.img and kali/filesystem.squashfs.

The easiest way to obtain them is to download the one of the Kali ISOs from their download page. I used 7z for the sake of simplicity to extract the contents from the .iso:

$> mkdir /tmp/kali && cd /tmp/kali
$> wget http://cdimage.kali.org/kali-2018.3a/kali-linux-light-2018.3a-amd64.iso
$> 7z x kali*.iso

Copy the aforementioned three files into the /srv/tftp/kali folder:

$> sudo cp ./live/{initrd.img,vmlinuz,filesystem.squashfs} /srv/tftp/kali/

After that the boot process should work!

The fetch kernel parameter will instruct the system to download the filesystem.squashfs using TFTP and then using it as the root file system.

Depending on the network speed, this will take a couple of seconds, but in the end the kali desktop environment should appear!

-=-