Critical to know if your a pentester — the “new” HTTP/2 request /header format (level: hard/expert)

DJ SUBSTANCE
7 min readDec 10, 2023

--

9x.network — the 9x crew has been spreading hacking info since 1994

HTTP/2 introduced some fairly substantial differences in caching, the request method’s themselves (+ their syntax) and other things.

Before we get into the details (from high level, you will understand a great deal more after just reading this summary, and your ethical hacking / bounty knowledge will be +++ ) keep reading:

What is HTTP/2?

HTTP/2 is a replacement for how HTTP is expressed “on the wire.” It is not a ground-up rewrite of the protocol; HTTP methods, status codes and semantics are the same, and it should be possible to use the same APIs as HTTP/1.x (possibly with some small additions) to represent the protocol.

The HTTP/2 protocol brings about several changes and improvements over HTTP/1.1, particularly in the formatting and transmission of requests and responses. One of these changes is the introduction of pseudo-header fields, which are used to convey the standard parts of an HTTP request or response in a more efficient and structured way.

Reference: https://http2.github.io/

Taking a Look as an example to refamaliarize ourselves with the way that the 2 different requests may look:

This is a typical HTTP/2 request not written in the new "shorthand"
The most important thing you can be looking at in these requests (if your using m
burp, zap, mitmproxy etc) is the version # after the POST or GET first line

GET /announcements/api/entity/v1/index/announcement-posts_en HTTP/1.0
GET /announcements/api/entity/v1/index/announcement-posts_en HTTP/1.1
GET /announcements/api/entity/v1/index/announcement-posts_en HTTP/2

--- I feel this is the absolute first thing you should be making note of,
In the list of the 3 GET's above, you see http1.0 (this is rare now a days,
but ive seen it, it should make you immediately aware of "old hardware" likely
(or programmers doing it wrong)

---- The 2nd example shows the most typical HTTP/1.1 - this is really what
I feel that is best to exploit, and my point in writing this article is
to help you understand how to write the request (for repeater perhaps) to
"downgrade" our http/2 responses to http/1.1 for easier attacks and pivots.

---- The HTTP/2 is becoming more commonly lately, I dont think its due to
anyone getting "with it" or more secure, i think the newer hardware and cloud
platforms we build on are handling it.

GET /announcements/api/entity/v1/index/announcement-posts_en HTTP/2
Host: api2.djsubstance.com
Cookie: deviceId=549335d9-dfd1-8e25-c8a3-d55ffbe0bad6;

Before discussing how to “downgrade” the HTTP/2 traffic, and get the server and devices in the chain (rev proxies etc) to start talking 1/1, lets talk briefly about the major changes in HTTP/2.

This is going to confuse the sh*t out of some of you, you may not believe me.

RFC’s that you should absolutely read if you are a serious pentester or developer: (Dont take my word, this is just an overview to get you thinking)

https://datatracker.ietf.org/doc/html/rfc9113 — HTTP/2 [current] June 2022
https://datatracker.ietf.org/doc/html/rfc7540 — HTTP/2 [original] May 2015

They are both worth looking at, in fact:
https://datatracker.ietf.org/doc/html/rfc2616 — HTTP/1.1 [original] June 1999

dj substance / tranceattic / free downloads elite trance music
This actually does say HTTP/2 but I think I went a little to crazy with the Graffitti ;)

There is a *lot* of detail I could go into about binary streams, and other extremely important (yet . beyond the scope of this intro ), that could be discussed, I will post the ultimate page Ive seen with all the things you could ever want to know (in a non RFC robot written form ;) at the end.

The meat and potato's of this post:
In HTTP/2, “pseudo-header” fields are headers that start with a colon (:) to distinguish them from regular HTTP headers. They represent the standard parts of the HTTP message that were represented in the start-line (like the HTTP method, path, and scheme) in HTTP/1.1. For instance, in an HTTP/2 request, the following pseudo-header fields are common:

(This is going to seem extremely foriegn initiatally)

  • :method: This represents the HTTP method used in the request (e.g., GET, POST, PUT, etc.).
  • :scheme: This indicates the protocol scheme (e.g., http or https).
  • :authority: This replaces the Host header from HTTP/1.1 and includes the authority portion of the URL, which is typically the domain name and port number.
  • :path: This contains the path and query part of the request URL.

