terça-feira, 10 de março de 2020

Bruteforcing Linux Disk Encryption (LUKS)

Hi guys! I decided to write this article for a few reasons.
Several Bruteforcing Linux Disk Encryption articles are unclear, not accurate, and missing steps.

To start this post, I will describe a scenario that happened a few months ago.
An unsatisfied IT contractor encrypted all virtualized servers from a company and asked for the ransom.

So let's start with the technical part.

First of all, you need to recognize the hypervisor used by the virtualized machine since the disk is not in RAW format. Each hypervisor has a different command to perform this action. In this case, let's suppose it was VirtualBox. If you try to crack the password directly running the hashcat against the VDI file even following the hashcat documentation, it won't work.

You need to convert the VDI file in the RAW format first(VBox 6.1):

vbox-img convert --dstfilename "<fullptah_of_ouputfile_disk.raw>" --srcfilename "<fullpath_of_encripted_file.vdi>" --srcformat VDI --dstformat RAW --variant Standard

*Depending on the disk size, it can take a long time to finish, and there is no progress indicator during the process. You must wait until the prompt is released.

Now, let's extract the encrypted partition(LUKS) from the RAW disk.

binwalk -D 'luks_magic:lukspartiton.raw:' disk.raw

*Depending on the disk size, it can take a long time to finish, and there is no progress indicator during the process. You must wait until the prompt is released or check if the file created by binwalk already has more than 2 megabytes. As the extraction is quite fast probably you are going to see a big file, it's not a problem.

The binwalk will create a directory named _disk.raw.extracted, inside this directory, where you can find the extracted file, the name should be something like F500000.lukspartiton.raw

