In the latest release of Acunetix, we added support for the HTTP / 2 protocol and introduced a number of vulnerability-specific tests related to this protocol. For example, we introduced tests for incorrect routing, server-side request forgery (SSRF) and web cache poisoning. In this article, we want to explain how these vulnerabilities occur so that you can understand the logic behind the tests.
Introduction to HTTP / 2
To understand HTTP / 2, it is best to compare it to its predecessor, HTTP / 1.x.
How HTTP / 1.x works
HTTP / 1.x is a text-based protocol. An HTTP request consists of headers and possibly a body. To separate titles from titles from the body, you use the character sequence rn
(CRLF).
The first title is e Request line, Consisting of a method, path, and version of a protocol. To separate these elements, you usually use white spaces. Other titles are pairs of names and values separated by colon (:). The only title required is Moderator.
The path may be represented in different ways. Usually, it’s relative and it starts with a sloping like / Path / here, But it may also be an absolute URI such as http://virtualhost2.com/path/here. Moreover, the host name from the path takes precedence over the value of the Moderator title.
GET /path/here HTTP/1.1
Host: virtualhost.com
Other-header: value
When the web server receives an HTTP / 1.x request, it parses it using certain characters as separators. However, due to the fact that HTTP is an old protocol and there are many different RFCs dedicated to it, different web servers analyze requests differently and have different restrictions regarding the values of certain elements.
How HTTP / 2 works
HTTP / 2, on the other hand, is a binary protocol with a completely different internal organization. To understand its vulnerabilities, you need to know how the key components of the HTTP / 1.x protocol are now represented.
HTTP / 2 got rid of the request bar and now all the data is displayed in the form of headers. Moreover, since the protocol is binary, each header is a field consisting of length and data. There is no longer a need to analyze data based on special characters.
HTTP / 2 has four required headers called Pseudo-headlines. these are :method, :path, :program, And :permission. Note that common pseudo-title names start with colon, but these names are not transmitted – instead, HTTP / 2 uses special identifiers for each of them.
- :method and :path Are straightforward analogues of the HTTP / 1.1 method and path.
- :program Is a new title that indicates which protocol is usually used http or https.
- :permission Is a substitute for Moderator title. It is allowed to ship as usual Moderator Title please but :permission There is a higher priority.
Incorrect routing and SSRF
Today’s web applications are often multi-layered. They often use HTTP / 2 to interact with user browsers and HTTP / 1.1 to access back-end servers using HTTP / 2 (inverted) proxy. As a result, the reverse proxy must convert the values obtained from HTTP / 2 to HTTP / 1.1, which expands the attack surface. Additionally, when implementing HTTP / 2 support on a web server, developers may pay less attention to the entries in different headings.
Proxy messenger
For example, when I did research for the lecture “Strange Proxy / 2 and Some Magic” at ZeroNights 2021, I found that Envoy Proxy (tested in version 1.18.3) allows you to use arbitrary values in :method, Including a variety of special characters, white space and tab characters. This allows for incorrect routing of attacks.
Suppose you specify :method to be GET http://virtualhost2.com/any/path?
and :path to be /
. The messenger sees a legal path /
And tracks to the rear end. However, when Envoy creates an end request in HTTP / 1.x protocol format, it simply enters the value from :method Into the line of requests. Accordingly, the application will be:
GET http://virtualhost2.com/any/path? / HTTP/1.1
Host: virtualhost.com
Depending on the type of back-up web server, it can accept or reject such a request (because of the extra space). In the case of nginx, for example, this would be a valid request with the path /any/path? /
. Moreover, we can reach an arbitrary virtual host (for example, virtualhost2.com
), To which we otherwise would not have had access.
On the other hand, the Gunicorn web server enables arbitrary values in the version of the protocol in the request bar. Therefore, to achieve the same result as with nginx, we defined :method To GET http://virtualhost2.com/any/path HTTP/1.1
. Once Envoy has processed the request, it will look like this:
GET http://virtualhost2.com/any/path? / HTTP/1.1 / HTTP/1.1
The epoxy
A similar problem exists in Haproxy (tested in version 2.4.0). This inverted proxy allows arbitrary values in :program title. If the value is not http
or https
, Haproxy Name this entry in the request bar of the request sent to the back end server. If you define :program To test
The web server request will look like this:
GET test://virtualhost.com/ HTTP/1.1
Host: virtualhost.com
We can achieve a result similar to that of Envoy by setting: scheme to http://virtualhost2.com/any/path?
. The final backend request line will be:
GET http://virtualhost2.com/any/path?://virtualhost.com HTTP/1.1
This trick can be used both to access arbitrary virtual hosts at the backend (host routing incorrectly) and to bypass various access restrictions in the reverse proxy, as well as to perform SSRF attacks on the backend server. If the backend has an insecure configuration, it may send a request to an arbitrary host specified in the path from the request line.
The latest release of Acunetix includes tests that detect SSRF vulnerabilities.
Cache poisoning
Another common vulnerability of tools that use the HTTP / 2 protocol is cache poisoning. In a typical scenario, a cache server is located in front of a web server and saves responses from the web server. To know which responses are cached, the cache server uses the key. A typical key is Method + Host + Path + Query.
As you can see, there are no titles in the key. Therefore, if a web application returns a header in response, especially insecurely, an attacker could send a request with XSS load in that header. The web app will then return it in response, and the cache server will cache the response and return it to other users requesting the same path (key).
HTTP / 2 adds new flavors to this attack. They are related to :program header, which may not be included in a cache server key, but through it we can influence the cache server request to a back-end server as in the examples of incorrect routing.
The attack may also take advantage :permission and Moderator Headlines. Both are used to specify the host name but the cache server may handle them incorrectly, and for example, use the Moderator header in the cache key, but move the request to the backend using the value of :permission title. in that case, :permission There will be a title without a key and an attacker can put a charge in it for a cache poisoning attack.
DoS Cache Poisoning
There is also a variation of the so-called cache poisoning attack DoS Cache Poisoning. This happens when a cache server is configured to save error-related responses (with response status 400, for example). An attacker could send a specially crafted request that is valid for the cache proxy but is invalid for the backend server. This is possible because servers analyze requests differently and have different restrictions.
HTTP / 2 offers us a fairly universal method for this attack. In HTTP / 2, to improve performance, each cookie should be sent in a separate cookie header. In HTTP / 1.1, you can only get one A cookie Title please. Therefore, the cache server, after receiving a request with several cookie titles, should chain them to one using ;
As a separator.
Most servers have a limit on the length of a single header. A typical value is 8196. Therefore, if an attacker could send an HTTP / 2 request with two 5000 cookie headers, they do not exceed the length and will be processed by a cache server. But the cache server chains them into one A cookie Title, then the length of A cookie The main title of the back end is 10000, which is above the limit. As a result, the backend returns a 400 error. The cache server stores it and we have DoS for cache poisoning.
The latest release of Acunetix includes tests for web cache poisoning and CPDoS using HTTP / 2.
More HTTP / 2 in the future
The vulnerabilities listed above are the most common HTTP / 2 vulnerabilities, but there are more. We plan to add more testing in future scanner editions.
If this topic interests you, I recommend reading the following articles:
Get the latest web security content
In your inbox every week.