PicoCTF 2022 - Operation Orchid
The challenge description goes as follows:
Download this disk image and find the flag.
We're then given an option to download the mentioned compressed disk image (disk.flag.img.gz). Decompress the archive with gunzip disk.flag.img.gz
.
Let's check what kind of disk image this is:
$ file disk.flag.img
disk.flag.img: DOS/MBR boot sector; partition 1 : ID=0x83, active, start-CHS (0x0,32,33), end-CHS (0xc,223,19), startsector 2048, 204800 sectors; partition 2 : ID=0x82, start-CHS (0xc,223,20), end-CHS (0x19,159,6), startsector 206848, 204800 sectors; partition 3 : ID=0x83, start-CHS (0x19,159,7), end-CHS (0x32,253,11), startsector 411648, 407552 sectors
Okay at the very least the system recognizes disk.flag.img
as a valid image. Let's try to mount the image to see if we can access the files.
$ mkdir ./mnt
$ sudo mount disk.flag.img ./mnt/
mount: /home/cameron/notes/ctf/picoCTF_2022/Forensics/OperationOrchid/mnt: wrong fs type, bad option, bad superblock on /dev/loop0, missing codepage or helper program, or other error.
Well that didn't work. It's important to know that, while the mount
command can often automatically detect the filesystem of a device or disk image, it doesn't automatically detect the offset.
We can get some more information about the image, by viewing the partition table with the mmls
command.
$ mmls disk.flag.img
DOS Partition Table
Offset Sector: 0
Units are in 512-byte sectors
Slot Start End Length Description
000: Meta 0000000000 0000000000 0000000001 Primary Table (#0)
001: ------- 0000000000 0000002047 0000002048 Unallocated
002: 000:000 0000002048 0000206847 0000204800 Linux (0x83)
003: 000:001 0000206848 0000411647 0000204800 Linux Swap / Solaris x86 (0x82)
004: 000:002 0000411648 0000819199 0000407552 Linux (0x83)
Here we have all the information we need to calculate the offset in bytes.
The mmls
output lists each section by a count of sectors. So in this case, we can see the first Linux partition starts at sector 2048
. To calculate the offset we just need to multiply the number of sectors by the bytes per sector listed above as
Units are in 512-byte sectors
So, our offset = 512 x 2048 = 1048576 bytes. Let's try to mount the image again with the appropriate offset.
$ sudo mount -o offset=1048576 disk.flag.img ./mnt/
Nice, we didn't get any errors this time. Let's check the ./mnt/
directory
$ tree ./mnt/
./mnt/
├── boot -> .
├── config-virt
├── extlinux.conf
├── initramfs-virt
├── ldlinux.c32
├── ldlinux.sys
├── libcom32.c32
├── libutil.c32
├── lost+found [error opening dir]
├── mboot.c32
├── menu.c32
├── System.map-virt
├── vesamenu.c32
└── vmlinuz-virt
2 directories, 12 files
Okay, doesn't look like there is much here. This just seems to be the boot partition.
We can check out the extlinux.conf
$ cat extlinux.conf
# Generated by update-extlinux 6.04_pre1-r9
DEFAULT menu.c32
PROMPT 0
MENU TITLE Alpine/Linux Boot Menu
MENU HIDDEN
MENU AUTOBOOT Alpine will be booted automatically in # seconds.
TIMEOUT 30
LABEL virt
MENU LABEL Linux virt
LINUX vmlinuz-virt
INITRD initramfs-virt
APPEND root=UUID=7b688671-b1b5-4e64-830d-36ebc2d4259e modules=sd-mod,usb-storage,ext4 quiet rootfstype=ext4
MENU SEPARATOR
It looks like this is an Alpine Linux image which is neat but isn't particularly helpful here. Let's look at the next partition we saw in the partition table.
The 2nd partition started at sector 206848, but it says it's a swap partition which is essentially a file that acts as extra memory to keep your system from crashing if it is using too much RAM. We'll skip this partition for now and look at the last partition which should contain the files for the system this image was pulled from.
The last partition starts at sector 411648, so 512 x 411648 = 210763776 bytes is our new offset. Let's unmount the first partition and remount with the new offset.
$ sudo umount ./mnt
$ sudo mount -o offset=210763776 disk.flag.img ./mnt/
$ tree -L 1 ./mnt/
./mnt/
├── bin
├── boot
├── dev
├── etc
├── home
├── lib
├── lost+found
├── media
├── mnt
├── opt
├── proc
├── root
├── run
├── sbin
├── srv
├── swap
├── sys
├── tmp
├── usr
└── var
Nice, that looks like a standard Linux system to me. Let's see if we can find that flag.
A good first step is to search for any files with "flag" in the name since this is a CTF after all. We can do that with the find
command.
$ sudo find ./mnt/ -iname "*flag*"
./mnt/root/flag.txt.enc
Well that looks promising. Let's check what kind of file that is.
$ sudo file ./mnt/root/flag.txt.enc
./mnt/root/flag.txt.enc: openssl enc'd data with salted password
Let's also check if flag.txt.enc
shows up in any logs, scripts or other files on the image.
$ sudo grep -r flag.txt.enc ./mnt
./mnt/root/.ash_history:openssl aes256 -salt -in flag.txt -out flag.txt.enc -k unbreakablepassword1234567
It looks like the openssl
command was used to encrypt the flag.txt
with a password of unbreakablepassword1234567
. The command we saw in /mnt/root/.ash_history
uses the openssl-enc
function of openssl
to encrypt the data. If we look through the man page, we'll notice that openssl-enc
has an option for decryption.
-e Encrypt the input data: this is the default.
-d Decrypt the input data.
Let's try decrypting flag.txt.enc
with the password we found.
$ openssl aes256 -d -salt -in flag.txt.enc -out flag.txt -k unbreakablepassword1234567
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
bad decrypt
140027284948288:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:../crypto/evp/evp_enc.c:610:
We got some warnings, but it looks like the command still output a decrypted file flag.txt
. Let's see what it says.
$ cat flag.txt
picoCTF{h4un71ng_p457_5113beab}
And there's our flag.
Don't forget to unmount the image once you're done!
$ sudo umount ./mnt/