Pentest Files: Smashing the password reset function for fun and profit

BY Conor O'Neil / ON Aug 19, 2022

Welcome to our Pentest Files blog series.

Each blog post will present an interesting or dangerous finding one of our testers has identified in an actual recent pen-test, so you can see the kinds of cool things our pen-testers get up to, and also to help you take steps to prevent similar vulnerabilities in your own assets.

These findings are taken from real reports, anonymised, and published with kind permission from our clients.

Tester: Tristan Fletcher

Target: Web Application

Vertical: Transport Tech

Impact: Arbitrary account takeover, access to all accounts on the application

What Happened?

Tristan found a bug in the password reset functionality of the target application, which allowed him to access the account of any user of the application, including the admin and super admin accounts, essentially giving him full control of the application!

Some Background

This was an email poisoning attack, where Tristan was able to control the content and parameters of the email sent as a result of the password reset function being used. However, this attack comes with a clever twist…

The Finding

Tristan is somewhat of a specialist at finding bugs in password reset functions of our customer web applications (keep an eye out for an upcoming blog post where Tristan will describe multiple techniques for doing so).

This particular instance was a simple yet elegant attack, which is actually a reasonably common find in modern web applications, and involved poisoning the password reset emails which the application sent.

By modifying a parameter within the “Forgot Password” functionality it was possible to modify the password reset link emailed to legitimate application users.

Tristan performed this by modifying the value of the emailAddress and resetPasswordUrl parameters.

By modifying the emailAddress parameter an attacker could take over the account of an arbitrary user of the application. Please note that this would require prior knowledge of the email address of a valid application user. However another issue identified by Tristan in the same test allowed easy enumeration of all valid email addresses for the application (combining vulnerabilities in this way is known as exploit chaining).

The resetPasswordUrl was also modifiable. By default this parameter would reference a link to the legitimate password reset link on the legitimate application domain. However, Tristan found that it was possible to instead modify this link to point to an attacker controlled domain.

When the user received this email, it would reference the attacker controlled domain. The path reference would include the token parameter. This meant that were a user to click this link that they would attempt to load a URL which contained the token from the attacker-controlled domain.

An attacker could then use this token to reset the password to one of their choosing.

The eagle-eyed among you are probably thinking “well that’s great and all, but wouldn’t someone have to actually click the link for this to work”…

The REALLY clever bit…

Yes. Typically, with an attack like this which involves emails, we are relying on the end user to interact and click with the email. This would limit the impact of the attack in the real world as the majority of people will not click an unsolicited password reset email.

However, in this instance, Tristan found that the target user did not in fact need to click this link to enable an account takeover. As this email travelled through multiple servers/mail-servers before arriving in the user’s inbox, it was loaded multiple times automatically. This is likely due to a combination of email anti-spam engines which automatically try to determine if a link in an email is spam or otherwise is malicious.

This risk is significantly heightened by the fact that administrative users used the same authentication flow.

Example Request - Modifying Password Reset Request

POST /XXXXX/XXXXX/holidays/UserResetPasswordRequests HTTP/1.1
Host: XXXXX.XXXXXXX.com
Cookie: ASP.NET_SessionId=qc4m2phi50izah1jy5vsgvao
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0
Accept: application/json
Accept-Language: en-GB
Accept-Encoding: gzip, deflate
Content-Type: application/json
Content-Length: 217
Te: trailers
Connection: close

{"emailAddress":"testaccount1@onsecurity.co.uk","resetPasswordUrl":"https://xxxxxxxxx.com/Holidays/xxxx/login/password-update?token={token}&emailAddress={emailAddress}&dataView=holidays"}

Example Response - Modifying Password Reset Request

Note the password reset token has been returned in the ‘Location’ header of the response. This is what gives the attacker the ability to reset arbitrary tokens.

HTTP/1.1 201 Created
Cache-Control: no-store
Content-Length: 329
Content-Type: application/json; charset=utf-8
Location: https://xxxxxxxxxx.com/Holidays/xxxxx/holidays/UserResetPasswordRequests/$token
Server:
Access-Control-Allow-Credentials: true
X-API-Version: 1.10.39.18381
Content-Security-Policy: script-src 'none'
X-Powered-By:
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Date: Mon, 18 Jul 2022 15:55:54 GMT
Connection: close

{"resetPasswordUrl":"https://xxxxxxxx.com/Holidays/Orbit/login/password-update?token={token}&emailAddress={emailAddress}&dataView=holidays","hasNotificationBeenSent":true,"emailAddress":"testaccount1@onsecurity.co.uk","creationDate":"2022-07-18T16:55:54.327","confirmedDate":null,"expiredDate":null}

As the password reset token had been obtained, an attacker would simply need to modify the URL to instead point to the legitimate application domain like so:

  • https://xxxxxxxxxxx.com/Holidays/xxxxx/login/password-update?token=45ea8531-aa11-2a1126e5-e315-4556-801d-9f7696c0f3f8&emailAddress=testaccount1@onsecurity.co.uk&dataView=holidays

From this URL it would then be possible for the attacker to change the password of the account to one of their choosing.

The Fix

Do not generate password reset links based on the user-supplied parameters.

Instead, password reset URLs should be based on a static trusted domain and path and not include user-supplied input within the generated link and subsequent email.

Bedtime Reading

https://portswigger.net/web-security/host-header/exploiting/password-reset-poisoning

https://cheatsheetseries.owasp.org/cheatsheets/Forgot_Password_Cheat_Sheet.html

Want to check for yourself if your application is free from this kind of vulnerability? Why not get a quote or contact us to set up a pentest.