CSRF where token is not tied to user session

3 min read Easy PortSwigger
CSRF
Contents

On this page

The lab

here is how portswigger describes it

This lab's email change functionality is vulnerable to CSRF. It uses tokens to try to prevent CSRF attacks, but they aren't integrated into the site's session handling system.

To solve the lab, use your exploit server to host an HTML page that uses a CSRF attack to change the viewer's email address.

You have two accounts on the application that you can use to help design your attack. The credentials are as follows:

  • wiener:peter
  • carlos:montoya

the last few labs had tokens that were missing or skippable, but here the token is real and gets checked every time

Why a Token that is not tied to the session is dangerous?#

the entire security of a csrf token rests on one thing, the attacker cannot get hold of a token that will pass for the victim. that is what stops the forgery, we can build the whole malicious form but we can never fill in the right token, because it is a secret that lives in the victim's session.

binding the token to the session is what makes that true. when a token is tied to a session, the server does two checks, is this a token i issued and does it belong to the session making the request. if the second check is missing, the token is no longer a per user secret, it is just any token the application has ever issued. and there is one token an attacker can always get legitimately, their own. so on a site like this we log into our own account take the perfectly valid token the server gives us, and drop it into the attack and because the server never checks whose session it came from, it accepts our token on the victim's request just the same

Step 1 - Capture the request from both accounts#

we are handed two accounts so the plan is to look at both. to keep two sessions alive at once i used a normal window for wiener and an incognito window for carlos, logged into each, submitted an email change and sent both requests to burp repeater.

1111
2222

the two tokens are different so the token is not just a fixed string the server really is generating a fresh one per user. that is exactly the case where session binding matters so it is worth testing whether that binding is actually there

Step 2 - Use one user's Token on the other user's request#

here is the test that proves the flaw in wiener's change email request i replaced wiener's token with carlos's token and sent it.

3333

it is accepted and the email changes. that is the whole vulnerability in one request a token minted for carlos works just fine on wiener's account, which means the token is validated as genuine but never checked against the session using it so any valid token the application hands out will do including one we generate ourselves.

Step 3 - Build the poc with our own token and deliver it#

now the attack writes itself. we log into our own account, copy a fresh valid csrf token and hardcode it into the poc then host it on the exploit server

HTML
<html>
  <body>
    <form action="https://your-lab-id.web-security-academy.net/my-account/change-email" method="POST">
      <input type="hidden" name="email" value="[email protected]" />
      <input type="hidden" name="csrf" value="MtiRqHJV2n22JT8h11o5ltIlUxKzlqyA" />
      <input type="submit" value="Submit request" />
    </form>
    <script>
    history.pushState('', '', '/')
    document.forms[0].submit()
    </script>
  </body>
</html>

the form carries both the new email and a csrf value that is a real token from our own session. when the victim loads the page it auto submits, their browser attaches their session cookie, and the server sees a genuine token it once issued and a valid session cookie, and since it never checks that the two belong together it accepts the change.

4444

with this, the lab is solved!