Booking.com, one of the world's largest online travel agencies, recently patched a vulnerability in its implementation of the OAuth protocol that could have allowed attackers to gain access to customer accounts by simply tricking them into clicking a link.
The attack combined three separate issues that on their own could be categorised as low risk and could be introduced by many developers into their implementations.
"For the OAuth issues we found, had a bad actor discovered and successfully exploited them, that attacker could have taken over the accounts of users logging in via Facebook," researchers from Salt Security, a company that specialises in securing APIs, said in their report.
"Once logged in, the attacker could have performed any action on behalf of the compromised users and gain full visibility into the account, including and all of a user’s personal information. Our research found that attackers could then use the compromised booking.com login to also log into sister company Kayak.com."
The proof-of-concept attack was privately reported to Booking.com and was quickly mitigated, the travel agency saying its investigation revealed there had been no compromise of the Booking.com platform and inviting other researchers to use its public bug bounty program.
Nevertheless, the report has valuable insights for website developers working with OAuth.
What is OAuth and how does it work?
OAuth is a highly popular Web authorisation and pseudo-authentication standard, through which one application can ask a different one for access to certain data it holds about a user or to verify that they are authenticated.
The common options on various websites to login with your Google, Facebook, or Microsoft accounts instead of creating new accounts use OAuth, where Google, Facebook, and Microsoft play the role of identity providers.
However, OAuth identity providers do more than assert back to requesting applications that users are authenticated or not.
They play the role of API providers, too, where the requesting application will gain access on behalf of the user to whatever services and data those providers expose through their APIs. This can mean accessing user profile information like their name, picture, and more.
The result of a successful OAuth request is an access token that provides continuous access to the identity provider's API on behalf of the user.
This makes it different from pure authentication-only standards like OpenID. It's the equivalent of asking someone for the key to their house to prove they say who they claim they are instead of simply having them show their government-certified ID.
That's why when implemented incorrectly, OAuth can have serious security implications. Since Oauth is a complex protocol, developers can make many subtle mistakes.
"Many ecommerce websites and apps use OAuth, for example, to allow users to authenticate their account and make purchases without having to enter their credentials multiple times," the Salt Security researchers said. "A security breach in OAuth can lead to identity theft, financial fraud, and access to all sorts of personal information including credit card numbers, private messages, health records, and more."
In a simplified manner, using Facebook.com as identity provider, for example, the OAuth flow works like this: When the user asks a website to log them in using their Facebook account, the website generates an encoded request and redirects the user's browser to Facebook's OAuth endpoint passing the secret request along as part of the redirect URL.
Facebook then ensures the user's browser has an authenticated session. If not, it asks the user to log into Facebook. Facebook then processes the website's request and generates an access token. It then redirects the user's browser back to the originating website, passing the also-encoded access token along in the URL.
The website decodes the access token and can now access Facebook APIs on behalf of the user and infer they are authenticated.
So, we are dealing with two redirect URLs the user's browser will follow, one from the website to Facebook and one from Facebook back to the website. The starting redirect URL from the browser to Facebook will include the redirect URL path where Facebook will then redirect the user. For example:
After Facebook processes this request it will redirect the user's browser to the redirect_uri value from the original request and append the secret token to it.
After receiving this response via the user's browser, randomsite.com will then be able to access the Facebook API using the secret token to get information about the user, such as name and email address:
The problem with this is that a passive attacker monitoring the traffic can simply take the token from the URL. So, a more secure approach is to return a one-time code instead, which the requesting website can then exchange into a token using the Facebook API, but this process also involves an application secret value that only the requesting website knows. An attacker intercepting the code can't do anything. This is the approach Booking.com was using, making the process more secure and harder to attack.
The initial redirect from Booking.com to Facebook follows this pattern:
Facebook redirects the user's browser to:
Booking.com then takes the code and makes a separate direct request to Facebook's API to exchange it with a token, including its own app-secret that's registered with Facebook in the request.
OAuth mistake 1: Insufficient path validation
The first issue that the Salt Security researchers found was that when Booking.com registered with Facebook as a client for OAuth, it provided Facebook with a predefined origin for requests coming from Booking.com, but only the subdomain, not the entire path. This means that if Facebook.com receives an OAuth request from Booking.com with a redirect_uri defined as:
The only part it will actually validate before processing the request is https://account.booking.com.
So, it is possible for an attacker to trick a Booking.com user to click on the following link:
Facebook would then redirect the victim to:
This is not too bad, since the path the attacker can control is still under the account.booking.com subdomain and they don't have access to read the response from it. Or do they?
OAuth mistake 2: Open redirect vulnerability
The researchers dug around on the Booking.com user profile page under account.booking.com, to find any feature or link that would redirect the user to a different link. They found that Booking.com also used OAuth internally, with it acting as an identity and API provider for its internal website features.
For example, the researchers found that clicking on "add a display name" in the user dashboard will redirect the user's browser to an internal Booking OAuth endpoint with a callback URL defined as:
That state is just base64 encoding for a JSON that includes a property called "mysettings_path":"mysettings/personal". So, when the OAuth request is processed, Booking.com redirects the user's browser to the aforementioned link which then performs yet another redirect to https://account.booking.com/mysettings/personal.
What happens here is that the final path is passed as base64 JSON into the OAuth redirect_uri, but knowing this an attacker can modify it and change mysettings_path to https://www.attacker.com/index.php and then encode it base64 and pass it part of the URL. This is known as an open redirection vulnerability. In other words, a link on a website the user clicks on or their browser otherwise processes can redirect the user to an attacker-controlled website.
Combining the two issues, an attacker can now craft the following link to send to a user:
Facebook will then redirect the user's browser to the redirect_uri, which then makes an internal OAuth request inside Booking.com itself, resulting in another redirect to an URI constructed from the base64 encoded JSON, which in fact is now an attacker-controlled website.
One more step required is to change the response_type=code to response_type=code, token, which is a supported feature in OAuth. That forces the redirect URL generated by Facebook to include the code in the URL using a hash (#) fragment rather than a query type parameter (?=) in the URL. This is important because query parameters are not passed along through the redirects to reach attacker.com, but hash fragments are.
Finally the attacker can get the victim's Facebook-generated OAuth code by simply tricking them to click on a link. So, the next action would be to initiate a new login with Facebook session on Booking.com and replace the code in the redirect URL Facebook sends to their browser with the victim's code and then pass it to Booking.com so that Booking authenticates them as the victim instead.
However, this fails because Booking.com needs to exchange the received code with a token using the Facebook API as previously mentioned. This is done directly between Booking.com and Facebook without involving the user's, or in this case the attacker's, browser. Part of this Booking to Facebook API exchange, Booking sends Facebook a redirect_uri again and it's the one it normally sends as part of the OAuth implementation: https://account.booking.com/social/result/facebook.
The attacker no longer has control over this process and Facebook's API spots the discrepancy: First it received a request for a code with one redirect_uri (the one the attacker crafted), but then when Booking tries to exchange the code for a token, it sends a different redirect_uri. Since they don't match, Facebook refuses to process it.
OAuth mistake 3: Mobile implementation bypasses security
It turns out that when creating their mobile application and implementing the login with Facebook option, Booking,com decided to take the code returned by Facebook to the mobile application, then pass it to the Booking.com website, which would perform the code to token exchange and then pass the token back to the mobile application.
In this process when the mobile application sends the code received from Facebook to Booking.com, it includes a property called resultUri in the JSON request.
This is the redirect_uri that the mobile application originally sent to Facebook to obtain the code, and it sends it to Booking.com for the site to make sure it uses the same one when trying to exchange the code for a token.
In other words, Booking.com takes the resultUri passed to it by the mobile application along with the code, and uses it as the redirect_uri in its new interaction with Facebook, therefore passing Facebook's security check. The problem is. An attacker can impersonate the mobile application and send their own resultUri, therefore tying the attack all together.
The attack flow would be like this:
- The attacker crafts a link to send to a victim, with an OAuth request from Booking.com to Facebook for the victim's account, passing it through the open redirect vulnerability so the attacker can obtain the resulting code generated by Facebook for the victim.
- The attacker opens the mobile application and attempts to authenticate with Facebook using their own account, but after receiving a code for their own account, it intercepts and halts the following requests sent by the application to Booking.com.
- It modified the requests by replacing their code with the victim's code and passing the crafted redirect URL from step 1 as the resultUri.
- com will take the information and contact the Facebook Graph API and successfully exchange the code into a token and pass it back to the attacker's mobile application. The attacker can now access the victim's account instead of their own.
"The vulnerability is in the integration between Facebook and Booking.com, however, it’s possible to sign in to a Booking.com account using Facebook even if that account was created using Google or another sign-in method," the Salt Security researchers said.
That's because Booking.com grants access to the account whose email address in its system matches the one it received a valid token for from Facebook.
Since the victim has a Facebook account on the same email address and doesn't become suspicious when they click on a Booking.com link that takes them to Facebook to authenticate, the exploit will give an attacker access to their account even if that account was manually created on Booking.com or the user normally uses Google.com to authenticate on Booking.
The only information that needs to match is the email address and it's common for users to use the same email address for all accounts they own.
Furthermore, Booking.com also runs another travel search engine called Kayak.com that it acquired in 2013, and Kayak allows users to authenticate with their Booking.com account. An attacker gaining access to a person's Booking account can also access their account on Kayak.
"Most of the focus is on the first security gap, which allows the attacker to choose another path for the redirect_uri," the Salt Security researchers said. "When you do an integration with Facebook or another vendor, it’s extremely important to provide hard-coded paths for the redirect_uri in the Facebook configuration. As you saw in the document, only origin is not enough."
Furthermore, as the third issue with the mobile application showed, the redirect_uri parameter used in API interactions should never be taken from user input or be controllable by the user via the application.
"Security vulnerabilities can happen in any website, and the response is what matters," the researchers said. "We reported everything to Booking.com, and the team was able to fix these security gaps very quickly. We were happy with Booking.com's commitment to security and the company’s willingness to take swift action to protect the personal information of its users."