Facebook account takeover due to unsafe redirects after the OAuth flow
Description
This bug could allow a malicious user to takeover the Facebook account after stealing a first-party access_token issued to apps.crowdtangle.com. The OAuth callback endpoint of apps.crowdtangle.com Facebook application would redirect the access_token to another endpoint in case the user is already logged-in. The other endpoint could be set by the attacker which means if we can find an open redirect in apps.crowdtangle.com, it could redirect the token in the fragment part of the URL to another website and use it to takeover the account. This attack won't require user interaction.
Details
- Stealing the Facebook limited access_token of a user
- If a not logged-in user visits any page in apps.crowdtangle.com that requires a logged-in user, a cookie would be set to the visited page ( cookie redirect_url=https%3A%2F%2Fapps.crowdtangle.com%2FENDPOINT) . Then a redirection will be made to https://apps.crowdtangle.com/auth?type=0 . After the user log-in, any request to https://apps.crowdtangle.com/facebook/auth endpoint would result to a 302 redirect to the URL inside the cookie redirect_url. Here the selected endpoint in the redirect_url cookie should be replaced with the open redirect endpoint.
- The Facebook application for apps.crowdtangle.com has the id 527443567316408, its correct callback endpoint is https://apps.crowdtangle.com/facebook/auth. To authenticate a user can visit https://apps.crowdtangle.com/auth/server endpoint, he/she would be redirected to https://apps.crowdtangle.com/facebook/auth , then redirected to https://www.facebook.com/v2.9/dialog/oauth?client_id=527443567316408&redirect_uri=https://apps.crowdtangle.com/facebook/auth&response_type=code&state=VALID_STATE . A valid callback would result in a POST message sent to apps.crowdtangle.com/users/login and the user would be logged-in.
From now on, any request to apps.crowdtangle.com/facebook/auth would redirect to https://apps.crowdtangle.com/ENDPOINT. - Since the callback endpoint would redirect to any url specified in step 1 by the attacker ( in our case https://apps.crowdtangle.com/ENDPOINT) , we would re-request https://www.facebook.com/v2.9/dialog/oauth?client_id=527443567316408&redirect_uri=https://apps.crowdtangle.com/facebook/auth&response_type=token , this time a token was requested and this would be returned in the fragment part of the url and not a code attached as a parameter (/facebook/auth#access_token=). Since now the user is logged-in after step 2, the endpoint /facebook/auth would redirect to /ENDPOINT, the browser would pass the hash part to the next url. The endpoint apps.crowdtangle.com/ENDPOINT would redirect to the attacker website with the URL fragment part containing the token.
- The apps.crowdtangle.com/ENDPOINT would be replaced in the attack with the open redirect endpoint. This would be apps.crowdtangle.com/CUSTOM_PAGE/e/x/x/HASH/ . CUSTOM_PAGE would be attacker or public board and we would manipulate the HASH part which is an encoded string that represent the next URL.
All previous steps would result to the ability to steal a Facebook user access_token generated under the Crowdtangle Facebook application permissions. Below is the attack script applying all previous steps in order and would lead to the access_token being received in the attacker website.
The Facebook user access_token received is first-party ( generated by a Facebook owned application ) which could be used to access https://graph.facebook.com/graphql endpoint. However, access_tokens generated for this particular application ( Crowdtangle ) had some limitations while doing graphql queries/mutations. The access_token would not allow us to do mutations which would turn it useless if we want to takeover the account since we won't be able to add a new phone number or email. Also queries were limited and i wasn't able to collect serious information about the user.
- Upgrading the access_token to another first-party application and then Account takeover
Facebook allows device logins. This is a feature for applications created in devices like TVs to enable to login to Facebook without email and password but instead a temporary code. The authentication mechanism would work as follow:
First the application requesting device login would request a temporary code from Facebook, this would return a code to be shown to the Facebook user and another code ( we'll note it retrieve_code ) to get the access_token of the user in case he/she accepted to use the application. Then, it should display the code to the user who would need to enter it in www.facebook.com/device or inside his/her mobile device. After entering the code, the user would be promoted to accept or deny to use the application. If he/she accepted to use it, this would result to the application requesting another API endpoint with the retrieve_code and which would result to the user access_token being returned.
Since many Facebook applications also use this login method in devices like TVs and Watches, we can reverse engineer the applications, get their client_code they use to request the temporary code to be shown to the user. After being shown to the user, we can get the access_token which would be a first party access_token.
Now how this would be linked to the previous attack? Since the previous method would require an excessive user interaction ( entering the user code , accepting to use the application , CSRF protections ... ) before we can get the user access_token , it's normally categorized to be safe by Facebook and can't be leveraged by attackers ( unless a CSRF bypass is found for example like my good friend JOSIP did before ).
What we can do here is to use the previous limited access_token gathered to make some Graphql Queries that would return us the CSRF token used in the Authentication flow. Since the CSRF token is not linked to the user browsing session, we can inject it in a malicious URL that would request Facebook OAuth endpoint and would lead directly to us getting a new access_token with much higher permissions.
From the previous attack , the victim would be redirected with an access_token to the attacker website. The attacker website would receive the access_token and do the following steps: