HexBrain

Ian Dunn · Report #277534

Timing Attack in Google Authenticator - Per User Prompt

Informativestatus
highseverity
$25bounty
6upvotes
29 Oct 2017disclosed

How it was found

Google Authenticator - Per User Prompt contains a timing attack vulnerability in how it validates the application password for a user account.

if ( sha1( $attempted_password_plaintext ) === $valid_password_hash || wp_check_password( $attempted_password_plaintext, $valid_password_hash ) ) {
	$this->is_using_application_password = true;
	return $user;
}

wp-content/plugins/google-authenticator-per-user-prompt/google-authenticator-per-user-prompt.php

As the above code runs on the authenticate hook, and uses a strict equality check, it's possible to brute force an application password using a timing attack and gain access to the account, without needing the real password or even a valid OTP token.

The plugin adds two authenticate hooks, one for the above app password check, then a second that does the OTP validation stuff, but only if the not using an app password. This means that we only need the app password to login, which we can brute force via timing attack.

if ( 'enabled' == trim( get_user_option( 'googleauthenticator_enabled', $user->ID ) ) && ! $this->is_using_application_password ) {
    // ... OTP stuff
}

The correct way to check the app password is to use hash_equals(), which is safe from timing attacks - https://secure.php.net/manual/en/function.hash-equals.php

Example:

if ( hash_equals( sha1( $attempted_password_plaintext ), $valid_password_hash ) || ... {

It's worth noting that hash_equals() is already in use in Google_Authenticator_Per_User_Prompt::verify_login_nonce().

All accounts that have an app password enabled (which is not by default) are vulnerable to takeover using this method.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original