Jump to content
Nytro

“Client-Side” CSRF

Recommended Posts

Posted
“Client-Side” CSRF
At Facebook, the Whitehat program receives hundreds of submissions a month, covering a wide range of vulnerability types. One of the interesting classes of issue which we've seen recently is what we've termed “Client-Side” Cross-Site Request Forgery (CSRF), which we've awarded on average $7.5k.

What is CSRF?

Before we jump into technical details, let's recap on what CSRF is. This is a class of issue in which an attacker can perform a state changing action, such as posting a status, on behalf of another user. This is made possible due to the fact that browsers (currently, until Same-Site Cookies are supported in all major browsers) send the user's cookies with a request, regardless of the request origin.
At Facebook, like other large sites, we have protections in place to mitigate this kind of attack. The most common type of protection is by adding a random token to each state-changing request, and verifying this server-side. An attacker has no way of knowing this value in advance, which means we can ensure any request has explicitly been made by the user. If you're participating in our Whitehat program, then you might see this token being sent - we name it “fb_dtsg”.

“Client-Side” CSRF

Whilst most researchers think of CSRF as a server-side problem, “Client-Side” CSRF exists in the user's browser or mobile device - a malicious user could perform arbitrary requests to a CSRF-protected end-point, by modifying the end-point to which the client-side code makes an HTTP request to with a valid CSRF token. This could be a form submission, or an XHR call.
For example, a product might want to log some analytic data after the page is loaded, which could look the following code:
let analytic_uri = window.location.hash.substr(1); (new AsyncRequest(“/ajax” + analytic_uri)) .method(POST) .setBody({csrf_token: csrf_token}) .send()
The user would browse to /profile.php#/profile/log. On page load, the JS would make a POST request to “/ajax/profile/log”, and the data saved. However, if an attacker modifies the fragment to “#/updatestatus?status=Hello”, then the JS is instead making a request to update the user's status, with a valid CSRF token.
One good trick for hunting for these kind of issues is looking for HTTP requests which are made after the page is rendered - if the end-point being requested is contained in the page's query string or fragment, then it's worth investigating! If you can only control part of the end-point, then it could still be vulnerable, by using tricks like path traversal.

Making arbitrary GraphQL requests

We had a great submission from one of our top researchers, Philippe Harewood, which used this style of issue to make arbitrary GraphQL on behalf of another user, for which we rewarded him $7,500.
On https://business.instagram.com, we had a page which took a business ID from the request, and made a Graph API request to that particular business:
POST /[business_id]?fields=... access_token=...
Facebook's Graph API is protected against CSRF by requiring a valid access token from the user. Without this token, the request is un-authenticated.
Philippe found that since the business ID wasn't validated to be an integer, he could change this to point to our GraphQL end-point (graphql), and make authenticated requests for the user (such as posting a new status), since the JS was making the request with the access token:
POST /graphql?q=Mutation...&fields=... access_token=...
This is a great example of influencing authenticated requests to point somewhere completely unintended.

Conclusion

These issues are an interesting and novel take on an older class of bugs, which has prompted us to take a look at ways of detecting and mitigating bugs in JS. If you too enjoy investigating and solving novel bugs, then come join the ProdSec team!

 

Sursa: https://www.facebook.com/notes/facebook-bug-bounty/client-side-csrf/2056804174333798/

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...