Proof of Concept for "Apache Httpd Limited cross-site scripting in mod_proxy error page (CVE-2019-10092)"

A few days ago, I came across the Apache Httpd Security Page and read about a XSS issue in mod_proxy. I couldn't find a Proof-of-Concept right away, so I dug into it and finally managed to exploit it.

Citing the security report for CVE-2019-10092:

low: Limited cross-site scripting in mod_proxy error page (CVE-2019-10092)
A limited cross-site scripting issue was reported affecting the mod_proxy error page. An attacker could cause the link on the error page to be malfomed and instead point to a page of their choice. This would only be exploitable where a server was set up with proxying enabled but was misconfigured in such a way that the Proxy Error page was displayed.
We have taken this opportunity to also remove request data from many other in-built error messages. Note however this issue did not affect them directly and their output was already escaped to prevent cross-site scripting attacks.
Acknowledgements: This issue was reported by Matei "Mal" Badanoiu

Reading through the comments in the bugtracker, I found the changeset that was supposed to fix the issue in the svn repo: r1864191. In the file proxy/proxy_util.c there is:

         apr_pstrcat(r->pool,
-            "The proxy server could not handle the request <em><a href=\"",
-            uri, "\">", ap_escape_html(r->pool, r->method), "&nbsp;", uri,
-            "</a></em>.<p>\n"
+            "The proxy server could not handle the request<p>"
             "Reason: <strong>", ap_escape_html(r->pool, message),
             "</strong></p>",
             NULL));

The function ap_escape_html maps to ap_escape_html2 and can be found in the github repo in server/util.c. It replaces instances of <, > and " with their html entity equivalents, so it's not possible to break out of the <a href="[url]">...</a> tag directly.

I thought about exploiting it using different protocols a la javascript:alert(1), but any URL will start with a leading /, so this did not work as you can see below:

test1

A while later I came across a tweet with an interesting approach. The trick is to use a vertical tab (%09) and then place another URL in the tag. So once a victim clicks the link on the error page, she will go somewhere else.

works-1

As you can see, the browser changes the destination from relative / to an absolute url https://enoflag.de. The exploit is http://domain.tld/%09//otherdomain.tld

Here's the httpd configuration to reproduce the behavior:

    <Location />
        ProxyPass http://127.0.0.1:9000/ connectiontimeout=1 timeout=2
        ProxyPassReverse http://127.0.0.1:9000/ 
        Order allow,deny
        Allow from all
    </Location>

Simply open a non-responsive listening socket on port 9000 to emulate a broken proxy (e.g. nc -l -v -p 9000).

UPDATE: There are different configuration issues that will trigger a "ProxyError" in Apache. Here's a small (unexhaustive) list:

A Gateway Error [0] should also work and is only the matter of having KeepAlive On or not. So the module does not necessarily need to wait 300s for a timeout. Here's another one [1]. Configuring frontend/backend SSL wrong might also be an issue [2,3]. Or even application level errors [4]

[0] https://serverfault.com/questions/185894/proxy-error-502-reason-error-reading-from-remote-server-with-apache-2-2-3-de
[1] https://github.com/aio-libs/aiohttp/issues/2687
[2] https://serverfault.com/questions/915002/502-from-apache-over-https-with-reverse-proxy-to-node-server-on-different-port
[3] https://serverfault.com/questions/742850/502-proxy-error-apache-reverse-proxy
[4] https://www.experts-exchange.com/questions/29108337/Apache-proxy-Error-reading-status-line-from-remote-server.html

Hope this helps :-)

-=-