Traveling with OAuth - Account Takeover on Booking.com

We discussed this vulnerability during Episode 193 on 06 March 2023

Relatively straight forward oauth hijack/account takeover flow with one interesting aspect in actually performing the login with the hijacked OAuth code.

The straight forward part is leaking the code from Facebook. Facebook’s side of the system only validates that teh redirect_uri belongs to the appropriate domain. This isn’t terribly unexpected, but combined with an open-redirect somewhere within the Booking.com domain one can have the victim redirected to an attacker controlled location with the code in the URL.

Which is the first issue documented, an open redirect. I’m not exactly sure what Booking.com was thinking here but under the Dashboard there is an option to ‘Add a Display Name’ and clicking that takes you to a domain like the following: https://account.booking.com/oauth2/authorize?aid=123;client_id=[...];redirect_uri=[...];response_type=code;state=[...]

It looks like an OAuth flow page, though according to the author it just redirects off to the /mysettings/personal endpoint. And that redirection happens based off of a Base64 encoded JSON content that is encoded into the state parameter. The mysettings_path from that JSON content is used to craft the redirect URL, and one can encoded their own URL pointing to another domain and have it redirect. So its an odd endpoint, but still an open redirect.

Now with the ability to steal codes used the open redirect, the challenge is logging in. Which did have a bit of an extra difficulty. Usually one could take the stolen code, and then during a legitimate OAuth flow tamper with their request, replacing the code returned by Facebook with the stolen code. The application iwll take that code and do its usual flow with it. The problem is that you send the redirect_uri with the code during the exchange process. The Booking server doesn’t know an abnormal redirect_uri was used, so it sends along the normal one, and when Facebook sees that it throws back an error because the redirect_uri doesn’t match the one used.

Fortunately for the authors here, the Booking mobile application had a bit of a weird process going on, where it would receive the code send it to booking.com backend, which would redirect it back to the back (using a deep link as its redirect), which would then send the code again to the server. When the code is passed to the backend for the second time, it sends a resultUri parameter, this parameter is used as the redirect_uri when exchanging the code. So by passing in the malicious redirect_uri value in that request, the flow will complete as expected, granting an account takeover.