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), " ", 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:
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.
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 :-)
-=-