Secure Kali Pi 2018
Secure Kali Pi 2018
We have covered how to create secure “throw-away hack boxes” using the Raspberry Pi before,
but we thought it was time to go back and take a look at the process
again. With all the new Raspberry Pi models and Kali changes from when
we last covered this, we found the old process was in need of some
updating.
As a review, what we are trying to
accomplish is to create a standalone “leave behind” device that, when
discovered, does not make it easy to figure out what you were doing. So
we use the LUKS full disk encryption along with the LUKS Nuke capability
to put this together. If you have a Raspberry Pi 3 Model B+, or really
any other model or similar device, feel free to use the instructions
below to set up your own secure system. This updated process is based on
our previous documentation, and updated with some community suggestions.
Overview of the process
Before we dive into the tech of what we
are going to try to accomplish, let’s take a quick look at our goals on
setting up our Raspberry Pi 3 Model B+ (henceforth called “RPi”):
- Create a normal Kali Linux RPi installation
- Prepare the system for encrypted boot with remote disk unlock
- Create an initramfs configured with Dropbear and SSH keys to allow the unlock to occur
- Backup existing data
- Configure the encrypted partitions
- Restore our data
- Configure LUKS Nuke
- Hack away!
This might seem like a lot, but its
really pretty straightforward and once completed, we will be left with a
RPi that will boot, get an IP from DHCP, and Dropbear will allow us to
connect via SSH to provide the LUKS key. This permits us to run the RPi
headless, but still keeping our data secure. Then down the road when we
are done with it, we can retrieve it or remote in and destroy our data
with LUKS NUKE.
Preparing the Base system
To start with, we need to write out the
RPi image to a SD card. We won’t get into that here, but you can find
information on doing so in our docs.
With that out of the way, we insert the
SD card into the RPi and let it boot up. On first boot, it will resize
the SD card and reboot, after that it’s ready for use. Next, we connect
over SSH, update Kali, and install a few packages we will need.
apt update
apt dist-upgrade
apt install cryptsetup lvm2 busybox dropbear
apt dist-upgrade
apt install cryptsetup lvm2 busybox dropbear
Doing the Magic-Fu
The RPi is all setup and ready to go so
let’s get our hands dirty and dive into things. Take note, once we start
this process, we are going to be changing a number of critical files on
our RPi installation. It is important to not reboot the device or
otherwise shut down the system until you are ready or you will be left
with a system that won’t boot.
First off, we need to append a line to /boot/config.txt:
echo initramfs initramfs.gz followkernel >> /boot/config.txt
Next, we want to validate where our actual root filesystem device is located:
root@kali:~# cat /etc/fstab
# proc /proc proc defaults 0 0
/dev/mmcblk0p1 /boot vfat defaults 0 2
/dev/mmcblk0p2 / ext4 defaults,noatime 0 1
# proc /proc proc defaults 0 0
/dev/mmcblk0p1 /boot vfat defaults 0 2
/dev/mmcblk0p2 / ext4 defaults,noatime 0 1
Take special note that our root filesystem lives at /dev/mmcblk0p2.
This is what we will use for our examples going forward, so be sure to
update the instructions with whatever value you received on your system.
Now that we know our root filesystem location, we will edit the /boot/cmdline.txt . By default, it contains the following:
root@kali:~# cat /boot/cmdline.txt
dwc_otg.fiq_fix_enable=2 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait rootflags=noload net.ifnames=0
dwc_otg.fiq_fix_enable=2 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait rootflags=noload net.ifnames=0
Take note of the entry reading root=/dev/mmcblk0p2. We are going to update it with a cryptdevice value:
root=/dev/mapper/crypt cryptdevice=/dev/mmcblk0p2:crypt
With the change made, our file looks like this:
root@kali:~# cat /boot/cmdline.txt
dwc_otg.fiq_fix_enable=2 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mapper/crypt cryptdevice=/dev/mmcblk0p2:crypt rootfstype=ext4 rootwait rootflags=noload net.ifnames=0
dwc_otg.fiq_fix_enable=2 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mapper/crypt cryptdevice=/dev/mmcblk0p2:crypt rootfstype=ext4 rootwait rootflags=noload net.ifnames=0
We also need to edit /etc/fstab and replace the device where our root filesystem currently is to be /dev/mapper/crypt:
root@kali:~# cat /etc/fstab
# proc /proc proc defaults 0 0
/dev/mmcblk0p1 /boot vfat defaults 0 2
/dev/mapper/crypt / ext4 defaults,noatime 0 1
#/dev/mmcblk0p2 / ext4 defaults,noatime 0 1
# proc /proc proc defaults 0 0
/dev/mmcblk0p1 /boot vfat defaults 0 2
/dev/mapper/crypt / ext4 defaults,noatime 0 1
#/dev/mmcblk0p2 / ext4 defaults,noatime 0 1
Next, we need to create a /etc/crypttab file containing the following:
crypt /dev/mmcblk0p2 none luks
Take special care here–the separators between the entries have to be tabs,
not spaces. Now, before we start to create our initramsfs, we need to
do a sly little hack to force cryptsetup to be included. To do this, we
will create a fake LUKS filesystem. We dd an empty file, format it as LUKS, mount it, and put a filesystem on it.
dd if=/dev/zero of=/tmp/fakeroot.img bs=1M count=20
cryptsetup luksFormat /tmp/fakeroot.img
cryptsetup luksOpen /tmp/fakeroot.img crypt
mkfs.ext4 /dev/mapper/crypt
cryptsetup luksFormat /tmp/fakeroot.img
cryptsetup luksOpen /tmp/fakeroot.img crypt
mkfs.ext4 /dev/mapper/crypt
Don’t worry too much about setting a strong password for this fakeroot as it is only used in this instance.
Setting up SSH and Initramfs
Now we are on the home stretch. This
part is really cool, as normally when a system running LUKS starts up,
the boot process pauses to allow you to unlock the HDD with your LUKS
key. If you are running a headless system, that’s not especially
convenient.
To work around that, we are going to
configure Dropbear to start up, allow you to authenticate with SSH, and
then connect you to provide your LUKS password–all from remote!
We start out by creating a file at /etc/dropbear-initramfs/authorized_keys that contains:
command="export PATH='/sbin:/bin/:/usr/sbin:/usr/bin'; /scripts/local-top/cryptroot && kill -9 `ps | grep -m 1 'cryptroot' | cut -d ' ' -f 3` && exit"
Its important to note, this needs to be
all on one line. No line breaks in there at all. If you have this set up
right, it should look similar to this:
root@kali:~# cat /etc/dropbear-initramfs/authorized_keys
command="export PATH='/sbin:/bin/:/usr/sbin:/usr/bin'; /scripts/local-top/cryptroot && kill -9 `ps | grep -m 1 'cryptroot' | cut -d ' ' -f 3` && exit" ssh-rsa AAAAB3NzaC... user@system
command="export PATH='/sbin:/bin/:/usr/sbin:/usr/bin'; /scripts/local-top/cryptroot && kill -9 `ps | grep -m 1 'cryptroot' | cut -d ' ' -f 3` && exit" ssh-rsa AAAAB3NzaC... user@system
Next, we make a small change to /usr/share/initramfs-tools/scripts/init-premount/dropbear.
This change is due to the fact that we need to slow down Dropbear to
ensure that networking is set up before Dropbear kicks in. At the end of
the file, where it reads:
# On NFS mounts, wait until the network is configured. On local mounts,
# configure the network in the background (in run_dropbear()) so someone
# with console access can enter the passphrase immediately. (With the
# default ip=dhcp, configure_networking hangs for 5mins or so when the
# network is unavailable, for instance.)
[ "$BOOT" != nfs ] || configure_networking
run_dropbear &
echo $! >/run/dropbear.pid
# configure the network in the background (in run_dropbear()) so someone
# with console access can enter the passphrase immediately. (With the
# default ip=dhcp, configure_networking hangs for 5mins or so when the
# network is unavailable, for instance.)
[ "$BOOT" != nfs ] || configure_networking
run_dropbear &
echo $! >/run/dropbear.pid
We want to add in a simple sleep statement like so:
[ "$BOOT" != nfs ] || configure_networking
sleep 5
run_dropbear &
echo $! >/run/dropbear.pid
sleep 5
run_dropbear &
echo $! >/run/dropbear.pid
With that completed, we are finally ready to create our initramfs!
mkinitramfs -o /boot/initramfs.gz
Before proceeding, we ensure that our customized changes made it into the new initramfs:
lsinitramfs /boot/initramfs.gz | grep cryptsetup
lsinitramfs /boot/initramfs.gz | grep authorized
lsinitramfs /boot/initramfs.gz | grep authorized
With that validated, we ensure all changes are written to disk and shut the RPi down.
sync && sync
init 0
init 0
Backup and Restore
Remove the SD card from your RPi and
return to the system you initially used to write the SD card. Let’s
prepare the environment:
ls -al /mnt/{chroot,backup,encrypted}
# Please make sure there is nothing here first before you move on, otherwise you will have a bad day.
rm -rf /mnt/{chroot,backup,encrypted}
mkdir -p /mnt/{chroot,backup,encrypted}
# Please make sure there is nothing here first before you move on, otherwise you will have a bad day.
rm -rf /mnt/{chroot,backup,encrypted}
mkdir -p /mnt/{chroot,backup,encrypted}
Now insert the SD card and validate the device ID. In our case, the device is /dev/sdc2 but yours might be different so adjust as necessary on your system. We mount the device and make a backup of the filesystem:
mount /dev/sdc2 /mnt/chroot/
rsync -avh /mnt/chroot/* /mnt/backup/
umount /mnt/chroot
rsync -avh /mnt/chroot/* /mnt/backup/
umount /mnt/chroot
Once that is done, we delete the
existing 2nd partition on the SD card and recreate an empty one, which
we set up for LUKS encryption.
echo -e "d\n2\nw" | fdisk /dev/sdc
echo -e "n\np\n2\n\n\nw" | fdisk /dev/sdc
echo -e "n\np\n2\n\n\nw" | fdisk /dev/sdc
With the partitions updated, we reload them by running partprobe and then configure LUKS on the new partition:
cryptsetup -v -y --cipher aes-cbc-essiv:sha256 --key-size 256 luksFormat /dev/sdc2
cryptsetup -v luksOpen /dev/sdc2 crypt
mkfs.ext4 /dev/mapper/crypt
cryptsetup -v luksOpen /dev/sdc2 crypt
mkfs.ext4 /dev/mapper/crypt
With that out of the way, we restore the root filesystem backup to the now encrypted partition.
mount /dev/mapper/crypt /mnt/encrypted/
rsync -avh /mnt/backup/* /mnt/encrypted/
sync
umount /mnt/encrypted/
cryptsetup luksClose /dev/mapper/crypt
rsync -avh /mnt/backup/* /mnt/encrypted/
sync
umount /mnt/encrypted/
cryptsetup luksClose /dev/mapper/crypt
Testing it out
You can now put the SD card back into
the RPi and let it start up. If you watch the boot, you should see
Dropbear start up. At that point, you should be able to SSH into the
system and unlock the drive.
root@kali:~# ssh -o "UserKnownHostsFile /dev/null" root@10.42.42.94
The authenticity of host '10.42.42.94 (10.42.42.94)' can't be established.
ECDSA key fingerprint is SHA256:L+QVP+OmncGDleuEoj77OlRGuCji2gp0c1gMYjUupU0.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '10.42.42.94' (ECDSA) to the list of known hosts.
Please unlock disk /dev/mmcblk0p2 (crypt):
cryptsetup (crypt): set up successfully
Connection to 10.42.42.94 closed.
The authenticity of host '10.42.42.94 (10.42.42.94)' can't be established.
ECDSA key fingerprint is SHA256:L+QVP+OmncGDleuEoj77OlRGuCji2gp0c1gMYjUupU0.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '10.42.42.94' (ECDSA) to the list of known hosts.
Please unlock disk /dev/mmcblk0p2 (crypt):
cryptsetup (crypt): set up successfully
Connection to 10.42.42.94 closed.
The versatility of these little devices
combined with the power of Kali never ceases to amaze us. Now we are
left with a nice headless system we can operate with relative confidence
that, even if it’s discovered, it won’t be too simple to get into.
But we aren’t done yet! Let’s add in some LUKS NUKE functionality:
cryptsetup luksDump /dev/mmcblk0p2
cryptsetup luksAddNuke /dev/mmcblk0p2
cryptsetup luksAddNuke /dev/mmcblk0p2
No comments:
Post a Comment