Here is an example to illustrate the difference:

HTTP/2 Request - the "old" way:
-------------------------------
GET /deadpool/json5.json HTTP/2
Host: www.target.com
Cookie: deviceId=549335d9-dfd1-8e25-c8a3-d55ffbe0bad6;
Accept: application/json
Content-Type: application/json
Platform: pc
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.6045.199 Safari/537.36
Sec-Ch-Ua-Platform: "macOS"
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://www.target.com/en/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Priority: u=1, i

One thing to make note of while I think of it, stop sending your full User-Agent
in your requests, and if you can ever change it, any remote system just wants
#1) to see a UA set
#2) to see something like Mozilla in there to think its valid

Change: User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.6045.199 Safari/537.36
to: User-Agent: Mozilla/5 (This will 99% of the time trick sites into
thinking you have JS enabled if your are curling BTW)

New format of http/2:
:method <GET|POST|OPTIONS|etc>
:path /index.php
:authority <host>
--- Here is an image of the differences:
This picture does the concept alot more justice but we still need to discuss more

As you can see in the image above, the top request is HTTP1/1 and doing the same thing with HTTP/2 — that is what it looks like

Just so everyone is on the same page and knows this actaully works and I have a clue what im talking about I am demonstrating this in Burp repeater.

This is a *valid* request, just remember that this is only going to be for the request, the response will look “normal” (at least from what ive seen) but remember the goal in my experience is to downgrade HTTP/2 servers to HTTP/1.1 . This is done by confusing the devices such as LB or rev. proxies in the middle to do so, and it usually works!

Here is the output of the above req:

Response of the http/2 burp repeater POST request i made up

Now this wasn't the best example I suppose, because the endpoint was using 1.1 anyways, but you can see that it “took” at least.

Here are the major differences in the headers, there is probably more in the RFC but this is the core of what you need to know:


HTTP/2 reqest header changes:
:method - The request method
:path - The request path. Note that this includes the query string
:authority - The Host header, roughly -
** :authority: typically the domain name and port number ** important

:scheme - The request scheme, typically 'http' or 'https'
:status - The response status code - not used in requests

In Summary — now you know that HTTP/2 isnt just a new looking “same old same old” method of web packet transport. The point of this post, and I hope you got something out of it, was the fact that the requests look totally different, and your goal is to trick your target into downgrading to 1/1 — If you dont know why, this is probably over your head.

Here are the complete list of updates of 1/1->2

Here are the key differences as a whole — I am not getting into the technical details of that, it has been covered and I will link a great doc at the end of the post:

HTTP/2 protocol introduces several key advancements and variances compared to HTTP/1.1. Notable differences include:

  1. Binary Framing Layer: Unlike HTTP/1.1, which uses plain text for requests and responses, HTTP/2 encapsulates all communications in a binary format. This maintains HTTP semantics such as verbs, methods, and headers, while using a binary framing layer.
  2. Multiplexing: HTTP/2 can multiplex multiple streams over a single TCP connection. This capability allows for simultaneous sending of multiple requests and responses, thereby reducing latency.
  3. Server Push: With HTTP/2, servers have the ability to push resources to clients even before the client requests them, enhancing page loading speeds.
  4. Header Compression: HTTP/2 employs HPACK compression for headers, reducing overhead and boosting performance.
  5. Flow Control: HTTP/2’s approach to flow control is distinct from that of HTTP/1.1, which depends on the transport layer to prevent buffer overflow. HTTP/2 achieves flow control at the stream level while multiplexing streams over a single TCP connection.

The focus of the protocol is on performance; specifically, end-user perceived latency, network and server resource usage. One major goal is to allow the use of a single connection from browsers to a Web site.

By far #1 seems the most complex to me. To be a expert pentester, learn it all, never stop.

Here is a link to a massive current book i converted to one huge .html on HTTP and the versions and specifics: https://9x.network/files/HTTP_2-HighPerformanceBrowserNetworking.html

Till next time

DJ Substance
:: One Nation :: Underground ::

--

--

DJ SUBSTANCE

twenty years professionally as a Network Engineer, more recently I have focused on red teaming mostly, but I am always up for learning and exchanging info