Consider this scenario: You’ve breached the physical perimeter of the target organization. Once inside, you need to establish some means of remote network access, whether for yourself or your teammates waiting on the outside. In this example, this takes the form of a device you plug in to an unattended network jack within the target organization.
Whether you call this device a leave-behind, cutout, or “throwaway hackbox,” the principle is the same and it needs to fulfill several requirements. It should be affordable in case it gets lost or damaged. It should be concealable so you can get it in. Setup should be quick and require a minimal level of interaction so that you don’t draw any unnecessary attention to yourself. Lastly, it should be secure, meaning the device should be encrypted in case it is used to store data prior to being extracted, holds any proprietary tools, and to prevent collection of any digital forensics. This post provides a tutorial that will help you configure a device to meet those requirements.
The end product will be a microcomputer (this guide uses the ubiquitous Raspberry Pi) with LUKS disk encryption, unlocked by a keyfile on an external USB drive. Once it’s booted, you pull the drive and go. No SSH, no terminal, no typing. If the device is discovered and powered off, those who discover it should have no means of decrypting it beyond brute force. It’s up to you to conceal and install it in a manner that makes it difficult to interrogate without powering off.
The tutorial covers installing the OS, encrypting the drive, and configuring it to unlock with the use of a key file. This post does not cover physically concealing the device (as that would be very mission-specific) or configuring the device to call back. The Offensive Security post “Kali Linux on a Raspberry Pi (A/B+/2) with Disk Encryption” served as a main reference. Though the beginning of the process is the same, this guide aims toward a different outcome.
Those interested in following along need the items below:
- A Raspberry Pi or similar microcomputer
- An SD or Micro SD card (depending on the Pi model). 16GB is probably a safe minimum size.
- A Linux host or Linux virtual machine (If using a virtual machine you’ll need an SD to USB adapter)
- A Raspberry Pi image of choice (I used the Kali 2.0 image)
- A thumbdrive to hold the keyfile
- A monitor for testing the Pi if you don’t use SSH
Barring any mistakes, this setup takes about an hour start to finish.
We’ll start by generating a keyfile on the thumbdrive so that it’s ready to go when we need it later on. Using a keyfile provides several advantages:
- No password to remember.
- The ability to generate an incredibly strong passphrase.
- No need to type anything in interactively, either via a keyboard or remote console (SSH).
- The ability to share the keyfile among multiple teammates (on multiple thumb drives).
1. Prepare the thumb drive and keyfile
Plug in your thumb drive. The LUKS cryptsetup binaries we’re using support all the most common partition types. I prefer to keep it as FAT since that’s what most thumb drives will be off the shelf.
First we assign the drive a label. Using a label will allow LUKS to identify the appropriate drive from which to load the keyfile. We could use a UUID as well, but then we would require multiple entries in /etc/crypttab (see below). By using a label, we could easily make multiple functioning keys for multiple team members without having to make new entries in /etc/crypttab.
mlabel -i /dev/sdb ::KEYDRIVE
Where sdb is your thumb drive and KEYDRIVE is the label of choice. You can confirm that the drive has been labeled by doing the following:
ls /dev/disk/by-label
With the file system created and labeled, mount the drive and create the keyfile:
mkdir -p /mnt/KEYDRIVE mount /dev/sdb1 /mnt/keydrive
Create a file full of random data for use as the keyfile. This example feeds 4096 random bits into the “keyfile” file.
dd if=/dev/urandom of=/mnt/keydrive/keyfile bs=1024 count=4
Now set your keyfile/thumb drive aside for later and grab the SD or Micro SD card you’ll be using for the Pi filesystem.
2. Write the image to the SD card
Write the Raspberry Pi image of choice to the SD card.
dd if=/path/to/image of=/path/to/sdcard bs=4M
This could take around 15 minutes depending on the size of the image you selected. To monitor the progress of dd in action, open up another terminal, identify the dd process id with “pgrep dd”, and issue the following command:
watch -n 30 kill -USR1 <dd pid>
This will issue the -USR1 signal to dd every 30 seconds, causing it to report how much data has been copied as well as the rate of transfer. Alternatively, you could use the pipe viewer tool from the beginning like so:
dd if=/path/to/image | pv | of=/path/to/sdcard bs=4M
Once the image has been copied, the SD card will have two partitions – a boot partition (mmcblk0p1) and one for the root file system (mmcblk0p2). If you receive an error message along the lines of “mount: special device /dev/XYZ does not exist” when you try to mount the partitions, just remove and reinsert the SD card to ensure your system is reading the new partition table.
3. Chroot into the SD card filesystem
Once the image has been written to the SD card, we can chroot into it and make the necessary changes and updates.
mkdir -p /mnt/chroot/boot mount /dev/sdb2 /mnt/chroot/ mount /dev/sdb1 /mnt/chroot/boot/ mount -t proc none /mnt/chroot/proc mount -t sysfs none /mnt/chroot/sys mount -o bind /dev /mnt/chroot/dev mount -o bind /dev/pts /mnt/chroot/dev/pts
If you don’t have it already, download the QEMU machine emulator for ARM so you can chroot into the mounted SD card.
apt-get install qemu-user-static
Once installed, place the appropriate binary in the mounted chroot environment, and chroot:
cp /usr/bin/qemu-arm-static /mnt/chroot/usr/bin LANG=C chroot /mnt/chroot
4. Setup the SD card filesystem
You’ll want to change the root password and update the package information, then install the necessary cryptsetup package:
passwd apt-get update apt-get install cryptsetup
Also do “update-rc.d ssh enable” if you want to enable ssh on boot. Edit the /boot/cmdline.txt file so that the root filesystem points to the device mapper, and the OS knows that it will be handled by cryptsetup.
Original:
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 elevator=deadline root=/dev/mmcblk0p2 rootfstype=ext4 rootwait
Modified:
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 elevator=deadline root=/dev/mapper/crypt_sdcard cryptdevice=/dev/mmcblk0p2:crypt_sdcard rootfstype=ext4 rootwait
Create the /boot/config.txt file and enter the following line:
initramfs initramfs.gz 0x00f00000
The Raspberry Pi looks at the /boot/config.txt while booting, and the above line simply instructs it to load the ramfs file with the name initramfs.gz at the above memory address.
5. Setup the fstab and crypttab
The fstab (file system table) contains information about the relevant partitions and their mount points. Here we’re telling it that the first partition on the SD card is for boot, and the second partition (which will be encrypted) is for the root file system. Edit /etc/fstab to look like this:
#<file system><mount point><type><options><dump><pass> proc /proc proc defaults 0 0 /dev/mmcblk0p1/boot vfat defaults 0 2 /dev/mapper/crypt_sdcard / ext4 defaults,noatime 0 1
The crypttab configuration file specifies the encrypted device that will be opened during the boot process, the fact that it will be opened with a key file, and that key file’s relative location. Edit /etc/crypttab to look like this, making sure that the label (here KEYDRIVE) and filename (here keyfile) match with what you created earlier. To be clear, the source device should point to the encrypted partition.
# <target name><source device><key file><options> crypt_sdcard /dev/mmcblk0p2 /dev/disk/by-label/KEYDRIVE:/keyfile luks,keyscript=/lib/cryptsetup/scripts/passdev
Now we need to make sure that the cryptsetup binary is included in the initramfs. Create the file /usr/share/initramfs-tools/conf-hooks.d/forcecryptsetup and add the following line of text:
export CRYPTSETUP=y
Finally, we’ll create the initial RAM file system with the filename initramfs.gz, placing it in the boot directory (which corresponds to the last command in step 4). This command takes the current kernel version as an argument, so to determine that when you’re chrooted in, grab the version from the “modules” folder in /lib/modules.
mkinitramfs -o /boot/initramfs.gz $(ls -l /lib/modules | cut -d" " -f10)
You may get a few errors regarding the crypt_sdcard device or address and failure to load the appropriate cipher modules. Don’t panic, these are normal at this point.
6. Exit from the chroot and and backup the file system
exit umount /mnt/chroot/boot umount /mnt/chroot/sys umount /mnt/chroot/proc
Next we’ll backup the file system as it is so we can replace it after creating an encrypted partition. Note that copying the file system can take over 15 minutes.
mkdir -p /mnt/backup rsync -avh /mnt/chroot/* /mnt/backup
umount /mnt/chroot/dev/pts umount /mnt/chroot/dev umount /mnt/chroot
7. Encrypt the partition
First, delete the existing second partition. Launch the interactive fdisk prompt for the device by typing
fdisk /dev/XYZ
Then type “d” for delete, “2” for the second partition, and “w” to write the changes. Re-enter the interactive prompt (fdisk /dev/XYZ) and this time write a new partition, typing “n” for new, “p” for primary, “2” for the second partition, enter twice to accept the defaults, and “w” to write the changes.
As earlier, unplug and replug the disk to ensure your system is reading the new partition table. Now we need to encrypt the partition. This command prompts you for a LUKS passphrase, so we specify the key file we created in step 1 with the -d flag. You could add a passphrase, but since cryptsetup allows for passing the keyfile, I don’t find it to be necessary. Note this command assumes that your thumbdrive with the key file is mounted.
cryptsetup -v -d /mnt/keydrive/keyfile --cipher aes-cbc-essiv:sha256 --key-size 256 luksFormat /dev/XYZ
Now open the freshly encrypted partition.
cryptsetup -v -d /mnt/keydrive/keyfile luksOpen /dev/sdb2 crypt_sdcard
You should see “Key slot 0 unlocked”, confirming that your key file on the USB drive successfully unlocked the encrypted partition. Next, format that file system, mount it, and copy the root filesystem back onto the card, and close the container.
mkfs.ext4 /dev/mapper/crypt_sdcard mkdir -p /mnt/encrypted mount /dev/mapper/crypt_sdcard /mnt/encrypted/ rsync -avh /mnt/backup/* /mnt/encrypted/ umount /mnt/encrypted/ sync cryptsetup luksClose /dev/mapper/crypt_sdcard
If you’re feeling confident, you can remove the /mnt/backup directory to save up some space. I recommend testing the Pi with a direct connection to a monitor so you can observe the boot process and any issues or errors that may arise. If it works, I recommend saving an image of the card. Definitely do that before making any updates or significant changes, and always test the equipment before going operational.
I hit a snag when I added a second more OPSEC-savvy key file (see below), but the device failed to boot off of it when it was stored in keyslot 1. I could still pass the key file to cryptsetup using the -d flag, but it would only boot from it when moved to keyslot 0. I’m not sure if this is the intended functionality of cryptsetup and the passdev script, but it’s something to look out for if you’re trying to add additional key files.
Do you even OPSEC, bro?
In our example we used a FAT formatted thumbdrive, but the drive was conspicuously labeled, and the key file had a rather telling filename. One of the beauties of LUKS allowing for a keyfile is that the file can be of any type, which is to say you could use an image file, .pdf, .mp3, etc. You could also use a .docx or similar file, but since those are easier to edit, you may increase the risk of breaking your key file.
By taking advantage of this method, you can create a thumb drive that is less suspicious in the event it gets lost or you get “rolled up.” In addition, you could use a picture or other file hosted somewhere on the internet, meaning the key file could also be retrieved, but wouldn’t necessarily be obvious.
However, in the image we created, the boot partition is unencrypted. This means that if the device is retrieved, someone could inspect that partition and find the initramfs.gz file. Inside the initramfs archive is a “conf” directory. The “conf” directory has the “conf.d” directory, in which there is a file called “cryptroot.”
The cryptroot file reflects /etc/crypttab, showing the encrypted device and how it is unlocked. That means it reveals the label of the USB drive and file name of the key file:
target=crypt_sdcard,source=/dev/mmcblk0p2,key=/dev/disk/by-label/KEYDRIVE:/keyfile,rootdev,keyscript=/lib/cryptsetup/scripts/passdev
I don’t believe this information leakage renders this approach useless, but it is important to know. If your thumb drive is lost or confiscated on site, activate the device’s self-destruct mechanism and activate whatever contingencies you have in place.
