How to perform dictionary attack on LUKS passphrase

Perform dictionary attack on forgotten LUKS passphrase to access encrypted device.

Prerequisites

Store LUKS header backup as the using the whole device can be very cumbersome.

$ file luks_header_backup 
luks_header_backup: LUKS encrypted file, ver 1 [aes, xts-plain64, sha256] UUID: ac32a865-2716-43e3-8db9-798d4279a3a3

For hashcat you will also need the first sector from the payload.

$ sudo dd if=/dev/sdb1 of=extended-luks-header bs=1M count=5
5+0 records in
5+0 records out
5242880 bytes (5.2 MB, 5.0 MiB) copied, 0.0273016 s, 192 MB/s

Create dictionary file with every possible passphrase combination, one per line.

$ cat passphrases-dictionary 
somepasssphrase
potentialpasssphrase
maybethispassphrase
[...]

bruteforce-luks

Install bruterforce-luks package.

$ sudo apt-get install bruteforce-luks

You can always get the source directly from bruteforce-luks GitHub repository.

$ bruteforce-luks

bruteforce-luks 1.3.1

Usage: bruteforce-luks [options] <path to LUKS volume>

Options:
  -b <string>  Beginning of the password.
                 default: ""
  -e <string>  End of the password.
                 default: ""
  -f <file>    Read the passwords from a file instead of generating them.
  -h           Show help and quit.
  -l <length>  Minimum password length (beginning and end included).
                 default: 1
  -m <length>  Maximum password length (beginning and end included).
                 default: 8
  -s <string>  Password character set.
                 default: "0123456789ABCDEFGHIJKLMNOPQRSTU
                           VWXYZabcdefghijklmnopqrstuvwxyz"
  -t <n>       Number of threads to use.
                 default: 1
  -v <n>       Print progress info every n seconds.
  -w <file>    Restore the state of a previous session if the file exists,
               then write the state to the file regularly (~ every minute).

Sending a USR1 signal to a running bruteforce-luks process
makes it print progress info to standard error and continue.

Error: missing path to LUKS volume.

To perform dictionary attack using bruteforce-luks version 1.3.1 you need to define number of threads (see additional notes section), amount of time between printing progress information, session file that can be used to continue attack later, file that contains possible passphrases and LUKS header backup.

$ bruteforce-luks -t 4 -v 60 -w state_file -f passphrases-dictionary luks_header_backup
Warning: using dictionary mode, ignoring options -b, -e, -l, -m and -s.

Warning: restoring state, ignoring options -b, -e, -f, -l, -m and -s.

Tried passwords: 2858
Tried passwords per second: 1.576393
Last tried password: anypassphrase1

[...]

State file contains basic information and current progress.

$ cat state_file
luks luks_header_backup
time 356922
dictionary passphrases-disctionay
662870

hashcat

Install hashcat package.

$ sudo apt-get install hashcat

I will use version 5.1.0.

$ hashcat --version
v5.1.0

To perform dictionary attack using hashcat version 5.1.0 you need to force execution (in case that OpenCL does not have any GPU available), define LUKS hash type, attack mode (straight), file to store found passphrase, file that contains possible passphrases and extended LUKS header backup.

$ hashcat --force --hash-type 14600 --attack-mode 0 --outfile recovered_passphrase ./extended_luks_header  passphrases-dictionary 
hashcat (v5.1.0) starting...

OpenCL Platform #1: The pocl project
====================================
* Device #1: pthread-Intel(R) Core(TM) i7-5600U CPU @ 2.60GHz, 256/740 MB allocatable, 1MCU

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

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

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

Watchdog: Hardware monitoring interface not found on your system.
Watchdog: Temperature abort trigger disabled.

* Device #1: build_opts '-cl-std=CL1.2 -I OpenCL -I /usr/share/hashcat/OpenCL -D LOCAL_MEM_TYPE=2 -D VENDOR_ID=64 -D CUDA_ARCH=0 -D AMD_ROCM=0 -D VECT_SIZE=8 -D DEVICE_TYPE=2 -D DGST_R0=0 -D DGST_R1=1 -D DGST_R2=2 -D DGST_R3=3 -D DGST_ELEM=16 -D KERN_TYPE=14621 -D _unroll'
Dictionary cache hit:
* Filename..: passphrases-dictionary
* Passwords.: 2556
* Bytes.....: 43464
* Keyspace..: 2556
* Runtime...: 0 secs

- Device #1: autotuned kernel-accel to 256                                                           
- Device #1: autotuned kernel-loops to 256                                                           
[s]tatus [p]ause [r]esume [b]ypass [c]heckpoint [q]uit => s

Session..........: hashcat
Status...........: Running
Hash.Type........: LUKS
Hash.Target......: /root/new-header.luks
Time.Started.....: Sun Jan  6 02:39:52 2019 (8 mins, 42 secs)
Time.Estimated...: Sun Jan  6 02:50:22 2019 (1 min, 48 secs)
Guess.Base.......: File (/root/notebook/l5)
Guess.Queue......: 1/1 (100.00%)
Speed.Dev.#1.....:        5 H/s (19.29ms)
Recovered........: 0/1 (0.00%) Digests, 0/1 (0.00%) Salts
Progress.........: 2048/2556 (80.13%)
Rejected.........: 0/2048 (0.00%)
Restore.Point....: 2048/2556 (80.13%)
Candidates.#1....: [email protected]@2018! -> debian-linux-2018!
HWMon.Dev.#1.....: N/A

[...]

Use -s option to skip number of words.

$ hashcat --force --hash-type 14600 -s 1002 --attack-mode 0  --outfile recovered_passphrase ./extended_luks_header  passphrases-dictionary 

Additional notes

Display number of CPUs to define used threads.

$ LC_ALL=C lscpu | awk -F: '/^CPU\(s\):/ { gsub(" ","",$2); print $2}'
4

If you cannot force hashcat to start and do not have additional GPU (error clGetDeviceIDs(): CL_DEVICE_NOT_FOUND), then install a "native" target which allows running OpenCL kernels on the host CPU.

$ sudo apt-get install pocl-opencl-icd