Exploiting time-sensitive vulnerabilities
Table of Contents
Welcome to my another writeup! In this Portswigger Labs lab, you’ll learn: Exploiting time-sensitive vulnerabilities! Without further ado, let’s dive in.
- Overall difficulty for me (From 1-10 stars): ★★☆☆☆☆☆☆☆☆
This lab contains a password reset mechanism. Although it doesn’t contain a race condition, you can exploit the mechanism’s broken cryptography by sending carefully timed requests.
To solve the lab:
- Identify the vulnerability in the way the website generates password reset tokens.
- Obtain a valid password reset token for the user
- Log in as
- Access the admin panel and delete the user
You can log into your account with the following credentials:
Solving this lab requires Burp Suite 2023.9 or higher.
In this web application, we can read different blog posts.
What’s that “Forgot password?” link?
We can reset a user’s password!
wiener first and see what will happen:
Burp Suite HTTP history:
When we clicked the “Submit” button, it’ll send a POST request to
We can go to the reset password endpoint to enter our new password!
Reset password endpoint
Let’s go there!
In here, we can type our new password and change the old one.
Sometimes you may not find race conditions, but the techniques for delivering requests with precise timing can still reveal the presence of other vulnerabilities.
One such example is when high-resolution timestamps are used instead of cryptographically secure random strings to generate security tokens.
Consider a password reset token that is only randomized using a timestamp. In this case, it might be possible to trigger two password resets for two different users, which both use the same token. All you need to do is time the requests so that they generate the same timestamp.
Hmm… I wonder what’s that password reset token.
It looks like a hashed string, we can try to identify the hash algorithm via
┌[siunam♥Mercury]-(~/ctf/Portswigger-Labs)-[2023.09.25|14:15:54(HKT)] └> hashid '38b7357daa3f78c8f607dd539a06a2a1ecdc96df' Analyzing '38b7357daa3f78c8f607dd539a06a2a1ecdc96df' [+] SHA-1 [+] Double SHA-1 [+] RIPEMD-160 [+] Haval-160 [+] Tiger-160 [+] HAS-160 [+] LinkedIn [+] Skein-256(160) [+] Skein-512(160)
Oh! It’s SHA-1 hash!
I’m also curious about what’s the original string before hashed?
Maybe it’s based on timestamp?
To test that, we can send the generate token request (
POST /forgot-password) in parallel.
First, let’s try send that request in separate connections:
As you can see, the tokens are different.
How about send in parallel?
They’re still different?
Then, I noticed that there’s a delay between the requests:
That being said, our requests are being processed in sequence rather than concurrently.
Also, in our session cookie name
phpsessionid, it’s suggested that the backend is using PHP.
Session-based locking mechanisms:
Some frameworks attempt to prevent accidental data corruption by using some form of request locking. For example, PHP’s native session handler module only processes one request per session at a time.
It’s extremely important to spot this kind of behavior as it can otherwise mask trivially exploitable vulnerabilities. If you notice that all of your requests are being processed sequentially, try sending each of them using a different session token.
To solve our requests are being processed one request per session at a time, we can use a different session token:
Note: Remember to retrieve the CSRF token.
Then, in our Burp Suite’s Repeater tab, replace the original session token cookie and CSRF token to a request tab:
Next, send those requests in parallel and check the password reset token in our email client:
Nice!! We got the same password reset token!!
Note: Sometimes it may fails, you could send those requests a couple more times.
Armed with above information, it’s clear that the password reset token is generated via timestamp and SHA-1 hashed.
To perform account takeover on user
carlos, we can simply change the
username POST parameter to
carlos in one of our Repeater’s requests:
Then, send those requests and get the password reset token, which should be the same as the
Finally, send a POST request to
/forgot-password?user=carlos&token=<token_here> with POST parameter
new-password-2 to reset
Now, we should be able to login as user
Nice! Let’s go to the admin panel and delete user
What we’ve learned:
- Exploiting time-sensitive vulnerabilities