TOTP brute-force search incomplete?
#1
I'm using Windows 10 Pro (1909, build 18363.900), and hashcat 5.1.0.
I tried following the "tutorial" for doing TOTP (HMAC-SHA1) that's at https://www.unix-ninja.com/p/attacking_g...henticator, but couldn't reproduce the results - I didn't get any duplicate secret to isolate the correct match. I decided to try a shorter (5 character), simplified example that I could cross-check easily. Using Python and the pyotp module:

Code:
>>> import pytop >>> import base64 >>> base64.b32encode(b'ahash') b'MFUGC43I' >>> totp = pyotp.TOTP(b'MFUGC43I') >>> totp.at(1000000000) '671202' >>> totp.at(1000001000) '455543'

So let's make a totp.hash file that contains:

Code:
671202:1000000000 455543:1000001000

Run the command (note the mask, and I don't think mode 18100 requires the --keep-guessing, but I included it anyway):

Code:
>hashcat64.exe --potfile-path=totp.potfile -a 3 -m 18100 --keep-guessing totp.hash ?l?l?l?l?l 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. OpenCL Platform #1: NVIDIA Corporation ====================================== * Device #1: Quadro P2200, 1280/5120 MB allocatable, 10MCU OpenCL Platform #2: Intel(R) Corporation ======================================== * Device #2: Intel(R) UHD Graphics 630, skipped. * Device #3: Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz, skipped. Hashes: 2 digests; 2 unique digests, 2 unique salts Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates Applicable optimizers: * Zero-Byte * Not-Iterated * Brute-Force Minimum password length supported by kernel: 0 Maximum password length supported by kernel: 256 Watchdog: Temperature abort trigger set to 90c 671202:1000000000:O5RWS6DB 455543:1000001000:PBYWM2LO 671202:1000000000:OBWW4ZDH 455543:1000001000:NZTG46LE Approaching final keyspace - workload adjusted. 671202:1000000000:NJ5GM5LK 455543:1000001000:O5SHA4DY Session..........: hashcat Status...........: Exhausted Hash.Type........: TOTP (HMAC-SHA1) Hash.Target......: .\totp.hash Time.Started.....: Fri Jun 19 10:28:21 2020 (0 secs) Time.Estimated...: Fri Jun 19 10:28:21 2020 (0 secs) Guess.Mask.......: ?l?l?l?l?l [5] Guess.Queue......: 1/1 (100.00%) Speed.#1.........:  308.8 MH/s (7.66ms) @ Accel:64 Loops:26 Thr:256 Vec:1 Recovered........: 0/2 (0.00%) Digests, 0/2 (0.00%) Salts Progress.........: 23762752/23762752 (100.00%) Rejected.........: 0/23762752 (0.00%) Restore.Point....: 456976/456976 (100.00%) Restore.Sub.#1...: Salt:1 Amplifier:0-26 Iteration:0-26 Candidates.#1....: sefjy -> xqxvq Hardware.Mon.#1..: Temp: 38c Fan: 47% Util: 85% Core:1455MHz Mem:5005MHz Bus:16

This console output matches the totp.potfile - 6 matches (three for each timestamp). Also, the Progress number appears correct: 26^5 (for length 5 lowercase) * 2 hashes to test = 23762752, leading me to believe this is correctly done. Unfortunately, this is very incomplete!!

Using a some more Python:

Code:
>>> import itertools >>> import string >>> def exhaustive_search(charset, length, code, timestamp):         matches = list() # keep a list of matches         num_searched = 0 # count how many we've checked         for candidate in itertools.product(charset, repeat=length):                 cadidate_bytes = ''.join(candidate).encode()                 cadidate_b32 = base64.b32encode(cadidate_bytes)                 if pyotp.TOTP(cadidate_b32).at(timestamp) == code:                         matches.append((cadidate_bytes, cadidate_b32))                 num_searched += 1         return (num_searched, matches) >>> exhaustive_search(string.ascii_lowercase, 5, '671202', 1000000000) # took ~ 3 minutes (11881376, [(b'abmrc', b'MFRG24TD'), (b'ahash', b'MFUGC43I'), (b'cygfx', b'MN4WOZTY'), (b'hcvyo', b'NBRXM6LP'), (b'jwjwq', b'NJ3WU53R'), (b'jzfuj', b'NJ5GM5LK'), (b'mdvbx', b'NVSHMYTY'), (b'nkqzv', b'NZVXC6TW'), (b'pmndg', b'OBWW4ZDH'), (b'qbbim', b'OFRGE2LN'), (b'tcmia', b'ORRW22LB'), (b'wcixa', b'O5RWS6DB')]) >>> exhaustive_search(string.ascii_lowercase, 5, '455543', 1000001000) # also took ~ 3 minutes (11881376, [(b'ahash', b'MFUGC43I'), (b'awiai', b'MF3WSYLJ'), (b'bdlly', b'MJSGY3DZ'), (b'bunvx', b'MJ2W45TY'), (b'cfraz', b'MNTHEYL2'), (b'ctwlb', b'MN2HO3DC'), (b'dqakb', b'MRYWC23C'), (b'dxtah', b'MR4HIYLI'), (b'fvvoe', b'MZ3HM33F'), (b'gcckn', b'M5RWG23O'), (b'gtpjs', b'M52HA2TT'), (b'jnpfj', b'NJXHAZTK'), (b'kzmhd', b'NN5G22DE'), (b'nfnyd', b'NZTG46LE'), (b'nrkfd', b'NZZGWZTE'), (b'odant', b'N5SGC3TU'), (b'vlivu', b'OZWGS5TV'), (b'wdppx', b'O5SHA4DY'), (b'wmdlu', b'O5WWI3DV'), (b'xqfin', b'PBYWM2LO'), (b'xuazs', b'PB2WC6TT')])

So my Python code found 12 and 21 matches (over the same 23762752 tests), not just 3 and 3. Also, the expected duplicate for 'ahash' can be identified. ASIDE: Yes, I know my Python is sub-optimal, I just wanted to bang out a quick-ish cross-check.
So what gives? Did I miss something in my command-line? Can someone reproduce my issue? The totp.hash file and command-line are right above and takes '0 seconds' (there's more overhead than actual runtime for this) to run.
Reply
#2
I think it has to do that a single kernel call can't crack a hash multiple times. There are just way too many collisions for a fast cracker like hashcat.

I think a similar problem/limitation/restriction is explained in docs/limits.txt
Reply
#3
I was able to add -T 1 (and, as required by -T, --force) to set the kernel thread count to 1. This technically slows things down, but still runs in 1 second.
Code:
hashcat64.exe --potfile-path=totp.potfile -a 3 -m 18100 --keep-guessing -T 1 --force totp.hash ?l?l?l?l?l hashcat (v5.1.0) starting... OpenCL Platform #1: NVIDIA Corporation ====================================== * Device #1: Quadro P2200, 1280/5120 MB allocatable, 10MCU OpenCL Platform #2: Intel(R) Corporation ======================================== * Device #2: Intel(R) UHD Graphics 630, 4095/13039 MB allocatable, 24MCU * Device #3: Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz, skipped. Hashes: 2 digests; 2 unique digests, 2 unique salts Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates Applicable optimizers: * Zero-Byte * Not-Iterated * Brute-Force Minimum password length supported by kernel: 0 Maximum password length supported by kernel: 256 Watchdog: Temperature abort trigger set to 90c 671202:1000000000:O5RWS6DB 455543:1000001000:PBYWM2LO 671202:1000000000:ORRW22LB 671202:1000000000:MFUGC43I 455543:1000001000:MFUGC43I 455543:1000001000:MJSGY3DZ 671202:1000000000:NBRXM6LP 455543:1000001000:OZWGS5TV 455543:1000001000:O5WWI3DV 455543:1000001000:N5SGC3TU 455543:1000001000:M5RWG23O 455543:1000001000:MR4HIYLI 455543:1000001000:NZTG46LE 671202:1000000000:OBWW4ZDH 455543:1000001000:MF3WSYLJ 455543:1000001000:NJXHAZTK 455543:1000001000:M52HA2TT 671202:1000000000:MFRG24TD 455543:1000001000:PB2WC6TT 455543:1000001000:MZ3HM33F 455543:1000001000:MRYWC23C 455543:1000001000:MNTHEYL2 455543:1000001000:NN5G22DE 671202:1000000000:NJ5GM5LK 671202:1000000000:NJ3WU53R 455543:1000001000:O5SHA4DY 671202:1000000000:NVSHMYTY 671202:1000000000:MN4WOZTY 455543:1000001000:MJ2W45TY Approaching final keyspace - workload adjusted. 671202:1000000000:NZVXC6TW Session..........: hashcat Status...........: Exhausted Hash.Type........: TOTP (HMAC-SHA1) Hash.Target......: .\totp.hash Time.Started.....: Fri Jun 19 15:25:36 2020 (1 sec) Time.Estimated...: Fri Jun 19 15:25:37 2020 (0 secs) Guess.Mask.......: ?l?l?l?l?l [5] Guess.Queue......: 1/1 (100.00%) Speed.#1.........: 15497.5 kH/s (7.05ms) @ Accel:512 Loops:26 Thr:1 Vec:1 Speed.#2.........:  2728.6 kH/s (6.93ms) @ Accel:32 Loops:26 Thr:1 Vec:1 Speed.#*.........: 18226.2 kH/s Recovered........: 0/2 (0.00%) Digests, 0/2 (0.00%) Salts Progress.........: 23762752/23762752 (100.00%) Rejected.........: 0/23762752 (0.00%) Restore.Point....: 453938/456976 (99.34%) Restore.Sub.#1...: Salt:1 Amplifier:0-26 Iteration:0-26 Restore.Sub.#2...: Salt:1 Amplifier:0-26 Iteration:0-26 Candidates.#1....: suxjq -> xqxvq Candidates.#2....: sdmfq -> xipfq Hardware.Mon.#1..: Temp: 44c Fan: 51% Util: 94% Core:1746MHz Mem:5005MHz Bus:16 Hardware.Mon.#2..: N/A

Strangely, it still skipped 3 (it gave me 30, I expected 33): OFRGE2LN, NZZGWZTE, & MN2HO3DC. Any ideas if other switches might help? I understand it will be slower, but obviously much faster than my Python example.
Reply
#4
Code:
-n 1
?
Reply
#5
I swapped in '-n 1' for '-T 1' and it ran basically the same and got the same incomplete (only 30 of 33) list.
I tried both together i.e. '-n 1 -T 1' and it was quite slow, relatively speaking (somewhere between 100 and 1000 times slower), so it took 20 seconds, but it caught all 33.

I retried the example from the tutorial to get a better feel for the timing difference
Code:
Switches  |  Hits | Time ----------+-------+----- <neither> |  3274 |  33s -n 1      | 11966 |  65s -T 1      | 14945 | 747s -T 1 -n 1 | 16058 | 2h34m
The 14945 and 11966 were complete enough to find the duplicate, but the 3274 wasn't. The (probably) exhaustive one is just too slow to be useful.
So -n 1 is the best choice for this setup, but different workloads may behave differently.
Reply