Week 60 - Modern CSRF Attacks
To pull off a CSRF today, you need to make sure the app is using cookies to authenticate users. This is because JWT’s are not vulnerable to CSRF since they are not automatically added to cross-origin requests like cookies are. So, to make CSRF work you must find one of the below occurrences:
1) Find an application that does a state-change within a GET request
Common state-changes I look for are password resets, account invites, or user role changes. Even if the parameters are passed within POST data, it’s worth trying them as GET parameters and seeing if the app accepts them. If it does, you can often turn this into a CSRF because most session cookies are set with SameSite=Lax (default in both Chrome and FireFox), meaning cookies are automatically passed within cross-origin GET requests but not POST. CORS also should not be an issue here because our request does not qualify as ‘complex’, which means that in this case, CORS DOES NOT BLOCK THE REQUEST - IT BLOCKS THE RESPONSE. For CORS to qualify a request as ‘complex’ it must meet one of the below requirements:
A request that uses methods other than GET, POST, or HEAD
A request that includes headers other than Accept, Accept-Language or Content-Language
A request that has a Content-Type header value other than application/x-www-form-urlencoded, multipart/form-data, or text/plain
If just one of the above cases is met, CORS will block the request from going through. Note: if the application uses a CSRF token on the GET request, you could be screwed unless you can find a CORS misconfiguration and retrieve the token. See number 2 for more details on that. You also need to make sure SameSite is not set to ‘Strict’, which means no cookies are attached in cross-site GET requests.
2) Find an application with a CORS misconfiguration and a session cookie explicitly set with SameSite=None
This is more of a rare find but would allow you to send a cross-origin request with POST data to the application via JavaScript. By ‘CORS misconfiguration’ I am referring to the attacker’s ability to control the ‘Access-Control-Allow-Origin’ response header and bypass CORS restrictions (for the sake of the example, I am also assuming ‘Access-Control-Allow-Credentials’ is set to ‘true’ as well), allowing them to read the server response. You might be thinking, why not just set the ‘Origin’ request header through JavaScript? This will not work because browsers do not allow you to set the ‘Origin’ header, you will get a forbidden error if you try.
The SameSite flag being set to None would allow cookies to be automatically attached to cross-origin POST requests. If the SameSite flag is not included when setting the cookie, FireFox and Chrome will automatically make it ‘SameSite=Lax’ which is why it must be explicitly set to ‘SameSite=None’ for this to work.
3) Find a Cross-Site Scripting vulnerability (my personal favorite)
This is the most common and cleanest way to pull off a modern-day CSRF. Since XSS allows you to execute JavaScript within the same origin of the site, you should have no CORS issues and no problem having cookies auto-attach to requests, regardless of the SameSite status. Even if the site is using a CSRF token, you could grab that from the page and include it within the state-changing request. This is one of the reasons why XSS is so dangerous, but unfortunately often overlooked.
Last updated