You are presented with a zip file containing the following files:
encrypted_usb.dd
README.txt
recovery_keys_dump.txt
README
Urgent Incident Response help needed!
We have been contacted by a key client, whose external storage devices have all been encrypted by some new and unknown ransomware variant.
Important files which have not been backed up have been encrypted and the client needs access to the files from 1 specific device urgently.
The drive uses BitLocker encryption; however, it was mounted at the time of the attack.
The client will not disclose their BitLocker password; however, we do have access to the BitLocker recovery keys from the asset management team.
Unfortunately, the asset management team didn’t map the recovery keys to specific devices, so we only have a company-wide dump.
The external storage device image (encrypted_usb.dd) and BitLocker recovery key dump (recovery_keys_dup.txt) are attached.
Can you help?
recovery_keys_dump.txt
516735-656957-925056-932288-472819-186862-770136-696813
209418-618481-221875-863288-199571-558844-456147-816495
289237-659109-210156-431433-506114-195851-203202-783829
...
The number of BitLocker keys makes it challenging to try to find the right one by hand.
cat recovery_keys_dump.txt| wc -l
1000
First we need to mount the dd
file as block device on the system (Kali).
By associating the file with a loop device, we can treat the file as if it were a physical block device such as a hard drive or USB drive.
This allows us to perform various operations on the file, such as reading its contents, writing to it, or manipulating it as if it were a real storage device.
losetup /dev/loop0 encrypted_usb.dd
If you don’t have loop
load the appropriate kernel module.
modprobe loop
Lets brute force all the keys found in recovery_keys_dump.txt
against the encrypted volume.
We will use the tool dislocker
to try to decrypt BitLocker-encrypted volume.
If the decryption process succeeds and the correct key is found, the dislocker command will unlock the encrypted volume under the image/
subfolder the correct key that successfully decrypted the volume will be presented.
mkdir image
while read line; do sudo dislocker -r -V /dev/loop0 -p$line image/ && echo $line; done < recovery_keys_dump.txt
334565-564641-129580-248655-292215-551991-326733-393679
Mount the decrypted dislocker-file
to /media/mount
.
mount -o loop image/dislocker-file /media/mount
Contents of /media/mount
crypto_passphrase.png.xxx.crypt
cryptor
do_not_open.png.xxx.crypt
meeting_minutes.png.xxx.crypt
passwords.png.xxx.crypt
ransom.txt
salary_screenshot.png.xxx.crypt
ransom.txt
Oh no! Your files are encrypted!
Your files have been encrypted using a secure xor encryption algorithm and are completely unrecoverable!
To decrypt your files, you need your secret encryption key.
To retrieve your secret encryption key, you will need to pay 50 BOTCIINS – otherwise your secret encryption key will be
deleted and you will never be able to access your files again!%
The important detail is the mention of XOR, so we know how we can create our own code to decrypt the files.
To do that, we will write some code, but first to have at least remote success, we need to know the charset and lenght of the passphrase used to encrypt the files.
I got the answer from the hint, but also tried this non-scientific method:
./crypto aaAa
exit code 1
./crypto a1aa
exit code 1
./crypto aaaaa
exit code 1
./crypto a!aa
exit code 1
./crypto aaaa
exit code 0
We can see that lenght is 4 char and the charset is lowercase alpha.
As we know the correct “magic bytes” for PNG files, we can try to brute force each combination.
The magic bytes are \x89\x50\x4E\x47\x0D\x0A\x1A\x0A
so we need to XOR only first 8 bytes of each file with the potential passphrase.
When the bytes are the same, we found our answer.
The solution:
import os
import itertools
# Define the PNG magic bytes
png_magic_bytes = b'\x89\x50\x4E\x47\x0D\x0A\x1A\x0A'
# Define the character space for the password
character_space = 'abcdefghijklmnopqrstuvwxyz'
# Generate all possible combinations of the password
# We know that the passwords is 4 lowercase characters
passwords = itertools.product(character_space, repeat=4)
# Path to the encrypted file
encrypted_file = 'do_not_open.png.xxx.crypt'
#encrypted_file = 'crypto_passphrase.png.xxx.crypt'
#encrypted_file = 'meeting_minutes.png.xxx.crypt'
#encrypted_file = 'passwords.png.xxx.crypt'
#encrypted_file = 'salary_screenshot.png.xxx.crypt'
# Path to save the decrypted file
decrypted_file = 'do_not_open.png'
#decrypted_file = 'crypto_passphrase.png'
#decrypted_file = 'meeting_minutes.png'
#decrypted_file = 'passwords.png'
#decrypted_file = 'salary_screenshot.png'
# Function to perform XOR encryption on a file with a given password
def xor_encrypt_file(file_path, password):
with open(file_path, 'rb') as file:
file_bytes = file.read()
password_bytes = password.encode()
encrypted_bytes = bytearray()
for i, byte in enumerate(file_bytes):
encrypted_byte = byte ^ password_bytes[i % len(password_bytes)]
encrypted_bytes.append(encrypted_byte)
return encrypted_bytes
# Read the first 8 bytes from the encrypted file
with open(encrypted_file, 'rb') as f:
encrypted_bytes = f.read(8)
# Iterate through each password combination and check if it decrypts the file successfully
for password in passwords:
password_str_4char = ''.join(password)
# We need 8 bytes long password for test XOR
password_str = password_str_4char+password_str_4char
decrypted_bytes = b''
# XOR each byte with the corresponding byte from the password
for i in range(8):
decrypted_byte = encrypted_bytes[i] ^ ord(password_str[i])
decrypted_bytes += bytes([decrypted_byte])
# Check if the decrypted bytes match the PNG magic bytes
if decrypted_bytes == png_magic_bytes:
print(f"Correct password found: {password_str_4char}")
print(f"Decrypted file saved as: {decrypted_file}")
# Decrypt the encrypted file using the current password
decrypted_bytes = xor_encrypt_file(encrypted_file, password_str_4char)
# Write the decrypted bytes to a file
with open(decrypted_file, 'wb') as file:
file.write(decrypted_bytes)
break