SameSite Strict bypass via client-side redirect

Description

This lab’s change email function is vulnerable to CSRF.

Reproduction and proof of concept

Study the change email function

  1. In Burp’s browser, log in to the wiener account and change its email address.

  2. In Burp, go to the Proxy -> HTTP history tab.

  3. Study the POST /my-account/change-email request and notice that this doesn’t contain any unpredictable tokens. It may be vulnerable to CSRF if you can bypass any SameSite cookie restrictions.

  4. Look at the response to the POST /login request. The website explicitly specifies SameSite=Strict when setting session cookies. This prevents the browser from including these cookies in cross-site requests.

Identify a suitable gadget

  1. In the browser, go to one of the blog posts and post an arbitrary comment. Observe that you are initially sent to a confirmation page at /post/comment/confirmation?postId=x but, after a few seconds, you are taken back to the blog post.

  2. In Burp, go to the proxy history and notice that this redirect is handled client-side using the imported JavaScript file /resources/js/commentConfirmationRedirect.js.

  3. Study the JavaScript and notice that this uses the postId query parameter to dynamically construct the path for the client-side redirect.

  4. In the proxy history, right-click on the GET /post/comment/confirmation?postId=x request and select Copy URL.

  5. In the browser, visit this URL, but change the postId parameter to an arbitrary string.

/post/comment/confirmation?postId=foo
  1. Observe that you initially see the post confirmation page before the client-side JavaScript attempts to redirect you to a path containing the injected string /post/foo.

  2. Try injecting a path traversal sequence so that the dynamically constructed redirect URL will point to your account page:

/post/comment/confirmation?postId=1/../../my-account
  1. Observe that the browser normalises this URL and successfully takes you to the MyAccount page. This confirms that the postId parameter can be used to elicit a GET request for an arbitrary endpoint on the target site.

Bypass the SameSite restrictions

  1. In the browser, go to the exploit server and create a script that induces the viewer’s browser to send the GET request you just tested:

<script>
    document.location = "https://0add007d0376cc05c083db48006a005c.web-security-academy.net/post/comment/confirmation?postId=../my-account";
</script>
  1. Store and view exploit.

  2. Observe that when the client-side redirect takes place, you still end up on your logged-in account page. This confirms that the browser included your authenticated session cookie in the second request, even though the initial comment-submission request was initiated from an arbitrary external site.

Craft an exploit

  1. Send the POST /my-account/change-email request to Burp Repeater.

  2. In Burp Repeater, right-click on the request and select Change request method. Burp automatically generates an equivalent GET request.

  3. Send the request. Observe that the endpoint allows you to change your email address using a GET request.

  4. Go back to the exploit server and change the postId parameter in your exploit so that the redirect causes the browser to send the equivalent GET request for changing your email address:

<script>
    document.location = "https://0add007d0376cc05c083db48006a005c.web-security-academy.net/post/comment/confirmation?postId=1/../../my-account/change-email?email=gotcha%40web-security-academy.net%26submit=1";
</script>

Note: include the submit parameter and URL encode the ampersand delimiter to avoid breaking out of the postId parameter in the initial setup request.

CSRF

  1. Test the exploit and confirm that it has successfully changed the email address.

  2. Deliver the exploit to the victim. After a few seconds, the lab is solved.

Exploitability

An attacker needs to have an account.