WINHELLO2hashcat
#1
Prologue
Since a couple of years now, Microsoft introduced WINDOWS HELLO in the operating system Windows 10 in order to let the user sign-in on a more personal way: using the face, fingerprint or a PIN.
When the user adds a local Win10 account and chooses to activate the Windows Hello PIN, there still is the possibility to sign-in with the user password.
But, when adding an online Win10 account, the user is asked - by default - to setup a PIN. This became the only way to sign-in to this account.
 
In September '21, Microsoft made some publicity about pushing their users to use a PIN.
https://docs.microsoft.com/en-us/windows...n-password
 
However, is there a possibility to crack this PIN?
 
After doing some self-study, reading blogs, reading code on Github, and trying to understand what happens...we finally got it. Sort of. Wink
Thanks to the exceptional reverse-engineering work of @tijldeneut, we understood that there is in fact a way to crack the PIN.
We also saw that he implemented a "--pinbrute" possibility, which we - for this Proof of Concept - extracted, cleaned and optimised.
 

Technical overview - TL;DR
Unfortunately the PIN does not have an easy-to-extract hash.
We wrote a tool WINHELLO2hashcat.py to do the hard work. Please visit our GitHub (https://github.com/Banaanhangwagen/WINHELLO2hashcat) to learn all the details.
 

Technical overview - detail
There are multiple steps one needs to follow (based on the article of @tijldeneut):
 
1) Parsing the NGC protector
First we need to determine the PIN_GUID, which can be found in the Next Generation Credential-folder: \Windows\ServiceProfiles\LocalService\AppData\Local\Microsoft\Ngc.
Each user has a subfolder there with a specific GUID; it contains encrypted data, but no keys.
In the `...\NGC\`-folder, there are some .dat-files which contain metadata
  • user SID (1.dat)
  • provider (7.dat)
In the `...\NGC\[GUID]\Protectors\1`-folder, we find protected data, and some other metadata
  • Key1 GUID (2.dat)
  • Timestamp in LE (9.dat)
  • Encrypted data (15.dat)
This NGC-encrypted-data is RSA-encrypted and requires a private key which is DPAPI-encrypted with the PIN.
If a PIN is activated we should find a Software Key Provider (7.dat) with a corresponding GUID (2.dat).
 
2) Parsing the Crypto Keys
Next we need to go to the private keys folder: `%windir%\ServiceProfiles\LocalService\AppData\Roaming\Microsoft\Crypto\Keys` and parse all the keys.
They all contain metadata (key type (RSA or ECS), the Key GUID and the Public Key in clear text) + two System DPAPI blobs. The first DPAPI-blob contains the Private Key Properties, which can be decrypted with a System DPAPI key and a static entropy string.
 
3) RSA Private Key Properties
These RSA Private Key Properties contain two important fields: PIN_salt and PIN_rounds.
 
4) System Master Key
The decrypted System Master Key is also needed to fulfill 2). Therefore we need the SECURITY and SYSTEM hives.
 
5) Convert the PIN
 
Steps in order to convert the provided PIN:
Code:
Stage 1: convert the provided string to a specific hex format
        Phase A: convert each char to the hex ASCII representation
        Phase B: take the hex value of the uppercase representation of each nibble
        Phase C: concat and convert to UTF-16-LE representation
Stage 2: derive the previous value with PBKDF2-SHA256 with the provided salt and iterations
Stage 3: get the hex representation of the derived bytes in uppercase + convert it to UTF-16-LE
Stage 4: compute the SHA512 of this value
 
In Python:
Code:
def convert_userpin_to_secretpin(user_pin: str, pin_salt: bytes, pin_rounds: int) -> bytes:
    stage1_hexpin = user_pin.encode().hex().upper().encode('UTF-16LE')
    stage2_pbkdf2 = hashlib.pbkdf2_hmac('sha256', stage1_hexpin, pin_salt, pin_rounds)
    stage3_hexconvert = stage2_pbkdf2.hex().upper().encode('UTF-16LE')
    stage4_sha512 = hashlib.sha512(stage3_hexconvert).digest()
    return stage4_sha512
 
6) Check the PIN (proof of concept)
Finally, we need to verify that the provided sign matches the computed-one based on the provided masterkey, hmac, verif_blob and "secret pin" bytes.
 
Code:
    The hash algo used by default is SHA512 (for Win10 and Win11).
Stage 1: prepare the master key
        Phase A: compute the SHA1 of the master key
        Phase B: append 108 bytes of 0x0 (to have a bytearray of 128 bytes)
Stage 2: create two separate seeds (sub_digest_seed and main_digest_seed)
        - sub_digest_seed is the masterkey xored with 0x36
        - main_digest_seed is the masterkey xored with 0x5c
Stage 3: compute the sub digest
        SHA512(
            sub_digest_seed +
            hmac +
            '\x78\x54\x35\x72\x5a\x57\x35\x71\x56\x56\x62\x72\x76\x70\x75\x41\x00' +
            secret_pin +
            verif_blob)
Stage 4: compute the main digest
        SHA512(main_digest_seed + "stage3 digest")
 
In Python:
Code:
def is_signature_matching(sign: bytes, masterkey: bytes, hmac: bytes, verif_blob: bytes, secret_pin: bytes) -> bool:
    sha512_blocsize = 128
# Stage 1 : prepare the master key
masterkey = hashlib.sha1(masterkey).digest()
masterkey += ('\x00' * 108).encode()
 
# Stage 2 : create two separate seeds (sub_digest_seed and main_digest_seed)
sub_digest_seed = bytes(a ^ b for (a, b) in zip(masterkey, b'\x36' * sha512_blocsize))
main_digest_seed = bytes(a ^ b for (a, b) in zip(masterkey, b'\x5c' * sha512_blocsize))
 
# Stage 3: compute the sub digest
sub_digest = hashlib.sha512()
sub_digest.update(sub_digest_seed)
sub_digest.update(hmac)
sub_digest.update(b'\x78\x54\x35\x72\x5a\x57\x35\x71\x56\x56\x62\x72\x76\x70\x75\x41\x00' + secret_pin)
sub_digest.update(verif_blob)
 
# Stage4: compute the main digest
main_digest = hashlib.sha512()
main_digest.update(main_digest_seed)
main_digest.update(sub_digest.digest())
if main_digest.digest() == sign:
        return True
 
    return False
 
 
Extract the hash
Inspired by https://github.com/tijldeneut/dpapilab-n...keysdec.py, we wrote a tool from scratch - called WINHELLO2hashcat.py - to extract the needed variables, and to format it into a readable hash for Hashcat.
 
This is the format:
Code:
$WINHELLO$*SHA512*{pin_iterations}*{pin_salt}*{sign}*{masterkey}*{hmac}*{verif_blob}*{entropy}
 
This script will be published and maintained on our GitHub - https://github.com/Banaanhangwagen/WINHELLO2hashcat
 
 
Remarks about TPM
  • The above mentioned technique only works on systems without TPM-chip. The NGC Crypto Provider will no longer be “Microsoft Software Key Storage Provider” but rather “Microsoft Platform Crypto Provider”. The file `15.dat` will not be present.
  • As a reminder, in order to install Windows 11, a TPM-chip is mandatory. However, this requirement can be bypassed using an officially documented technique. (https://support.microsoft.com/en-us/wind...e77ac7c70e)
 
 
Remarks about PIN
  • A Windows Hello PIN is minimum 4 and maximum 127 characters long. (https://docs.microsoft.com/en-us/windows...e-defaults )
  • By default only digits are activated. Nonetheless, the user can chose to "include letters and symbols" in the PIN. Only non-accented letters, digits and special characters from ASCII-table are accepted.
  • During our testing, the pin_iterations were always 10000.
 
 
Remarks about signature check
During our testing, the hash algo used by default was always SHA512 (for Win10 and Win11).
 
 
Remarks about NGC
Reading the code on @tijldeneut's GitHub, we understand that when a Windows Hello PIN is used, the user-password can be extracted in clear (!) from disk.
Unfortunately, our tests with his tool were not always successful and we didn't have the time to deep-dive into this.
We encourage you to experiment with his code and to suggest any fixes or optimizations.
 
 
Credits
This work couldn't be possible without the hard work of:
Reply
#2
Awesome work, thanks to everyone involved with this!
Reply
#3
Indeed nice work, happy to see this happen, thank you for everything.
Reply
#4
Amazing work! Wondering if i could get some help with this?
I've stupidly forgotten my windows acnt sign in
I am using a secondary admin account on the system. I have elevated cmd to system cmd.
I have created HIVE backups on desktop.
I have also had a bit of luck with dpapilab where i have managed to get a hold of the indentical GUID, Keytype and Public Key(hex).
 
[Image: 123123.png]

So it seems to find the pin guid but its failing to decrypt it. Any idea what i might have missed?

Green indicates the PINGUID and usernames
Reply
#5
Apparently, there is a problem when decrypting the system_masterkey.
What Win version are you working on ? Only PIN or also a password sign-in?

Finally, can you PM me all the needed files in a zip, in order that I can reproduce/debug?
Thank you.
Reply
#6
(11-22-2021, 10:32 PM)Banaanhangwagen Wrote: Apparently, there is a problem when decrypting the system_masterkey.
What Win version are you working on ? Only PIN or also a password sign-in?

Finally, can you PM me all the needed files in a zip, in order that I can reproduce/debug?
Thank you.

Version = WIN10Pro 20H2 10.0.19042 Build 19042
I have ensured no TPM is present.
Requesting PIN on startup exactly like [Image: 141985995-0b7ff0bd-16d9-4d6a-9440-cbc53acda340.png]

Just Realising the version number i am on might be the issue now... What version was WinHello forced onto users? I had no luck decrypting the hashes i got out of mimikatz so it was assumed they where bogus and somebody pointed me here as a solution.
Reply
#7
Wink 
(11-22-2021, 10:56 PM)Pathogenex Wrote:
(11-22-2021, 10:32 PM)Banaanhangwagen Wrote: Apparently, there is a problem when decrypting the system_masterkey.
What Win version are you working on ? Only PIN or also a password sign-in?

Finally, can you PM me all the needed files in a zip, in order that I can reproduce/debug?
Thank you.

Version = WIN10Pro 20H2 10.0.19042 Build 19042
I have ensured no TPM is present.
Requesting PIN on startup exactly like [Image: 141985995-0b7ff0bd-16d9-4d6a-9440-cbc53acda340.png]

Just Realising the version number i am on might be the issue now... What version was WinHello forced onto users? I had no luck decrypting the hashes i got out of mimikatz so it was assumed they where bogus and somebody pointed me here as a solution.

Turns out I should have been using my system hash not user.

Can't thank you lot enough. This tool returned two years of my life after account recovery failed me!
Legends in your own right!
Thanks again keep up the great work
Reply
#8
Hello,
Hashcat 6.2.5, windows hello test hash
runs fine on NVidia RTX 2060 but fails on Radeon RX 460 with the following error:

* Device #3: ATTENTION! OpenCL kernel self-test failed.

The Passcape tool works fine for both GPUs
Reply
#9
(11-22-2021, 05:20 PM)Pathogenex Wrote: Amazing work! Wondering if i could get some help with this?
I've stupidly forgotten my windows acnt sign in
I am using a secondary admin account on the system. I have elevated cmd to system cmd.
I have created HIVE backups on desktop.
I have also had a bit of luck with dpapilab where i have managed to get a hold of the indentical GUID, Keytype and Public Key(hex).
 
[Image: 123123.png]

So it seems to find the pin guid but its failing to decrypt it. Any idea what i might have missed?

Green indicates the PINGUID and usernames
I have same problem: "Cannot decrypt the private key properties...No entry found"
Target PIN, reg files & folders from win 10 pro 1909 build 18363.1556.
Script running on win 10Pro 20H2 build 19042.1466
Reply
#10
Hey Short, what is the exact command that you used ?

Be advised that Pathogenex used the user_masterkey, and not the system_masterkey what gave that error...
Make sure that your paths are correct.
Reply