©2019 Security Unleashed | New Delhi

  • Animesh Gupta

HOST HEADER ATTACK




Introduced in HTTP 1.1, a host header is a third piece of information that you can use in addition to the IP address and port number to uniquely identify a Web domain or, as Microsoft calls it, an application server. For example, the host header name for the URL http://www.cybertechops.com is www.cybertechops.com.


1. Why HTTP host header needed? Can we proceed without it?


RFC 2616 (sec 14.23) A client MUST include a Host header field in all HTTP/1.1 request messages. If the requested URI does not include an Internet host name for the service being requested, then the Host header field MUST be given with an empty value. Any HTTP/1.1 request without host header field must be responded by server with 400(bad request) status code.


2. What is the main purpose of using HTTP request header?


Application using virtual host and load balancer identifies request by their host header. Server is assigned to single IP address that may host multiple websites. When request comes to server it will redirect to different websites by identifying request from host field. Thus, must validate host header before redirect to websites.


3. What are the attacks related to host headers?


There are several different types of attacks related to host header injection

1. Unauthorized URL Redirect by Cache poisoning

2. Password Reset Poisoning

3. Access to internal hosts

4. Cross site scripting


It is common practice for the same web server to host several websites or web applications on the same IP address. This why the host header exists. The host header specifies which website or web application should process an incoming HTTP request. The web server uses the value of this header to dispatch the request to the specified website or web application. Each web application hosted on the same IP address is commonly referred to as a virtual host. So what constitutes a host header attack?

What happens if we specify an invalid Host Header? Most web servers are configured to pass the unrecognized host header to the first virtual host in the list. Therefore, it’s possible to send requests with arbitrary host headers to the first virtual host.

Another way to pass arbitrary Host headers is to use the X-Forwarded-Host header. In some configurations this header will rewrite the value of the Host header. Therefore it’s possible to make the following request.


GET / HTTP/1.1

Host: www.example.com

X-Forwarded-Host: www.attacker.com

Many web applicatios rely on the HTTP host header to understand “where they are”. Unfortunately, what many application developers do not realize is that the HTTP host header is controlled by the user. As you might already know, in application security user input should always be considered unsafe and therefore, never trusted without properly validating it first.

The use of the host header is especially common in PHP web applications, however, it’s certainly not a problem endemic to PHP web applications. The PHP script in the following example is a typical and dangerous use of the host header.


<script src="http://<?php echo SERVER['HOST'] ?>/script.js">


An attacker can potentially manipulate the code above to produce the following HTML output just by manipulating the host header.


<script src="http://attacker.com/script.js">

Impact


The two major attack vectors host header attacks enable are web-cache poisoning, and abuses of alternative channels for conducting sensitive operations, such as password resets.

How to set HTTP headers (for cache-control)?


To use cache-control in HTML, you use the meta tag, e.g.


<meta http-equiv="Cache-control" content="public">


The value in the content field is defined as one of the four values below.

Some information on the Cache-Control header is as follows


HTTP 1.1. Allowed values = PUBLIC | PRIVATE | NO-CACHE | NO-STORE.

Public - may be cached in public shared caches.

Private - may only be cached in private cache.

No-Cache - may not be cached.

No-Store - may be cached but not archived.


The directive CACHE-CONTROL: NO-CACHE indicates cached information should not be used and instead requests should be forwarded to the origin server. This directive has the same semantics as the PRAGMA: NO-CACHE.


Clients SHOULD include both PRAGMA: NO-CACHE and CACHE-CONTROL: NO-CACHE when a no-cache request is sent to a server not known to be HTTP/1.1 compliant. Also see EXPIRES.


Note: It may be better to specify cache commands in HTTP than in META statements, where they can influence more than the browser, but proxies and other intermediaries that may cache information.

X-Forwarded-Host (XFH)