After this process, according to the documentation, hashcat needs about 2 megabytes to identify everything it needs to crack the password. 512 blocks of 4097 bytes, or in other words, at least 2097664 bytes from the beginning of the RAW partition disk are required. (Reference: https://hashcat.net/forum/thread-6225.html)

You can generate this piece of the file using the famous Linux command dd, but you also can use tools like FTK or any other tool able to manipulates disk files and extract the LUKS partition. Just make sure if the generated file has the appropriate headers and size at the end of the process.

dd if=F500000.lukspartiton.raw of=encriptedheader.crack bs=512 count=4097


To check if your piece of file image is ready to be cracked, you can use the Linux command "file" or check with some Hex editor for the strings LUKS.


root@Anubis:/cript# file encriptedheader.crack
encriptedheader.crack: LUKS encrypted file, ver 2 [, , sha256] UUID: XXXXXXXX-3d7f-4760-aec6-XXXXXXXXXXXX

Also, you can check running the "strings" command
. The expected return should be like the following:

root@Anubis:/cript# strings encriptedheader.crack | grep -i luks LUKS

{"keyslots":{"0":{"type":"luks2","key_size":64,"af":{"type":"luks1","stripes":4000,"hash":"sha256"},"area":{"type":"raw","offset":"32768","size":"258048","encryption":"aes-xts-plain64","key_size":64},"kdf":{"type":"argon2i","time":4,"memory":713834,"cpus":2,"salt":"<REDACTED>"}}},"tokens":{},"segments":{"0":{"type":"crypt","offset":"16777216","size":"dynamic","iv_tweak":"0","encryption":"aes-xts-plain64","sector_size":512}},"digests":{"0":{"type":"pbkdf2","keyslots":["0"],"segments":["0"],"hash":"sha256","iterations":65997,"salt":"<REDACTED>","digest":"<REDACTED>"}},"config":{"json_size":"12288","keyslots_size":"16744448"}} {"keyslots":{"0":{"type":"luks2","key_size":64,"af":{"type":"luks1","stripes":4000,"hash":"sha256"},"area":{"type":"raw","offset":"32768","size":"258048","encryption":"aes-xts-plain64","key_size":64},"kdf":{"type":"argon2i","time":4,"memory":713834,"cpus":2,"salt":"<REDACTED>"}}},"tokens":{},"segments":{"0":{"type":"crypt","offset":"16777216","size":"dynamic","iv_tweak":"0","encryption":"aes-xts-plain64","sector_size":512}},"digests":{"0":{"type":"pbkdf2","keyslots":["0"],"segments":["0"],"hash":"sha256","iterations":65997,"salt":"<REDACTED>","digest":"<REDACTED>"}},"config":{"json_size":"12288","keyslots_size":"16744448"}}

At this point, if you have read the documentation, you can recognize if the hashcat supports the disk encryption by checking the parameters 'encryption,' 'type,' and 'hash' from the strings command output.
Double-checking the file size before starting the Bruteforce.

root@Anubis:cript# ls -al

total 4604 
drwxrwx--- 1 root vboxsf 0 Mar 10 2020 . 
drwxr-xr-x 3 root root 4096 Feb 23 22:00 .. 
-rwxrwx--- 1 root vboxsf 2097664 Mar 10 2020 encriptedheader.crack 

Now you are sure and ready to start the cracking. 

I used this syntax for hashcat, but of course, you can change according to your needs.


hashcat -m 14600 -O -a 0 -w 3 encriptedheader.crack example.dict -o crackedpass.txt


If everything is fine, you will see this output. hashcat (v5.1.0) starting...

* Device #1: WARNING! Kernel exec timeout is not disabled.
             This may cause "CL_OUT_OF_RESOURCES" or related errors.
             To disable the timeout, see: https://hashcat.net/q/timeoutpatch
* Device #2: Intel's OpenCL runtime (GPU only) is currently broken.
             We are waiting for updated OpenCL drivers from Intel.
             You can use --force to override, but do not report related errors.
nvmlDeviceGetFanSpeed(): Not Supported

OpenCL Platform #1: NVIDIA Corporation
======================================
* Device #1: GeForce MX130, 512/2048 MB allocatable, 3MCU

OpenCL Platform #2: Intel(R) Corporation
========================================
* Device #2: Intel(R) UHD Graphics 620, skipped.
* Device #3: Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz, skipped.

Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Applicable optimizers:
* Zero-Byte
* Single-Hash
* Single-Salt
* Slow-Hash-SIMD-LOOP

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256

Watchdog: Temperature abort trigger set to 90c

Dictionary cache hit:
* Filename..: example.dict
* Passwords.: 128416
* Bytes.....: 1069601
* Keyspace..: 128416

Cracking performance lower than expected?

* Update your OpenCL runtime / driver the right way:
  https://hashcat.net/faq/wrongdriver

* Create more work items to make use of your parallelization power:
  https://hashcat.net/faq/morework


[s]tatus [p]ause [b]ypass [c]heckpoint [q]uit =>

Session..........: hashcat
Status...........: Running
Hash.Type........: LUKS
Hash.Target......: encriptedheader.crack
Time.Started.....: Tue Mar 10 12:31:13 2020 (23 secs)
Time.Estimated...: Tue Mar 10 12:51:19 2020 (19 mins, 43 secs)
Guess.Base.......: File (example.dict)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:      107 H/s (4.22ms) @ Accel:2 Loops:256 Thr:64 Vec:1
Recovered........: 0/1 (0.00%) Digests, 0/1 (0.00%) Salts
Progress.........: 2304/128416 (1.79%)
Rejected.........: 0/2304 (0.00%)
Restore.Point....: 2304/128416 (1.79%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:45312-45568
Candidates.#1....: 0611soep -> 078112025
Hardware.Mon.#1..: Temp: 70c Util: 98% Core:1032MHz Mem:2505MHz Bus:4

[s]tatus [p]ause [b]ypass [c]heckpoint [q]uit =>


Otherwise, if you receive the error:

Hashfile 'encriptedheader.crack': Invalid LUKS version
No hashes loaded.

It indicates the file was not created properly. Double-check the file size and the headers.
Or, the hashcat is not compatible with the LUKS version that the disk was encrypted with.

Have a nice cracking!


UPDATE:
You can limit binwalk's output using `--size $((2**22))` and make it halt on the first match with `--count 1`. I also recommend using `qemu-img dd` to limit how much of the input image you process.

Tip from: https://twitter.com/PEdrArthur