Skip navigation
An equation that indicates logging in plus the Google Application Specific Password (ASP) equals danger!

Beyond the Vulnerabilities of the Application Specific Password: Exploiting Google Chrome’s OAuth2 Tokens

Where we left off...

Earlier this year, we wrote about how any Google Application Specific Password (ASP) could be used to bypass 2-Step Verification and take full control of an account. Before our post, Google had issued a fix that prevented this technique from being used to fully compromise an account - but even after the fix, your ASPs can still be used to do almost anything else with your Google account.

This leads to some threats that might not be immediately obvious, even to the security-conscious. To illustrate this point, let's consider two different types of services:

  • Instant Messaging (e.g. Google Talk / Hangouts)
  • E-Mail (e.g. GMail)

It varies per-user, but the typical threat models around these services are quite different. If an attacker compromises your Instant Messaging account, he might be able to spam your contacts (or at worst, perform some forms of social-engineering attacks against them). However, if an attacker compromises your main E-Mail account, then it's likely that he'll immediately be able to compromise many of your other accounts across the internet, as E-Mail is one of the most commonly used account-recovery mechanisms.

Consider this piece of discussion by the developers of Pidgin (a popular cross-platform instant messaging client) on why they do not bother to encrypt stored passwords:

Instant messaging is not very secure, and it's kind of pointless to spend a lot of time adding protections onto the fairly strong file protections of UNIX (our native platform) when the protocols themselves aren't all that secure. The way to truly know who you are talking to is to use an encryption plugin on both ends (such as OTR or pidgin-encryption), and use verified GPG keys. Secondly, you shouldn't be using your instant messaging password for anything else. While some protocols have decent password security, others are insufficient and some (like IRC) don't have any at all.

However, because an Application Specific Password is not Application Specific, this rationale breaks - what was expected to be a low-value credential is actually a very high-value credential.

Pidgin isn't the only example of this problem - we recently found a very similar issue in the current stable version of Google Chrome...

Exploiting Google Chrome's OAuth2 Tokens

This week, we presented a talk at Passwords13 covering our investigation into Application Specific Passwords. In the process, we did some follow-up investigation on a few loose-ends from our previous work; one of these was a realization that Mac/Linux/Windows versions of Google Chrome have an auto-login feature for Google accounts, just as on Android / ChromeOS. This feature had been critical in our previous work with ASPs and Android, so we figured it was well worth a look.

On Desktop versions of Chrome, the auto-login feature is hidden and disabled by default; you can turn it on by navigating to chrome://flags:

enable auto-login

However, if you have ever linked Chrome to your Google account (e.g. for bookmark / tab synchronization), this feature will immediately work, without requiring you to re-authenticate. From this, we could infer that Chrome was storing a credential with access to much more than just your bookmarks and tabs. So, we fired up our intercepting HTTPS proxy again to figure out exactly how this works.

First, we saw a request that uses a stored OAuth2 "refresh token" to request a temporary access token:

POST /o/oauth2/token HTTP/1.1
Host: accounts.google.com
...
refresh_token=1/0209_TGZzDyfxwozFV...&client_id=77185425430.apps.googleusercontent.com&client_secret=OTJgUOQcT7lO7GsGZq2G4IlT&grant_type=refresh_token

Notably, the client_id and client_secret parameters here are hardcoded into Chrome's source code, so we only need the refresh_token to perform this request. As a response, we got:

HTTP/1.1 200 OK
...
{
    "access_token" : "ya29.AHES6ZT23S3gmlK...",
    "token_type" : "Bearer",
    "expires_in" : 3600
}

Then, using this access_token, we went on to request an "uberauth" token:

GET /OAuthLogin?source=ChromiumBrowser&issueuberauth=1 HTTP/1.1
Host: accounts.google.com
Authorization: OAuth ya29.AHES6ZT23S3gmlK...
...

This yields a response like:

HTTP/1.1 200 OK
...
APh-3FyuAXYyOOQwaR20...

Using this "uberauth" token, we can construct a URL using the https://accounts.google.com/MergeSession mechanism - the same one we saw before when using an Application Specific Password - to sign us into almost any Google web property. For example:

http://accounts.google.com/MergeSession?source=chrome&uberauth=APh-3FyuAXYyOOQwaR20...&continue=https%3A%2F%2Fmail.google.com%2Fmail%2F

Notably, from all of this, we haven't seen any mention of an Application Specific Password - Chrome has fully converted to an OAuth2 workflow (at least as of our testing version - 28.0.1500.71 on OS X). However, as it can log you into virtually any Google web property (except the most security-sensitive Account Settings pages), the OAuth2 token is still about as powerful as an Application-Specific Password.

So, our final task was to find out how Chrome stores this token. Looking in the Chrome Preferences file for the default user profile, we found:

...
"oauth2LoginRefreshToken": {
    "status": "Successful",
    "value": "1/0209_TGZzDyfxwozFV..."
}
...

That's right: it's stored in plaintext.

So what?

As with our earlier discussion of E-Mail versus Instant Messaging, the issue here is once again that our intuitive security expectations do not match reality. If you think that Chrome's stored credentials can only be used to sync bookmarks, tabs, etc., then you might not consider it at all problematic that Chrome would store them in plaintext. However, when (to enable a hidden, mostly-unknown feature) these credentials are made much more powerful - in some ways, even more powerful than your actual password for an account with 2-step verification enabled - bad things could result...