Skip to content

Instantly share code, notes, and snippets.

@arirubinstein
Last active June 8, 2021 10:50
Show Gist options
  • Save arirubinstein/fd5453537436a8757266f908c3e41538 to your computer and use it in GitHub Desktop.
Save arirubinstein/fd5453537436a8757266f908c3e41538 to your computer and use it in GitHub Desktop.

Update: download the new Pokemon Go app - it fixes all of this. Download it, and reauth, and you should be set. The grant scopes and prompt are correct and visible now too! Now if only I could actually find a pikachu...

Pokemon tokens are requested with these understandable scopes:

Shrinking the below, however it's still somewhat relevant

Here is the actual URL that loads in the webview on iOS: https://accounts.google.com/ServiceLogin?passive=1209600&continue=https://accounts.google.com/o/oauth2/programmatic_auth?scope%3Dopenid%2Bemail%2Bhttps://www.google.com/accounts/OAuthLogin%2Bhttps://www.googleapis.com/auth/userinfo.email%26client_id%3D848232511240-73ri3t7plvk96pj4f85uj8otdat2alem.apps.googleusercontent.com%26from_login%3D1%26as%3D-....&ltmpl=embedded&oauth=1&sarp=1&scc=1

Pokemon Google App Info:

  • Client ID: 848232511240-73ri3t7plvk96pj4f85uj8otdat2alem.apps.googleusercontent.com
  • Client Secret: NCjF1TLi.............

Going through the auth process on the device yields a bearer token at the end of the exchange with access to: (according to google, google's oauth playground, and token info)

// API callback
{
 "issued_to": "848232511240-73ri3t7plvk96pj4f85uj8otdat2alem.apps.googleusercontent.com",
 "audience": "848232511240-73ri3t7plvk96pj4f85uj8otdat2alem.apps.googleusercontent.com",
 "scope": "https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/userinfo.email https://www.google.com/accounts/OAuthLogin",
 "expires_in": 3472,
 "email": "itme@gmail.com",
 "verified_email": true,
 "access_type": "offline"
}

List of all services that this can be used by according to google

Google Apps Script Execution API v1

  • Run Scripts Runs a function in an Apps Script project that has been deployed for use with the Apps Script Execution API. This method requires authorization with an OAuth 2.0 token that includes at least one of the scopes listed in the Authentication section; script projects that do not require authorization cannot be executed through this API. To find the correct scopes to include in the authentication token, open the project in the script editor, then select File > Project properties and click the Scopes tab.

Google Dataflow API v1b3

  • Jobs Projects Creates a dataflow job.
  • Jobs Projects Gets the state of the specified dataflow job.
  • Jobs Projects Request the job status.
  • Jobs Projects List the jobs of a project
  • Jobs Projects Request the job status.
  • Jobs Projects Updates the state of an existing dataflow job.
  • Jobs Projects Leases a dataflow WorkItem to run.
  • Jobs Projects Reports the status of dataflow WorkItems leased by a worker.
  • WorkerMessages ProjectsSend a worker_message to the service.

Google People API v1

  • Get People Provides information about a person resource for a resource name. Use people/me to indicate the authenticated user.
  • GetBatch Get People Provides information about a list of specific people by specifying a list of requested resource names. Use people/me to indicate the authenticated user.

Google+ Domains API v1

  • Get Activities Get an activity.
  • Insert Activities Create a new activity for the authenticated user.
  • List Activities List all of the activities in the specified collection for a particular user.
  • List Audiences List all of the audiences to which a user can share.
  • Insert Circles Create a new circle for the authenticated user.
  • List Circles List all of the circles for a user.
  • Insert Media Add a new media item to an album. The current upload size limitations are 36MB for a photo and 1GB for a video. Uploads do not count against quota if photos are less than 2048 pixels on their longest side or videos are less than 15 minutes in length.
  • Get People Get a person's profile.
  • List People List all of the people in the specified collection.

Consumer Surveys API v2

  • Get Mobileapppanels Retrieves a MobileAppPanel that is available to the authenticated user.
  • List Mobileapppanels Lists the MobileAppPanels available to the authenticated user.
  • Update Mobileapppanels Updates a MobileAppPanel. Currently the only property that can be updated is the owners property.
  • Get Results Retrieves any survey results that have been produced so far. Results are formatted as an Excel file.
  • Get Surveys Retrieves information about the specified survey.
  • Insert Surveys Creates a survey.
  • List Surveys Lists the surveys owned by the authenticated user.
  • Start Surveys Begins running a survey.
  • Stop Surveys Stops a running survey.
  • Update Surveys Updates a survey. Currently the only property that can be updated is the owners property.

Google+ API v1

  • Get Activities Get an activity.
  • List Activities List all of the activities in the specified collection for a particular user.
  • Search Activities Search public activities.
  • Get Comments Get a comment.
  • List Comments List all of the comments for an activity.
  • Get People Get a person's profile. If your app uses scope https://www.googleapis.com/auth/plus.login, this method is guaranteed to return ageRange and language.
  • List People List all of the people in the specified collection.
  • ListByActivity People List all of the people in the specified collection for a particular activity.
  • Search People Search all public profiles.

Google OAuth2 API v2

  • Get Userinfo
  • V2 Userinfo

Conclusion

There is an undocumented flow of being able to exchange a token with the https://www.google.com/accounts/OAuthLogin scope for a session token for google properties. I believe this is a mistake on Google and Niantic's part, and isn't being used maliciously in the way that was originally suggested. It appears that using this token in the way that was initially suggested would still be difficult with this grant as the type of use for it is not programmatic (unless there is another hidden api somewhere to grant api tokens). Omitting this scope seemed to make the auth known as "Basic user information" instead of "Full account access", and is likely what Niantic will do to update the client. The auth flow is confusing, and google should reflect that logging in with this scope can yield a token that can be exchanged for sessions on google properties. IMO, Google shouldn't be giving out this scope to non-google apps.

Given that Google is going to be retroactivelly re-scoping tokens to remove this possibility, Pokemon Go should be safe to play in the next couple of days on iOS, or even now. Go have fun and play a game :)

