tl;dr: we bypassed several steps of a challenge, based on a virtual machine, by directly extracting, decrypting and mounting its disk instead of abusing its network services. This technique is not new nor very clever, but it was still a fun bypass that interested many people so here are our explanations.
During the Nuit du Hack XV conference, we participated and won the challenge organized by Wavestone: our booth neighbours. We thank them for this interesting challenge and for the wonderful prize: a 3D-printer that is already sitting in our office!
— Tipi’hack (@tipi_hack) 24 juin 2017
For the last step of the challenge, we download an OVA file which is an exported virtual machine that can be imported, e.g. in VirtualBox. We can boot the VM: the drive is encrypted but the password is given. Once started, we cannot login because we do not have any credential, however a webapp and the SSH service are exported and usable. We observe that this is a Linux system.
We know that the flags are certainly stored in the VM so we decide to directly attack its drive instead of trying to use the webapp as the challenge author envisioned.
We encourage you to read the author’s writeup to discover the proper way to solve this whole challenge:
- Nuit du Hack 2017 – CTF Challenge Writeup – Part 1
- Nuit du Hack 2017 – CTF Challenge Writeup – Part 2
The disk is encrypted but we know the password, so we can try to extract it and mount it, or we can simply try to obtain a root shell through a well-known trick.
First, we can simply extract the OVA with the following command to obtain an .ovf (VM settings) and a .vmdk files (hard-drive image):
tar -xvf connected_missile.ova
We convert the VMDK to the raw format (same format as for disk images obtained with the dd command) with the VBoxManage command (from VirtualBox):
VBoxManage clonehd --format RAW connected_missile-disk1.vmdk disk.raw
Then we use fdisk to see how the drive is partitioned:
# fdisk -l disk.raw Disk disk.raw: 4 GiB, 4294967296 bytes, 8388608 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x3b69d3a9 Device Boot Start End Sectors Size Id Type disk.raw1 * 2048 499711 497664 243M 83 Linux disk.raw2 501758 8386559 7884802 3.8G 5 Extended disk.raw5 501760 8386559 7884800 3.8G 83 Linux
Solution #1: By changing the boot options
There is a well-known technique to elevate our privileges on Linux by changing the boot options to add a parameter to the kernel to replace the init program by a shell (e.g. /bin/bash).
The first partition is small so we suppose it is the /boot partition. It starts at offset 2048 and we see that the sector size is of 512 bytes, so its start is at 2048*512 bytes. We mount it with this command:
mount -o loop,offset=$((2048*512)) disk.raw /media
The /boot partition is not encrypted so we can directly browse it and confirm that we have indeed the /boot partition. We analyze the grub configuration in /grub/grub.cfg and change it to add « init=/bin/bash » at the end of the kernel line (« linux /vmlinuz-3.16.0-4-586… »).
We unmount the partition and convert back the raw image to a VMDK file:
umount ~/disk.raw VBoxManage convertfromraw --format vmdk disk.raw disk.vmdk
Now, in VirtualBox, we just have to change the VMDK in the VM settings under the Storage menu: remove the « connected_missile-disk1.vmdk » disk, add a new disk from existing file and select the new « disk.vmdk » file.
We start the VM, type the encryption password and directly obtain a root shell:
Actually, during the challenge, we took another path: we tried to add the init parameter in the Grub prompt (by typing ‘e’ when selecting the OS to boot), however Grub was protected by a password. So we decided to replace its hash in the grub.cfg by one we generated for a known password. It worked, however the technique explained previously is more straightforward.
Solution #2: By mounting the disk
We suppose that the root partition is the last one. Its start offset is 501760 and we take into account that the sector size is of 512 bytes. We mount it as a loop device:
losetup /dev/loop0 disk.raw -o $((501760 * 512))
In Gnome we get an automatic prompt asking for the password. Otherwise we manually run cryptsetup to decrypt it with the password we already have:
cryptsetup open /dev/loop0 challdisk
Under /dev/mapper, we now have the whole disk and two LVM volumes virtual–rpi–vg-root and the associated swap. Now we can mount the root LVM volume:
# mount /dev/mapper/virtual--rpi--vg-root /media
The disk is small enough that we can launch a dumb exhaustive search for the flags:
# grep -Fr "NDH{" /media 2>/dev/null /media/var/www/backups/flag:NDH{DamnWildcards*} /media/etc/motd: NDH{IsThatANewPublicKey?} __/ / /media/flag:NDH{HowDoesItFeelToBeRoot?}
— Clément Notin