top of page

Exploiting CSRF: Bypassing SameSite Strict with Client-Side Redirects

BlueDolphin

Updated: Feb 2

YouTube Walkthrough


 

Summary

In this blog, we will explore a unique and intermediate approach to CSRF attacks, leveraging the labs provided by Port Swigger.


Lab Overview: Same Site Strict bypass via client-side redirect


Why is this important

Implementing a defensive meausre such as the SameSite header within a web application is common practice and widely implemented. This exploit aims to leverage a insecure client side script, to bypass the SameSite Strict security measure.


Key Takeaways

A key takeaway for the audience is to be comfortable enough with CSRF attacks to take it one step further in attempting to bypass CSRF security SameSite header.


  1. CSRF attack surface validation

    1. Checking for the 3 prerequisites

  2. Converting parameter submissions

    1. Transforming a POST to a GET

  3. SameSite Strict header limitations

    1. Limits to verifying SameSite request source

  4. Payload generation

    1. Working through multiple steps to construct the proper payload


Steps to reproduce


  1. Understanding the application

    1. Login function

    2. Change email function

    3. Blog functionality

    4. CSRF - checklist

  2. Crafting the payload

    1. Modifying the request

    2. Redirect payload creation

    3. Path traversal and encoding

    4. Wrap & serve


  3. Lessons learned

    1. The importance of testing for GET/POST interchangeability.

    2. The role of client-side scripts in bypassing SameSite restrictions.

    3. The risks of insufficient input validation.

  4. External resources

    1. See bottom of blog


 

Understanding the Application


Login function

Our initial landing page welcomes us to a blog and offers limited functionality.


Log into the application via the provided credentials, and review the HTTP login request/response. In this instance we can see that a session cookie is set upon successfully logging in. We can also see that the SameSite configuration is set to Strict, which means our entire session will adhere to the SameSite header.


Change Email Function


Once we have logged in, we are provided with the change email function. This is important because it acts as a relevant action that the user can control. For example, a function to change the color or theme of our account page is not a relevant user action.

After changing our email we have a look at the network request and response. We can see that the request takes our session cookie and submits this with our account id.


When exploring an API endpoint's functionality, it is a best practice to test whether valid POST requests can also be converted to GET requests. If the server accepts GET requests, it allows parameters to be passed directly in the URL query string. This flexibility can expose vulnerabilities, as attackers are no longer limited to POST body submissions.

In this case, changing the request to a GET request resulted in a successful server response, demonstrating that the endpoint supports both methods. This behavior significantly expands the potential attack surface, making the endpoint more susceptible to exploitation.


Blog Functionality


Having reviewed the change email functionality, it is time to pivot to the blog potion of the application.


We make a comment on the blog to learn how the application handles this input. Initially we are redirected after making our post. Given the name of this lab, we know that the redirect is how we will bypass the SameSite header.


Reviewing the HTTP history chain, reveals what happens after we comment on the blog. This is where we discover the client side redirect. This client side redirect will be later leveraged to bypass SameSite security headers. We can see the breakdown of requests below.

Request flow:

  1. Comment posted

  2. Comment confirmation function.

  3. Confirmation function calls ConfirmationRedirect.js

  4. ConfirmationRedirect.js executes and user is redirected.



Reviewing the redirect source reveals that the redirect confirmation script actually takes the users current window.location object and concatenates this with the post ID of your comment. This open the door to possibly controlling the input passed in the URL query path and this is where things get exciting!


Below you can view the redirect script that is running on confirmation.


If you are unfamiliar, you can type window.location in your console to the functions results client side!


CSRF - Checklist

There are 3 criteria that must be met in order to validate a CSRF attack surface. While not mandatory, it is a great rule of thumb. We observed a relevant user action in the change email function. We observed that requests are tied to user sessions submitting the cookie every client side request. Finally, we observed no security tokens such as CSRF protection measures.


  1. Relevant user input ✅

    1. Change email function

  2. Cookie based session handling ✅

    1. Observed in the login server response

  3. No unpredictable tokens ✅

    1. No security tokens observed ✅


 


Crafting our payload

For this final phase we try to craft a successful payload after validating the attack surface for a CSRF attack, and identifying a bypass to the SameSite security header. Make sure to leverage the "View exploit" option on the exploit generator in the lab/.


  1. Modifying the request Initially, the change email function is a POST request. However, if the endpoint also accepts GET requests, we can pass the submission via a URL leveraging a client-side redirect. Attempting to use a malicious POST form hosted on our exploit server, similar to previous labs, would trigger the SameSite header protections, blocking the submission from an external source.

    1. To reproduce this behavior, use Burp Suite to intercept the change email request. Then, right-click on the request and select "Change Request Method". This action converts the POST request into a GET request, moving the body parameters into the URL as query string parameters for the API endpoint.

      /my-account/change-email?email=bananas%40gmail.com&submit=1

  2. Redirect payload creation

    1. Our next step is to develop our payload by appending the change email function with the redirect script. The goal is to force a client side request with user supplied input passed through the URL query string. This was observed in the redirect script after we commented on a blog. This effectively bypasses the "SameSite Strict" header. However our resource was not found. So this implies our user input was successfully passed.

      /post/comment/confirmation?postId=/my-account/change-email?email=bananas%40gmail.com&submit=1

      Here we can see that the resource was not found!


  3. Path Traversal & Encoding

    1. This step deals with handling the transformation of the payload. We have effectively changed the data format by transforming our POST request with parameters passed in the body, into a URL query string using the same parameters passed in the URL. However, special parameters passed in the URL require encoding for proper handling. The @ and & are URL encoded.

      We still have an issue with finding our endpoint however. Previously we received a "Not Found" error. We can attempt a path traversal technique to break out of the child directory as we attempt to find the path to the Change Account API endpoint. /post/comment/confirmation?postId=../../my-account/change-email?email=bananas%40gmail.com%26submit=1


      We can see that the resource was actually found this time prompting us to dive further.


  4. Wrap & serve payload

    1. The goal here is to create a client-side script hosted on your exploit server that redirects the victim's browser to a crafted URL. This URL exploits the application's functionality by combining the client-side redirect script with your malicious query string to perform the CSRF attack.


      When the victim visits the malicious link, we want their browser to automatically execute the script. The window.location property in JavaScript is used to navigate the browser to the specified URL, which contains your payload. This triggers the vulnerable endpoint, making the change (e.g., updating the email) while using the victim's session. <script>

         window.location = "https://0a8a0008031cf6a4811552a0003f0087.web-security-academy.net/post/comment/confirmation?postId=10/../../my-account/change-email?email=zzz%40boom.com%26submit=1";

      </script> This worked - Congratulations!




 

Lessons learned


  1. Testing GET/POST Interchangeability: Always test if API endpoints accept both GET and POST requests. This behavior can widen the attack surface and expose vulnerabilities.

  2. Client-Side Scripts and SameSite Restrictions: Client-side scripts like window.location can bypass SameSite cookie policies when combined with crafted payloads, enabling CSRF attacks.

  3. Risks of Insufficient Input Validation: Poor input validation allows attackers to manipulate query strings, redirects, or API endpoints, facilitating unauthorized actions.



 

External resources


 
 
 

Comments


bottom of page