Apache HTTP Server Reverse Proxy/Rewrite URL Validation Issue
Last updated on: December 19, 2022
Table of Contents
Today Apache acknowledged another reverse proxy issue (CVE-2011-4317) which I discovered while creating a QualysGuard vulnerability signature for an older problem CVE-2011-3368. Depending on the reverse proxy configuration, the vulnerability could allow access to internal systems from the Internet.
While reviewing the patch for the older issue CVE-2011-3368, it appeared that it was still possible to make use of a crafted request that could exploit a fully patched Apache Web Server (Apache 2.2.21 with CVE-2011-3368 patch applied) to allow access to internal systems if the reverse proxy rules are configured incorrectly. I submitted an advisory and proof of concept to Apache and Apache made the issue public today.
For a good description of the older CVE-2011-3368 issue as well as how a reverse proxy works please check the excellent blog post by Context.
Here is a description of the new issue CVE-2011-4317 and its proof of concept.
Apache’s patch for CVE-2011-3368
The patch for CVE-2011-3368 (see Figure 1) is straight forward and self explanatory. The “server/protocol.c” file was modified. The patch looks at the request being sent and returns a HTTP 400 Response (Bad Request) if the URL does not begin with a forward slash “/”.
--- httpd-2.2.21/server/protocol.c +++ httpd-2.2.21/server/protocol.c @@ -640,6 +640,25 @@
ap_parse_uri(r, uri);
+ /* RFC 2616: + * Request-URI = "*" | absoluteURI | abs_path | authority
+ * + * authority is a special case for CONNECT. If the request is not
+ * using CONNECT, and the parsed URI does not have scheme, and
+ * it does not begin with '/', and it is not '*', then, fail
+ * and give a 400 response. */
+ if (r->method_number != M_CONNECT
+ && !r->parsed_uri.scheme <-- A
+ && uri[0] != '/'
+ && !(uri[0] == '*' && uri[1] == '\0')) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "invalid request-URI %s", uri);
+ r->args = NULL;
+ r->hostname = NULL;
+ r->status = HTTP_BAD_REQUEST;
+ r->uri = apr_pstrdup(r->pool, uri);
+ }
+
if (ll[0]) { r->assbackwards = 0; pro = ll; }
Figure 1
This part of the code takes care of the issue for CVE-2011-3368. However; if you carefully look at the patch, it does not process URIs that have a scheme (see Figure 1, A). So, if a malformed URL request with a scheme was constructed, it would still be possible to bypass security and gain access to systems on the internal server provided that the reverse proxy rules were incorrectly configured.
Proof of Concepts
Target: Fully patched Apache Web Server (Version 2.2.21) with CVE-2011-3368 patch applied, with a reverse proxy set up and incorrectly configured RewriteRule/ProxyPassMatch rules.
Rewrite rules in httpd.conf:
RewriteRule ^(.*) http://10.40.2.159$1
ProxyPassMatch ^(.*) http://10.40.2.159$1
Example 1:
GET @localhost::<PORT> HTTP/1.0\r\n\r\n
where <PORT> is any port number being requested.
To demonstrate the proof of concept, Tomcat was set up to run on port 8880 on the internal server. Please note that any application could be running on any port on the internal server and a malicious user could use the PoC to request access to an application running on that port.
Access to internal web server can be possible by using a crafted request like:
GET @localhost::8880 HTTP/1.0\r\n\r\n
The screenshot below shows that a basic query with the crafted request (see Figure 2, B) to the target results in access to the page at 8880 (see Figure 2, C).
Figure 2
Upon receiving the request, Apache translates the URL by applying the rewrite rules. The “uri” extracted is “:8880” which gets appended, resulting in the URL
http://10.40.2.159:8880
The “uri” extracted in this case is everything following the first occurrence of the colon (:) in the request. Since the crafted request has 2 colons (::), the second colon is treated as being part of the URI.
To view the URI being extracted based on the rewrite rules, “RewriteLogLevel” was set to 3 in Apache configuration file. The rewrite translation logs get written to the log file. The first step to come up with the crafted request was to review the log file by sending different requests and studying how the rewrite translation was working. In the case of Example 1, since everything following the first colon (:) was being treated as the URI, a second colon was appended with a port number to see the response. The server treated the second “:” as being part of the URI and since there was an application already running on the port, it was possible to gain access to the page.
Example 2:
GET <random_string>:@<internalservername> HTTP/1.0\r\n\r\n
where <random_string> is any string, <internalservername> is the domain of an internal server being requested.
Access to internal web server can be possible by using a crafted request like:
GET qualys:@qqq.qq.qualys.com HTTP/1.0\r\n\r\n
The screenshot below shows that a basic query with the crafted request to an internal website (see Figure 3, D) allows access to the page remotely (see Figure 3, E).
Figure 3
Upon receiving the request, Apache translates the URL by applying the rewrite rules. The “uri” extracted is “@qqq.qq.qualys.com” which gets appended, resulting in the URL
http://10.40.2.159@qqq.qq.qualys.com
The “uri” extracted in this case is everything following the first occurrence of the colon (:) in the request. This is treated as <username>@<host> giving access to the internal <host> if no authentication is required.
Patch
Apache fixed this issue in Version 2.2.22.
Workaround
Until a patch is applied, configuring the reverse proxy rules in the apache configuration file correctly will prevent this issue from occurring. For example, in the above case, if the reverse proxy rules (RewriteRule or ProxyPassMatch directives in httpd.conf) are configured as follows, the proof of concept will not work.
RewriteRule ^(.*) http://10.40.2.159/$1
ProxyPassMatch ^(.*) http://10.40.2.159/$1
Is there any easy way to check and see if the Apache web server built into Mac OS X is vulnerable or not? And, if so, is there an easy way to fix it (reconfigure it) aside from blocking with firewalls, etc.?
If the Apache server is configured to be used as a "Reverse Proxy" with incorrect "RewriteRule" or "ProxyPassMatch" directives as shown above, then it could be affected.
To avoid the issue, make sure the RewriteRule in the apache configuration file (usually httpd.conf or apache2.conf) is correctly configured.
The issue happens because the forward slash "/" is missing before $1. In the above proof of concept, if the forward slash is present, then the web server is not vulnerable.
Having a correctly configured RewriteRule like the following will prevent the issue.
RewriteRule <regex> <redirect url>
i.e
RewriteRule ^(.*) http://10.40.2.159/$1
Please note the use of the forward slash before $1 in the above correctly configured rule.
The solution does not require firewall changes.
One note on "workaround" and problem I encountered
The workaround ensures whatever comes across in the HTTP GET comes after the server’s domain and is preceded by a "/"
E.g. from example above the RewriteRule changes
Orignial -
RewriteRule ^(.*) http://10.40.2.159$1
Workaround -
RewriteRule ^(.*) http://10.40.2.159/$1
I had an issue about a year ago where the first character in the backreference $1, was a "/" Therefore just adding a "/" without proper regex checks yielded a double "//" in the middle of the url and broke that particular apps functionality.
Using the above example, I added the following regex to strip any leading "/" in backreference $1 and then ensured one and only one "/" comes after the domain and precedes the backreference.
RewriteRule [^\/]+(.+)
http://10.40.2.159/$1
@Jeff: Yes, the solution does not require firewall changes. Only the RewriteRule or ProxyPassMatch directives in apache configuration file (httpd.conf) have to be correctly configured if Apache is set up to be used as a reverse proxy. I updated the workaround to be clearer.
And thank you for the updated regex. For the purpose of the PoC, I had just used the most generic regular expression.
The problem I have is that I know I patched Apache to 2.2.22 and my response header do NOT Contain Apache anywhere, AND to top it all off our rewrite rule is well written in that it forces the "/" as shown in the example workaround.
if I do all of the above, then why am I still getting these fidnings when running a scan?
@Lionel: If you are running a patched server, and also have the rewrite rules configured correctly, I don’t see a reason why a scan should flag it.
Please open up a request with support and I can take a look at the CRM ticket and request further information from you on the scan details and investigate why this could be happening.