HTTP Host header vulnerabilities

Restricting client access based on the Host http header to fix the host header vulnerability where user exploit host http header .

Send ambiguous requests

The code that validates the host and the code that does something vulnerable with it often reside in different application components or even on separate servers. By identifying and exploiting discrepancies in how they retrieve the Host header, you may be able to issue an ambiguous request that appears to have a different host depending on which system is looking at it.

The following are just a few examples of how you may be able to create ambiguous requests.

Inject duplicate Host headers

One possible approach is to try adding duplicate Host headers. Admittedly, this will often just result in your request being blocked. However, as a browser is unlikely to ever send such a request, you may occasionally find that developers have not anticipated this scenario. In this case, you might expose some interesting behavioral quirks.

Different systems and technologies will handle this case differently, but it is common for one of the two headers to be given precedence over the other one, effectively overriding its value. When systems disagree about which header is the correct one, this can lead to discrepancies that you may be able to exploit. Consider the following request:

GET /example HTTP/1.1
Host: vulnerable-website.com
Host: bad-stuff-here

Let’s say the front-end gives precedence to the first instance of the header, but the back-end prefers the final instance. Given this scenario, you could use the first header to ensure that your request is routed to the intended target and use the second header to pass your payload into the server-side code.

Supply an absolute URL

Although the request line typically specifies a relative path on the requested domain, many servers are also configured to understand requests for absolute URLs.

The ambiguity caused by supplying both an absolute URL and a Host header can also lead to discrepancies between different systems. Officially, the request line should be given precedence when routing the request but, in practice, this isn’t always the case. You can potentially exploit these discrepancies in much the same way as duplicate Host headers.

GET https://vulnerable-website.com/ HTTP/1.1
Host: bad-stuff-here

Note that you may also need to experiment with different protocols. Servers will sometimes behave differently depending on whether the request line contains an HTTP or an HTTPS URL.

Add line wrapping

You can also uncover quirky behavior by indenting HTTP headers with a space character. Some servers will interpret the indented header as a wrapped line and, therefore, treat it as part of the preceding header’s value. Other servers will ignore the indented header altogether.

Due to the highly inconsistent handling of this case, there will often be discrepancies between different systems that process your request. For example, consider the following request:

GET /example HTTP/1.1
 Host: bad-stuff-here
Host: vulnerable-website.com

The website may block requests with multiple Host headers, but you may be able to bypass this validation by indenting one of them like this. If the front-end ignores the indented header, the request will be processed as an ordinary request for vulnerable-website.com. Now let’s say the back-end ignores the leading space and gives precedence to the first header in the case of duplicates. This discrepancy might allow you to pass arbitrary values via the “wrapped” Host header.

Other techniques

This is just a small sample of the many possible ways to issue harmful, ambiguous requests. For example, you can also adapt many HTTP request smuggling techniques to construct Host header attacks. We’ll cover this in more detail in our dedicated request smuggling topic.

Inject host override headers

Even if you can’t override the Host header using an ambiguous request, there are other possibilities for overriding its value while leaving it intact. This includes injecting your payload via one of several other HTTP headers that are designed to serve just this purpose, albeit for more innocent use cases.

As we’ve already discussed, websites are often accessed via some kind of intermediary system, such as a load balancer or a reverse proxy. In this kind of architecture, the Host header that the back-end server receives may contain the domain name for one of these intermediary systems. This is usually not relevant for the requested functionality.

To solve this problem, the front-end may inject the X-Forwarded-Host header, containing the original value of the Host header from the client’s initial request. For this reason, when an X-Forwarded-Host header is present, many frameworks will refer to this instead. You may observe this behavior even when there is no front-end that uses this header.

You can sometimes use X-Forwarded-Host to inject your malicious input while circumventing any validation on the Host header itself.

GET /example HTTP/1.1
Host: vulnerable-website.com
X-Forwarded-Host: bad-stuff-here

For Environments like below

  • Red Hat Enterprise Linux
  • Red Hat JBoss Enterprise Application Platform (EAP)
    • 6
    • 7
  • Red Hat JBoss Web Server
  • JBoss Core Services

Apache

For httpd, you can use a RewriteRule like below. This example rule would only allow www.example.com and example.com

RewriteEngine On
RewriteCond %{HTTP_HOST} !^(www.example.com|example.com)$ [NC]
RewriteRule .* - [F]

If you need to restrict X-Forwarded-Host headers allowed because httpd is behind a proxy, then you may use a rule like the following:

Note: This rewrite rule will be same for IBM Http Server ,Redhat httpd server ,Redhat hat web Server ,OHS …etc

RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Host} !^$ [NC]
RewriteCond %{HTTP:X-Forwarded-Host} !^(www.example.com|example.com)$ [NC]
RewriteRule .* - [F]

For JBoss EAP 7, use an expression-filter in the Undertow subsystem:

/subsystem=undertow/configuration=filter/expression-filter=host-checker:add(expression="not(equals(%{i,Host}, www.example.com) or equals(%{i,Host}, example.com)) -> response-code(403)")
/subsystem=undertow/server=default-server/host=default-host/filter-ref=host-checker:add 

The resulting XML would look like this

<subsystem xmlns="urn:jboss:domain:undertow:3.1">
    <buffer-cache name="default"/>
    <server name="default-server">
        ...
        <host name="default-host" >
            ...
            <filter-ref name="host-checker"/>
        </host>
    </server>
    <filters>
        ...
        <expression-filter name="host-checker" expression="not(equals(%{i,HOST}, www.example.com) or equals(%{i,HOST}, example.com)) -> response-code(403)"/>
    </filters>
</subsystem>

For JBoss EAP 6, use a rewrite in the JBoss Web subsystem:

<subsystem xmlns="urn:jboss:domain:web:2.1" default-virtual-server="default-host" native="false">
    <connector name="http" protocol="HTTP/1.1" scheme="http" socket-binding="http"/>
    <connector name="ajp" protocol="AJP/1.3" scheme="http" socket-binding="ajp"/>
    <virtual-server name="default-host" enable-welcome-root="true">
        <alias name="localhost"/>
        <alias name="example.com"/>
        <!-- added -->
        <rewrite pattern="^/(.*)$" substitution="-" flags="F">
            <condition test="%{HTTP_HOST}" pattern="!(www.example.com|example.com)" flags="NC"/>
        </rewrite>
    </virtual-server>
</subsystem>

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *