Most of web application security vulnerabilities, leverage user input in ways that were not initially intended by their developer(s). Password Reset Poisoning is one such vulnerability, that leverages commonly unthought of headers, such as the Host
header seen in an HTTP request:
GET https://example.com/reset.php?email=foo@bar.com HTTP/1.1 Host: evilhost.com
Notice the difference where we specify the host in the URL (example.com) and a different, malicious host, in the Host header (evilhost.com).
Example – Password Reset(s)
One common functionality in most web applications, is the ability to reset your password. Requesting to do so may sometimes involve sending an email to your inbox with a URL embedding in a special one-time token to click on. The one time token is there to allow the user to set a new password without having to specify the old (current) one.
Part of building that URL, is deciding what the domain should be, which in PHP may look something along the lines of:
$resetPasswordURL = “https://{$_SERVER[‘HTTP_HOST’]}/reset-password.php?token=12345678-1234-1234-1234-12345678901”;
This is then injected into an email template and sent to the user as expected. From the Developer’s perspective, he is always expecting $_SERVER[“HTTP_HOST”]
to be example.com so would rarely perform any additional sanity checks on the input.
Targeted Attack
As a malicious actor, you want to take control of a particular individual’s account. By leveraging Password Reset Poisoning, you can:
-
- Obtain the target’s email address used on the site.
This is sometimes done via:a) Social Engineering attacks (Phishing, Smishing etc.)
b) OSINT (Open-source Intelligence)
c) Mining old data breaches for the user’s information. - Send a Password Reset request on behalf of the target scoped in step one, with the modified Host header like so:
POST https://example.com/reset.php HTTP/1.1 Accept: */* Content-Type: application/json Host: evilhost.com {“email”: “target@company.com”}
Which if we refer back to the previous code, will string interpolate the reset password URL to (for example):
https://evilhost.com/reset-password.php?token=12345678-1234-1234-1234-12345678901
- Wait for the target to receive the manipulated email such as the following: These emails would look entirely secure to the user, especially if the link is hidden behind some button or image. Primarily due to the fact that the email is actually sent by the correct application and not the evil host.
- The victim’s password reset token is extracted once the link is clicked. At this point, the attack can go a step further by cloning the site to make it seem as though the user is accessing the correct one. This is generally done in one of two ways:
a) The attacker clones part of the application (e.g. login page) and presents that to the user once they have clicked the link.
b) The attacker’s site (evilhost.com) acts as a proxy to the real site whereby the behavior and the contents would be identical to the original site, making everything look seamless to the end-user. This is the most convincing method.
- Obtain the target’s email address used on the site.
Remediation
From a development perspective, do not trust the Host
header, or any input header for that matter. Instead, the application’s base URL should be determined by some configuration depending on the environment. A good example is a config.ini
file such as:
[GLOBAL] DB_URL=mysql:// DB_USER=root DB_PASS=toor [APPLICATION] BASE_URL=example.com
This can then be string interpolated safely as a constant in the previous code. Assume there is some utility function get_config(section, entry)
:
$resetPasswordURL = “https://” . get_config(‘APPLICATION’, ‘BASE_URL’) . ”/reset-password.php?token=12345678-1234-1234-1234-12345678901”;
Additionally, as an application developer, you should support and highly incentivize Multi-Factor Authentication to avoid malicious actors hijacking accounts with password reset tokens alone. Ideally also avoiding 2FA methods such as SMS Authentication.
Conclusion
Password Reset Poisoning is one of those attacks that appear very trivial and are very much on the practical side rather than the theoretical, often used as low-hanging fruit in Bug Bounty Programs.
That said, they are very easy to secure against and easily illustrate why you should always be cautious of any possible form of user input. This is especially true when developers make use of web application security scanners to automatically detect such vulnerabilities. Acunetix will not only test the Host header for Password Reset poisoning, it will also test for a slew of other Host Header attacks to help you to fully secure your web application(s).