Two-Factor Authentication Vulnerabilities
Last updated
Last updated
An application can implement the "remember me" function so that the next authentication from the same device does not require to enter the second factor. To implement this functionality, an application can save a long-lived token to cookies and/or remember an IP address.
In case it is a long-lived token, you can check the following points:
Token is randomly-generated
Token is different for each user and session (device)
Token is stored secure and not accessable from JavaScript, check Cookie Security
Check if it is possible to revoke remembered devices remotely
If an application remember an IP, check if it possible to spoof an IP using HTTP headers, check Abusing IP whitelists
An application can "memorizes" the IP address from which a user is authenticated and does not ask for the second factor at further logins. If an application relies on HTTP headers to determine a client's IP address, try to spoof the IP address using the following headers:
Enabling two-factor authentication must revoke all existing sessions. If it does not happen, a victim will not be able to manage the security of their account. As a result, an attacker can keep an active session created before a second factor was enabling for an extended period of time.
An application can ignore two-factor authentication when performing actions that can lead to automatic login to an user account.
An application can issue a session token with limited access after providing credentials. Try to use this session token in an un-enrollment request to disable 2FA (or access API endpoints which require authentication). You can check it with the next steps:
Submit credentials to an application
Catch a session token from the response
Stop an authentication on the 2FA step
Use the token in a un-enrollment request (or an API request)
Login into account without 2FA requirement (access sensitive data / perform changes)
References:
The implementation of two-factor authentication for mobile or desktop version of an application may differ from a web one. Two-factor authentication may be weaker or completely absent.
If an application does not require an additional confirmation (current password, current OTP, code from SMS, etc.) when disabling two-factor authentication, this provides an option to disable two-factor authentication via CSRF, XSS or Clickjacking attacks.
An application can automatically log into an account without requiring a second factor after the password recovery / email confirmation process is completed. For instance, you can check it for the password recovery with the following steps:
Log into an account.
Enable two-factor authentication.
Go through password recovery.
If after changing your password you got into your account without a second factor, an application is vulnerable.
An application can ignore two-factor authentication when logging in through a third-party account, for instance, social networks, Github, Google, etc. You can check it with the following steps:
Log into an account.
Enable two-factor authentication.
Link a third-party account.
If logging in through a third-party account does not require a second factor, an application is vulnerable.
If a staging version of an application is publicly available, try logging in with your credentials. In such environments, two-factor authentication can be disabled. Non-production environments can be located on separate domains or subdomains of the main domain, for instance:
beta.website.com
stage.website.com
beta-website.com
stagewebsite.com
etc.
Additionally check if older API versions are available, they may not require a second factor or not have rate-limit algorithms. If an application supports API versioning, the version can be passed in the URL or HTTP headers, for instance:
https://api.website.com/v1/users
https://website.com/api/v1/users
Accept: application/test.data.v1.12+json
etc.
References:
With two-factor authentication, an application can direct a user to a special page using a URL with predefined parameters. If this page can be accessed without cookies or using cookies from another session, you can check the following cases:
URL generation
URL expiration date
Search engine URL indexing
If the URL is guessed, indexed by search engines, has a long expiration date, it can be used to sign in to accounts without entering credentials. Therefore, if there is a way to bypass two-factor authentication, you can access other users account.
Backup codes are generated immediately after a second factor is enabled and are available only after enabling. For each subsequent request, the codes can be generated anew or remain unchanged.
Try to find a vulnerability that could steal backup codes from a response to a request to backup code display endpoint.
Applications that use time-based codes typically maintain a time interval during which the codes are valid, so people can type them slowly. Since new codes are generated in steps of n
seconds (generally n
is 30 - 60 seconds), multiple codes are valid at the same time. However, each code in the allowable window is a valid code for the user's account. If the codes are valid for an hour, many codes are valid at the same time within this window. Therefore, it is much easier to guess the valid code, because there are more than one valid code in the possible set of codes.
For example, if the codes are generated in steps of 30 seconds and a common validity range here is about 5 minutes in either direction from the time as set on the server, the allowable window is [current_time - 5 mins, current_time + 5mins]
and the number of valid codes at the same time is 10 mins * 60 sec / 30 sec = 20 codes
.
References:
An application can revoke the current code and does not store the most recent code's timestamp for rejecting codes that are older than the current one. As a result, an attacker is able to use a code that is older that the one, that the user chooses to enter. You can check it with the following steps:
Open two different browsers and go to log in
Get to the 2FA screen in both browsers
Obtain a valid 2FA code, and write it down, do not use it yet
Wait for the next valid 2FA code, and log in using it in one browser
In the other browser, try to log in with the old 2FA code that was written down
If you can log in using both sessions, the application is vulnerable
An application can provide multiple 2FA modes, such as SMS- and TOTP-based 2FA processes. If an application uses a per-user unique parameter other than a half-authenticated session cookie to refer to the desired 2FA mode, you can try to complete an authentication process with your 2FA mode that is not used by a victim. An example of an attack flow might contains the next steps:
Victim set up SMS-based 2FA
Attacker enrolls in 2FA using an authenticator app (TOTP-based 2FA) and saves their unique parameter, for instance factor_id
Attacker enters a victim's email address and password
If the password is correct, an attacker's browser is sent a new authentication cookie and redirects to /mfa/sms/verification
Attacker does not follow the redirect to the SMS verification form. Instead, attacker sends their factor_id
and code from the authenticator app with victim's half-authenticated cookie to TOTP verification endpoint: /mfa/totp/verification
endpoint.
References:
Typically, an authentication flow initializes a session after creds have been passed and waits for a second factor to complete the flow. Try to change password/disable 2FA in this step and complete the authentication flow. If the session does not time out or you can renew it yourself (for example by changing the authentication way) and an app allows you to login, you can still access the user account even after changing password/disabling 2FA.
An example of an attack might look as follows:
An attacker gains access to a victim's account that does not have 2FA.
The attacker enables 2FA for the victim's account.
In another browser, the attacker stops after passing creds and waits indefinitely at this step.
The attacker disables 2FA for the victim's account.
The victim regains access to the account and changes password/resets sessions.
The attacker completes the flow with 2FA and gain access to the account again.
References:
Most code-based 2FA systems rely on a shared secret. If this secret is not actually cryptographically secure, or is very short, an attacker may be able to guess it. As a result, an attacker will be able to generate valid codes.
If you have source code access, ensure that the secret is being generated with cryptographically strong generator. Most programming languages' default random number generators are predictable, meaning an attacker might be able to figure out which secrets were assigned to which users. Additionally, verify that a shared secret is 20 bytes long at least, because shorter secrets should be avoided for security purposes.
If you can review the source code, try to check the secret for lenght and apparent randomness (scan a QR code with a barcode scanner to retrive the secret). Generate several secrets for the same or different accounts and try to answer the following questions:
Is each secret different?
Does any part of the secret appear to be sequential?
Is any part of the secret based on the account information?
Otherwise insecure?