An update and info about https://www.google.com/accounts/OAuthLogin

I spent the night digging to understand why this specific grant is "more permed" than the others, and uncovered some very interesting and undocumented information. There is very little documented about this uberauth mechanism, however it can be used to access more than the initial scope for the oauth grant. It's the mechanism that chrome uses to auto-log you into google properties.

It appears that only specific projects (including this one by Pokemon Go) can request this specific type of auth.

It IS possible to exchange an accesstoken with https://www.google.com/accounts/OAuthLogin for a specific token called an uberauth. This token can then be used to open a web session with any google property, leading to the "Full Account Access".

The token that gets generated must be exchanged for one of these "more powerful" tokens to be useful, and the article below by Duo covers how this process can work. While monitoring the app, I did not see any activity from the app's side to exchange a token for this, and it appears that this level of access is not designed to be used programmatically (via apis), but rather via a web browser. Making use of this access programmatically seems difficult, however there may be additional undocumented APIs that would allow an exchange for an api token of sorts.

The app uses binary blobs to communicate with Niantic's servers, so I can't speak as to whether or not they are storing or even seeing these tokens. Given Niantic's response, it appears that they are most likely going to remove this scope from a new version of the Pokemon Go app.

In summary:

  • The direct token that Niantic gets can't access the gmail api / gcal api
  • However, the token could potentially be exchanged through the undocumented mechanism /MergeSession to create a web session logged in as you on any google property
  • I haven't seen the app try to exchange this token for an ubertoken while poking at it
  • The app communicates with Niantic with binary blobs and theoretically could send this token to them
  • This lines up with Niantic and Google's statement
  • Undocumented parts of auth flow are bad, and can lead to problems like this ambiguity
  • This token is overpermed, due to the https://www.google.com/accounts/OAuthLogin scope
  • This oauth flow is special, and doesn't prompt you for confirmation on additional auths. Given that the secret is in the app, this is worrisome

Links:

Code:

Requesting an uberauth from the bearer token:

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

Redeeming an uberauth session to a gmail session

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

@deoxxa
Copy link

deoxxa commented Jul 12, 2016

Just a note - the communication from the app to Niantic isn't encrypted. It's plain old binary protocol buffers. There is a point where your JWT is sent to them though, specifically in the first exchange (which seems to be some kind of channel/session negotiation).

EDIT: I mean, it is encrypted with HTTPS. So it's not like you're going to get MITM'd at a cafe, but you can dig the plaintext out if you control the device.

@DaxDupont
Copy link

@deoxxa
http://www.theregister.co.uk/2016/07/11/pokemon_go_leaky/ It doesn't do HTTPS certificate checking apparently.

@arirubinstein
Copy link
Author

Thanks @deoxxa - you're totally right here. I updated the post to reflect that. It's still wrapped in TLS, however I didn't dig into the protocol or try to reverse it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment