Passwordless products promise greater security and convenience by allowing users to log in to Windows systems with only their smartphone. But what is going on behind the scenes and how could a domain’s security stance be worsened by such a solution? In this post I will explain how these products are implemented and detail the vulnerabilities and weaknesses discovered in three tested products.
This blogpost is not about Windows Hello. It is about a specific class of products, which I will call passwordless products, that allow users to login to any domain joined PC using only their smartphone. Think of it as the modern iteration of the smartcard login, but instead of a smartcard the user uses his smartphone. Additionally all the products in this blogpost are third party products, as far as I know there is no such product by Microsoft itself.
The general architecture involves three parties: the smartphone on which the product specific app is installed, the computer on which the product is installed and an on-prem or cloud server, which facilitates the communication between the smartphone and the PC.
When a user authenticates on his computer, the user also authenticates to the domain controller, to access network resources in the Active Directory environment. When a user logs in with one of these passwordless products this is also the case, and the described products do not modify how authentication is done in the Active Directory environment.
The implementation on the computer is done with a custom Windows credential provider and a service. Windows credential providers are DLLs loaded by the login process, which have the purpose to gather user credentials and pass them to the login process. (Microsoft Documentation) The paswordless products install their own credential provider to hook themselves into any started login process. The service handles communication to the server and communicates via IPC to the credential provider.
The most important takeaway of the client implementation is that the credential provider needs to pass valid credentials to the logon process, which are then validated later on in the login process. The credential provider itself does not have the power to validate credentials. Since the user is not entering his credentials, valid credentials need to be cached somewhere and on successful authorization by the user (on the app) are then passed to the credential provider.
This is the main functionality these products implement, which is caching user credentials and passing them to the credential provider, once the user has authorized the login on their smartphone.
In the rest of this blog, three products are detailed and a vulnerability for each product is presented. The vulnerabilities allow non-privileged users to abuse these cached credentials to log in as another user.
Thales SafeNet CVE-2021-42138
The user installs the SafeNet mobile app and enrolls the app for his user by scanning a QR code provided by the company.
When a user logs into a computer, the user enters the username, gets a login notification on the app and after accepting the notification, if it’s the first time the user logs into that computer, the user has to enter the password.
On subsequent logins to the same computer the user will only need to enter the username and accept the login notification on the smartphone to log in.
How it works
SafeNet caches the login credentials on the computer. When a user logs in the first time to a computer, the SafeNet credential provider encrypts the user’s password and writes it to a file. The next time the user logs in, the credential provider reads that file and decrypts the user’s password.
Since the file is readable for all users I investigated how the passwords were encrypted, as a vulnerability there, could allow any user to decrypt the passwords of other users.
Using dynamic analysis it can be seen that DPAPI is used to decrypt the credentials.
Checking how the passwords are encrypted, shows that the DPAPI encryption is done with the LocalMachine flag:
A quick glimpse at the documentation shows that with this flag, any user on the computer can decrypt the data.
Additionally, the decryption uses the entropy parameter. In DPAPI the entropy acts as a sort of password, meaning a blob can only be decrypted if the same entropy value as used in the encryption, is used for decryption. However, it turns out the value is static and hardcoded into the binary.
So here is what we have: a file with encrypted user passwords readable by all users, DPAPI encryption with the LocalMachine scope and static entropy. These together result in a vulnerability (published as CVE-2021-42138), which allows any user on the machine to decrypt the passwords stored in the file, including the password of other users.
The following tiny PowerShell script can decrypt the passwords stored in the file on any PC with the vulnerable SafeNet version installed.
Thales deployed mitigations against this vulnerability. However in a follow-up test, it turned out that it was still vulnerable. The only thing that changed was another 2 layers of encryption. A new DLL manages the new encryption of the user’s passwords. To exploit the new vulnerability, it is possible to import the DLL and call one of the exported functions, appropriately named getADCachedCreds.
So why not just change the access permissions on the file with the encrypted passwords, surely this would be the most intuitive way of fixing this vulnerabilty? The reason why the file needs to be readable, and the password being decryptable by normal users is the fact that Thales SafeNet supports passwordless login for the “Run as different user” Windows functionality. The login process for “run as different user” runs as the current user. As opposed to when normally logging in on the lock screen or clicking run as Admin, where the login process runs as the SYSTEM user.
Since the Credential Provider DLL is loaded into the logon window process the encryption/decryption of the passwords is done with the permissions of that process. Passwordless login for “run as different user” would not work if the file containing the encrypted passwords was only readable by the SYSTEM user, since on this login, the DLL will be running with the permissions of a normal user.
In the newest version of SafeNet, a registry key is present, which if set to 1 ensures that DPAPI encryption will be done without the LocalMachine flag. As far as I know however, this registry key is not set to 1 by default…
The user installs the VeridiumAD mobile app and enrolls the app by scanning a QR code provided by the company.
When the user logs into a computer, the user enters the username, gets a login notification on the app and is logged in. Unlike SafeNet and HYPR, the user never has to enter his password even the first time logging into a computer.
How it works
VeridiumAD uses an on-prem server, which interacts with the AD CS service to obtain a user login certificate. This login certificate is sent to the computer after the user has authorized a login. The login process is shown in the image below. After the user clicks log in with VeridumAD and enters the username, the service makes an HTTP request to the server. After the server receives the HTTP request, the push notification is triggered for that user.
The service also starts polling the server, waiting for the user to either approve or decline. Once the user approves, the login certificate of the user is returned on one of the polling requests. This login certificate is passed to the VeridiumAD service, which in turn sends it to the VeridiumAD credential provider and then to the login process.
The HTTP request, which triggers the login notification, can be made by anyone in the internal network with access to the VeridiumAD server API. When sending the request, an arbitrary user-SID and a custom notification text can be specified. This will trigger the login notification for that arbitrary user. Additionally, the server can also be polled and if the victim user accepts the malicious push request, the polling user obtains this victim’s login certificate.
There is a small complication however, in that a SSL client certificate is required to actually communicate with the server’s API.
When the VeridiumAD service is restarted, the service sends a certificate signing request to the server and in the response receives the SSL client certificate.
The endpoint is protected with NTLM authentication. However, this CSR HTTP request can be made by any domain user.
This vulnerability then allows for any user to potentially obtain the login certificate of all other user’s if they fall for the malicious push notification. The requirements for mounting the attack are access to the VeridiumAD API and credentials of any valid domain user.
VeridiumId mitigated the vulnerability by making it such that only computer accounts in a specific group may make the CSR HTTP request.
HYPR (CVE to be assigned)
The user installs the HYPR app. To enroll the HYPR app for passwordless log in to a computer, the user logs in normally (with password) to a computer, then opens the HYPR desktop app and scans a QR code displayed by the desktop application. Afterwards the user gets a button in his HYPR app to log in as the current user for that computer. A user may have multiple user/computer login buttons in his app.
To log in the user simply clicks the desired user/computer login button and will be logged in and therefore the user does not even need to touch the keyboard.
How it works
HYPR caches the user’s login certificate on the user’s phone. The HYPR service on the computer continuously polls the cloud server and if the user authorizes a login in the app, the app sends the encrypted login certificate to the cloud server, which then forwards the certificate to the client as part of a polling response,. On the client the certificate is decrypted by the HYPR service and passed to the login process.
The login certificate is encrypted with a key derived with Diffie-Hellman between the computer and the smartphone. The certificate can only be decrypted as SYSTEM on the computer or with full control of the smartphone.
It is possible to obtain encrypted login certificates of other users. This stolen encrypted login certificate can be leveraged to login as another user. The attack scenario is that an attacker has code execution as a low privileged user and is looking to login as another user (referred to as the target user), who uses HYPR to log in to that computer.
Obtaining Encrypted Login Certificates of other users
HYPR stores information of the users enrolled for passwordless login on the computer in the registry. Each user has a key, containing his devices (smartphones) and values needed to communicate to the cloud server. The keys are readable for any user on the computer.
The values are stored DPAPI encrypted without entropy and the LocalMachine flag set. Meaning these values are readable by any user on the machine and a local attacker can read out the values of other users.
With these values it is possible to poll the cloud server. If the target user clicks the login button in their HYPR app for that computer, the attacker obtains the encrypted login certificate of the target user.
To exploit the vulnerability. the attacker starts a login process on his own HYPR app, which the attacker enrolled for the low-privileged user on the computer, modifies the parameters sent to the HYPR cloud server in step 2 to start a login process for the target user on the computer and then sends the stolen encrypted login certificate of the target user to the server in step 3.
There is however a complication. When initiating a login, the HYPR cloud server sets the encCounter value. This encCounter value is sent to the app after the login flow is started and also to the HYPR service in the polling response containing the encrypted login certificate.
The app takes the encCounter value prepends it to the login certificate, encrypts that data and sends it to the server. The HYPR service takes the encCounter value and compares it to the value in the obtained plaintext. If the encCounter in the plaintext does not match the encCounter received in the HTTP response, the HYPR service aborts the login.
This complicates the attack, since after stealing the encrypted login certificate, the attacker now needs to make sure that the static encCounter of the stolen encrypted login certificate matches the encCounter set by the server. However, the attacker cannot influence the value set by the server.
Fortunately for the attacker, the encCounter value is predictable. It starts at 1 and is incremented by one for each login. Additionally the encCounter is reset back to 1 when a user is deregistered from the computer. When a user deregisters from a computer and reregisters, the shared encryption key between smartphone and computer however stays the same, since the DH private/public keys are static for a smartphone/computer.
With the values in the registry it is possible to deregister the target user from the computer.
So to prepare the actual attack, the attacker first obtains an encrypted login certificate of the target user, then deregisters the target user and waits for the target user to re-register. Afterwards the attacker starts a login process on the computer (in this case a UAC login prompt) and starts a login process on the app. On the first HTTP request sent by the app, the attacker replaces the username and device id (identifying the smartphone) with the target user’s username/device id.
Afterwards a biometric/pin prompt needs to be done by the attacker on the app and then a session id is sent back. This session id is used to obtain the encCounter value and prepare the server to receive the encrypted login certificate.
If the EncCounter matches the one of the encrypted login certificate of the target user, the attacker continues to the next step, otherwise the previous steps are repeated.
The attacker nows sends the stolen encrypted login certificate to the server:
This certificate is now sent as the polling response to the HYPR service by the server. The service decrypts the certificate and passes it to the login process. Now the attacker is logged in as the target user.
Another vulnerability which allows a user to log in as another user. There are however a number of countermeasures which can be taken to foil this attack. Making the encCounter a random value and making sure the value does not repeat, will making reusing encrypted login certificates impossible. Ensuring that only the correct user has access to the values stored in the registry would prevent being able to deregister or poll the server on behalf of another user. And lastly it should not be possible to start login flows on the app for other users. The first and second issue are fixed in newer HYPR releases.
It should be clear that these passwordless solutions in no way eliminate passwords from the network. Instead credentials are cached somewhere and a complex infrastructure is set up to pass the credentials to the login process upon user authorization. Vulnerabilities will expose these cached login credentials to be abused by attackers with a foothold in the network or on a computer.
For all tested products there is a new way to obtain login credentials of other users as a local Administrator. This is of course anyway possible on Windows. However with such a product installed, obtaining the credentials cached by the passwordless product does not require dumping memory or cracking a hash. Instead simply mimicking the credential provider/service will suffice. This will make such an attack hard to detect/prevent.
I hope this blogpost was able to shed some light on how these products work. I want to finish by saying that I have only tested the three products above, there are other products whose implementation may hugely differ. All three companies were very cooperative and were quick to fix the vulnerabilities, that were responsibly disclosed to them. The vulnerabilities, as presented above should not be present anymore in the newer versions of these products.