November 30, 2019

Ha! Success. Got past the CAPTCHA prompt

Good news is, I managed to log into my test account. Bad news are, it doesn't work on a PC (yet). But by trying to lock non-droids out, Google might have told us more about the login internals than intended.

Here’s the thing: the login code in Raccoon is horrible. It wasn’t well designed to begin with and just got worse over time as patches were required. When the CAPTCHA problem hit, I already had a nearly finished replacement, that suddenly just stopped working. So, I spent the better part of this month on poking around and tweaking my implementation till the network requests looked exactly like those of a real device (fun fact: every 3rd party google login client does it wrong). Still no luck. Then I finally decided to transplant my code into a tablet, letting it communicate through Android’s own network stack and guess what? Success! No CAPTCHA challenge at all.

Considering that my current implementation isn’t that much different from the previously working one, this allows for two possible conclusions:

  • A real device sends some kind of a ping before initiating the login process, whitelisting the IP address.
  • Google does OS fingerprinting on the network stack to figure out if it’s a genuine Droid.

I couldn’t find any evidence for the ping thing and it would be stupid (not reliable) anyway. So my money is on the fingerprinting. Couple of observations:

  • Real Android devices do have support for CAPTCHAed logins. My code handles them exactly the same, but only gets a new challenge every time a solution is sent.
  • Even with the recent changes, a user of a real device is not suppose to see a CAPTCHA.
  • There hasn’t been an outcry from Android 4 users. So this OS detection must work with legacy devices and without deploying code.
  • My CAPTCHAed login attempts to not pop up in the security log of the web console.
  • Conclusion: The login server detects early that it is not talking to a real droid and wouldn’t let you pass no matter what. It just sends you the challange to keep you busy/in the the dark.
  • The transplanted code is still able to login, even if it omits a couple of headers, a real Droid would send (“source”, “sdk_version”, “User-Agent”).
  • Most surprisingly, the useragent does not seem to matter at all. It works with “GoogleLoginService” as well as with “GoogleAuth” (making my previous blog post interesting, but irrelevant).
  • Any project sending headers such as “client_sig” has clueless developers. It (probably) doesn’t cause harm, but it also doesn’t belong there either.
  • Android contains tons of (questionable) performance hacks. The network stack is no exception.
  • Fingerprinting happens above (not on layer) 4, but below the application protocol.