Downgrading Attacks

What Is HTTP/2 Downgrading?

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”  HTTP/2   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  HTTP/1.1  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Client β”‚ ────────> β”‚ Reverse Proxy β”‚ ─────────> β”‚ Web Server β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The reverse proxy:

  1. Receives HTTP/2 from client

  2. Rewrites to HTTP/1.1 for backend

  3. Rewrites HTTP/1.1 responses back to HTTP/2

Why Does This Happen?

Reason
Description

Legacy backend

Web server doesn't support HTTP/2

Misconfiguration

Admin unaware of default behavior

Default settings

Proxy defaults to HTTP/1.1 backend

Mixed infrastructure

Different software versions


H2.CL Vulnerability

The Problem

HTTP/2 RFC states:

A request or response that includes a payload body can include a content-length header field.

If reverse proxy:

  1. Accepts Content-Length header in HTTP/2

  2. Doesn't validate it matches actual body

  3. Uses faulty CL when rewriting to HTTP/1.1

β†’ Request smuggling!

Attack Mechanism

Attacker sends HTTP/2 request:

Proxy rewrites to HTTP/1.1:

Result

Proxy Sees
Backend Sees

1 POST request

1 POST request

Body contains smuggled data

+ 1 GET request (smuggled!)


H2.TE Vulnerability

The Problem

Even though HTTP/2 RFC says:

The "chunked" transfer encoding MUST NOT be used in HTTP/2.

Some proxies still accept Transfer-Encoding header and use it during rewrite.

Attack Mechanism

Attacker sends HTTP/2 request:

Proxy rewrites to HTTP/1.1:

Result

Backend uses TE (takes precedence over CL):

  • Empty chunk 0 terminates first request

  • Smuggled request processed separately


Practical Exploitation - H2.CL

Scenario

  • WAF blocks reveal_flag=1 parameter

  • Need to bypass WAF to reveal flag

  • Site uses HTTP/2 with downgrading

Exploit Request

Burp Configuration

  1. Uncheck "Update Content-Length" in Repeater

  2. Ensure request sent as HTTP/2

  3. Set Content-Length: 0 manually

With Header Absorption

The Foo: header absorbs the next request's first line.


Forcing Admin Action

Payload

Execution

  1. Send smuggling request

  2. Wait ~10 seconds for admin

  3. Check if flag was revealed

TCP Stream After Downgrade

Proxy view: Single POST to /

Backend view:

When admin visits, their request triggers the smuggled GET with admin's session.


Attack Flow Diagram


Key Differences from HTTP/1.1 Smuggling

Aspect
HTTP/1.1 Smuggling
HTTP/2 Downgrading

Protocol

HTTP/1.1 only

HTTP/2 β†’ HTTP/1.1

Headers

CL vs TE ambiguity

Fake CL/TE in HTTP/2

Binary format

N/A

Bypassed via downgrade

Detection

Check for both headers

Check for downgrading


References

Last updated