Attacks related to cache poisoning represent a clearly visible web security trend that has emerged in recent years. The security community continues to research this area, finding new ways to attack.

As part of the recent release of Acunetix, we have added new checks related to cache poisoning vulnerabilities and we continue to work in this area to improve coverage. In this article, I’d like to share with you a few techniques related to one of the new checks – Cache Poisoning DoS (CPDoS).

What Is a Cache Poisoning Denial-of-Service Attack

In 2019, Hoai Viet Nguyen and Luigi Lo Iacono published a whitepaper related to CPDoS attacks. They explained various attack techniques and analyzed several content delivery networks and web servers that could be affected by such attacks.

CPDoS attacks are possible if there is an intermediate cache proxy server, located between the client (the user) and the web server (the back end), which is configured to cache responses with error-related status codes (e.g. 400 Bad Request). The attacker can manipulate HTTP requests and force the web server to reply with such an error status code for an existing resource (path). Then, the proxy server caches the error response, and all other users that request the same resource get the error response from the cache proxy instead of a valid response.

The whitepaper presents 3 attack types that allow the attacker to force a web application to return a 400 status code:

  • HTTP Header Oversize (HHO) – when the size of a header exceeds the maximum header length
  • HTTP Meta Character (HMC) – when the header of the attacker’s request contains a special “illegal” symbol
  • HTTP Method Override (HMO) – when the header of the attacker’s request changes the verb (method) to an unsupported one

New HHO Attack Tricks

While analyzing these attacks and working on my project dedicated to reverse proxies, I’ve managed to come up with a couple of tricks that can be used to perform an HHO attack.

Basically, an HHO attack is possible when the maximum header length is defined differently in the cache proxy and the web server. Different web servers, cache servers, and load balancers have different default limits. If the cache proxy has a maximum header limit that is higher than the limit defined in the web server, a request with a very long header can go through the cache server to the web server and cause the web server to return a 400 error (which will then be cached by the cache server).

For example, the default maximum header length for CloudFront is 20,480 bytes. On the other hand, the default maximum header length for the Apache web server is 8,192 bytes. Therefore, if an attacker sends a request with a header that is 10,000 bytes long and CloudFront cache proxy passes it to an Apache server, the Apache web server returns a 400 error.

However, an HHO attack is possible even if the cache server has the same header length limit as the web server or one that is a little lower. There are two reasons for this:

  • The web server maximum header length limit is a string length limit. The web servers that I have tested don’t perform any normalization and probably don’t even parse the header before applying the length check.
  • However, cache proxies send correct (normalized) headers to the back end.

Same-Limit HHO Attack Example

A practical HHO attack could be performed as follows:

  1. The attacker sends a request with a header that is 8192 bytes long (including \r\n) but with no space between the header name and the value. For example:
    header-name:abcdefgh(…)(8192 characters in total)
  2. The cache proxy checks the length of the header and finds that it is not more than 8192 characters long. Therefore, it parses the header and disregards the missing space.
  3. Then, the cache proxy prepares the correct version of the header to be sent to the web server:
    header-name: abcdefgh(…)(8193 characters in total)
  4. The cache proxy does not check that the final length of the header exceeds 8192 characters and sends the header to the web server.
  5. The web server that receives the header sees that it exceeds the limit by one byte, and therefore it returns the 400 error page.

Similar-Limit HHO Attack Example

If the cache proxy maximum header length limit is a bit lower than the web server limit, we cannot use the trick described above (1 byte is not enough). However, in such a case, we can misuse another feature.

Many proxy servers add headers to requests that are forwarded to the web server. For example, X-Forwarded-For, which contains the IP address of the user. However, if the original request also contains the X-Forwarded-For header, the proxy server often concatenates the original value with the value set by the proxy server (the user IP).

This allows us to perform the following attack:

  1. The attacker sends a request with the following header:
    X-Forwarded-For: abcdefgh(…)
    (8192 characters in total)
  2. The proxy concatenates this request with its own value:
    X-Forwarded-For: abcdefgh(…)12.34.56.78
    (8203 characters in total)
  3. The proxy sends the value to the web server, which replies with an error code because the header is too long.

Depending on the type of a proxy and its configuration such added headers may be different and the lengths of added values may be different as well. You can check some of them on my project page.

The Impact of CPDoS Attacks

When we were testing our new CPDoS script on bug bounty sites, we noticed that many sites are vulnerable to such attacks. However, in some cases, the impact of the attack is questionable. This is because quite a few cache proxies are configured to cache responses with error status codes only for a few seconds, which makes it difficult to exploit.