In the last post about bypassing web filters, I discussed how SNI spoofing works and how this can also be prevented by web filters. This post is about another bypass technique called Host Header spoofing.

What Is a Host Header

The Host header is an HTTP request header sent by the client (usually a browser) to the webserver as part of the HTTP request, and specifies the hostname of the server1. Because a webserver can host multiple websites on the same IP address, this information is required to deliver the correct website. This is called virtual hosting. Reverse proxies can also use this header to determine to which backend system the incoming requests should be sent.

In the following example, Alice connects to the webserver with the IP address 203.0.113.5, which hosts the websites a.example.net, b.example.net, and c.example.net. As Alice’s browser sends the Host header b.example.net, the webserver knows to deliver the files for the right directory.

Alice requesting a file from b.example.net

Nowadays, HTTP traffic is almost always wrapped in TLS, and since the Host header is part of the HTTP request, it is also encrypted. This is illustrated below.

First, the browser establishes a TLS session with the server. In the TLS handshake, the hostname is sent in the SNI ①. Then, an HTTP request is sent to the server ② inside the TLS tunnel ③. As part of this request, the browser again specifies the hostname in the HTTP Host header ④:

HTTP request with Host header inside TLS tunnel

Note: Normally, you would not be able to inspect the decrypted messages exchanged in a TLS tunnel. Instead of the HTTP GET request, you would simply see encrypted data. For this setup, the TLS keys were dumped using the SSLKEYLOGFILE variable2,3 and imported into Wireshark, which allows on-the-fly decryption of TLS traffic.

Host Header Based Filters

Companies often intercept and inspect TLS traffic on proxies. For this to work, the Certificate Authority (CA) certificate of the proxy must be installed on all client devices. This is therefore only possible in corporate environments, where the company manages all clients, so they can install the proxy CA. Without the installed proxy CA, users would receive a TLS certificate error and be able to detect that someone is looking at their traffic (this is also known as a Man-in-the-Middle attack).

With a setup as described above, the proxy is able to decrypt and inspect all traffic, and use the information from the HTTP request (like the Host header) to determine whether a request is legit or not. This approach is used to block dangerous files (such as .exe files), known malicious websites, specific website categories like gaming, or file uploads exceeding a certain size to prevent data exfiltration.

In most cases, such filters work with a blocklist (or known-bad) approach. However, in rare cases, we have seen customers implement the opposite, by defining a list of allowed (or known-good) websites, that can be accessed through the filter.

Bypassing Simple Web Filters Using Host Header Spoofing

When proxies only rely on the Host header to determine if a request is legitimate, this can be exploited to bypass such web filters.

This requires control over the HTTP request, which can be achieved by malware running on the system or by an attacker or user with system access attempting to bypass the web filter.

Imagine you have the following situation where Alice is able to access the website legit.example.net but the access to evil.example.com is blocked by the firewall based on the Host header evil.example.com:

Connection is blocked to evil.example.com

Alice (or a malware on her computer) is now able to bypass the web filter by connecting to evil.example.net (leaving the SNI evil.example.net unmodified), but specifying the Host header legit.example.net:

Blocking mechanism bypass by spoofing a legit hostname in the Host header

The final IP, TLS and HTTP packet structure looks like this:

Host Header Spoofing

Since we only changed the Host header, but not the SNI, there is also the added benefit that we can bypass web filters that perform SNI matching with the hostname/SAN from the certificate (see previous blogpost about SNI spoofing).

Example Using curl

To craft such a request is easy. Using curl, we can control the Host header as shown below:

curl -H "Host: legit.example.net" https://evil.example.com

Here we can see that the SNI is unchanged ① to match the certificate subject but the HTTP request ② contains the spoofed Host header ③:

Connectin with evil host in the SNI but legit one in the Host header

Note: For demonstration purposes, the TLS connection is decrypted again to allow inspection of the contained HTTP traffic.

We found such bypasses in projects, where the customer e.g. blocked large file uploads to most websites to prevent data exfiltration. In this case, this imposed restriction on our C2 communication, because the C2 implant was not able to transmit larger chunks of data back to our server. By overriding the Host header to a value which was excluded from the blocklist (the customer’s own file sharing solution), the filter could be bypassed, allowing unrestricted communication from our C2 implant.

Host Header Spoofing Protection and Limitations

The bypass technique discussed above only works if the proxy only uses the Host header to decide whether a website should be blocked or not, ignoring other mechanisms such as SNI inspection/matching.

However, in most cases web filters will perform additional checks to improve resilience against such bypasses. For example, a proxy could verify that the hostname in the SNI and in the Host header are identical, and drop requests where they are different.

Example: Fortinet FortiGate

The Fortinet FortiGate firewall/proxy has such a feature called “Domain Fronting Protection”4 which blocks mismatches of the hostnames:

FortiGate Domain Fronting Protection Documentation

The HTTP response looks like this if this is detected:

HTTP/1.1 403 Forbidden
[...]

[...]
<h3>403 domain fronting blocked</h3>
<p>The webserver reported that an error occurred while trying to access the website. Please return to the previous page.</p>
[...]

The message in the log looks like this:

type="utm" subtype="webfilter" eventtype="domain-fronting" srcip=172.17.0.2 dstip=198.51.100.23 dstport=443 hostname="legit.example.net" msg="Domain fronting detected" rawdata="HTTP Host <legit.example.net> does not match SNI <evil.example.com>"

This protection feature is enabled by default but can be disabled:

This protection is enabled by default but can be disabled.

More about domain fronting will be explained in the next post.

Takeaway

Host header spoofing is a rather simple bypass technique, and – given a correctly configured web filter solution – is easily preventable. Nonetheless, it’s always worth looking for it in your next penetration test or in your own infrastructure!

Also keep in mind that it’s not always about being able/not able to access a specific site, but also about bypassing other restrictions such as large file uploads, or downloading certain file types.

References

  1. RFC 2616, HTTP/1.1, “The Resource Identified by a Request”: https://www.rfc-editor.org/rfc/rfc2616#section-5.2 ↩︎
  2. Everything Curl, SSLKEYLOGFILE: https://everything.curl.dev/usingcurl/tls/sslkeylogfile.html ↩︎
  3. Internet Draft, The SSLKEYLOGFILE Format for TLS, https://www.ietf.org/archive/id/draft-ietf-tls-keylogfile-03.txt ↩︎
  4. Fortinet Documentation, Fortigate, Domain Fronting Protection: https://docs.fortinet.com/document/fortigate/7.6.2/administration-guide/639769 ↩︎