There is another way of bypassing arbitrary Host headers by using the X-Forwarded-Host Header. The X-Forwarded-Host HTTP header is used to forward the original Host header value to the origin server. X-Forwarded-Host header is very crucial HTTP header for determining which Host was originally used when there is a proxy or CDN between the client and origin server. This header is necessary for servers running behind a reverse proxy (such as nginx).

If a request contains the X-Forwarded-Host HTTP header a website would then use its value in place of the actual HTTP hostname. In cases where caching is enabled, this could allow an attacker to potentially embed a remote URL as the base_url for any site. This would then cause other visitors to the site to be redirected unknowingly.

Thus if an application fails to prevent user from using the X-Forwarded-Host header, it will effectively override the Host header.

Web-cache poisoning

Web-cache poisoning is a technique used by an attacker to manipulate a web-cache to serve poisoned content to anyone who requests pages.

For this to occur, an attacker would need to poison a caching proxy run by the site itself, or downstream providers, content delivery networks (CDNs), syndicators or other caching mechanisms in-between the client and the server. The cache will then serve the poisoned content to anyone who request it, with the victim having no control whatsoever on the malicious content being served to them.

The below is an example of how an attacker could potentially exploit a host header attack by poisoning a web-cache.

$ Telnet www.example.com 80

Trying x.x.x.x...

Connected to www.example.com.

Escape character is '^]'.

GET /index.html HTTP/1.1

Host: attacker.com

HTTP/1.1 200 OK

...

<html>

<head>

<title>Example</title>

<script src="http://attacker.com/script.js">

...

Now, if there is any caching going on either by the site owners or any proxies along the way, other clients will get the exploited page.


Remediation

1) Host header injection can be mitigated by rejecting any request that doesn't match the target domain.

2) Validating Host header to ensure that the request is originating from that target host or not.

3) Host header injection can be mitigated in Apache and Nginx by creating a dummy virtual host that catches all requests with unrecognized Host headers.

4) By creating a whitelist of trusted domains during the initial setup of the application and mapping domains received in Host header of each and every request with it.

5) It is recommended to disable the support for the X-Forwarded-Host header and if can’t be disabled put proper security checks on it to prevent its tampering.

6) One should use secure server configuration.


Password Reset Poisoning


A common way to implement password reset functionality is to generate a secret token and send an email with a link containing this token. What could happen if an attacker requests a password reset with an attacker controlled host header?

If the web application makes use of the host header value when composing the reset link, an attacker can poison the password reset link that is sent to a victim. If the victim clicks on the poisoned reset link in the email, the attacker will obtain the password reset token and can go ahead and reset the victim’s password.

Popular photo-album platform Gallery uses a common approach to forgotten password functionality. When a user requests a password reset it generates a random key:



Places it in a link to the site:



and emails to the address on record for that user. When the user visits the link, the presence of the key proves that they can read content sent to the email address, and thus must be the rightful owner of the account.

The vulnerability was that url::abs_site used the Host header provided by the person requesting the reset, so an attacker could trigger password reset emails poisoned with a hijacked link by tampering with their Host header:

> POST /password/reset HTTP/1.1 > Host: evil.com > ... > csrf=1e8d5c9bceb16667b1b330cc5fd48663&name=admin


This technique also worked on Django, Piwik and Joomla, and still works on a few other major applications, frameworks and libraries that I can't name due to an unfortunate series of mistakes on my part.

Of course, this attack will fail unless the target clicks the poisoned link in the unexpected password reset email. There are some techniques for encouraging this click but I'll leave those to your imagination.

In other cases, the Host may be URL-decoded and placed directly into the email header allowing mail header injection. Using this, attackers can easily hijack accounts by Bcc’ing password reset emails to themselves. Even if the application's mailer ignores attempts to BCC other email addresses directly, it's often possible to bounce the email to another address by injecting \r\Return-To: attacker@evil.com followed by an attachment engineered to trigger a bounce, like a zip bomb.