Most applications provide users with the ability to reset their passwords via email. This functionality has always been of interest to attackers as there are a number of potential attack vectors such as: abusing weak/missing rate limiting, host header injection, using forged reset tokens and more.

In this article I describe one of my recent findings about a Password Reset implementation that used weak password reset tokens in the reset links that were sent via email.

The application I was working on was a part of a private bug bounty program, we’ll call it www.weaksite.com in this article.

After neglecting the application for a few weeks and I forgotten the credentials for my test accounts (I usually do). I went ahead and did a Forgot Password request for my two test accounts:

  • harshbothra+1@bugcrowdninja.com
  • harshbothra+2@bugcrowdninja.com

Most password reset mechanisms follow this process:

Request Forgot PasswordReceive Unique Reset LinkFollow Unique LinkSet New Password

While resetting the password using the Reset Link, I observed that the tokens used in the reset links were very similar:

  1. https://weaksite.com/reset_password?token=zbp.nwavaqjbeptho%401+neugboufenu
  2. https://weaksite.com/reset_password?token=zbp.nwavaqjbeptho%402+neugboufenu

The second thing I observed was that the length of the reset token was equal to the number of characters of my email addresses; also %40 is the ASCII representation for @ in hex.

Based on this, I was sure that the application had a weak token generation mechanism, but I still had to figure out exactly how the application was encoding the token. After spending a few more minutes, I derived the algorithm on how the token was being generated.

Caesar_Cipher_Key13(Reverse(email)) == Password Reset Token

  1. Take the victim’s email, ex: hbothra22@gmail.com
  2. Reverse the characters of the email, i.e.: moc.liamg@22arhtobh
  3. Encrypt reversed email with a Caesar Cipher using a shift of 13, i.e.: zbp.yvnzt@22neugbou
  4. Change @ to %40 and we have our reset token

Final Example Token = zbp.yvnzt%4022neugbou

As per Wikipedia, the action of a Caesar cipher is to replace each plaintext letter with a different one a fixed number of places down the alphabet. ROT13 is a common implementation of Caeser cipher where the shift is done by 13 places.

Read more about the Caeser ciphers here and ROT13 here.

Now using this algorithm we can generate reset tokens and therefore Password Reset Links for any users with known email addresses. To top it all, the application was also vulnerable to email enumeration via the Forget Password feature and we could use that to identify valid user accounts and reset them.

Takeaways

  1. Password Reset Tokens, considering their sensitivity, they need to be handled in a secure way. The algorithm used to generate a password reset token should not be reversible without a server side lookup table.
  2. It is essential to make sure that no publicly breakable algorithms such as Caesar cipher or Base64 are used to generate a password reset token.
  3. Additionally, salts and combination of multiple complex algorithms can be used to generate a randomized password reset token which is not reversible or guessable.
  4. Make sure that the password reset token is valid for a specific period.
  5. Make sure that there is a limit to request password reset token which can be implemented via enabling rate limits or adding a CAPTCHA.