Bug 4501 - Host of Troubles: General HTTP Cache Poisoning Attack against Squid
Summary: Host of Troubles: General HTTP Cache Poisoning Attack against Squid
Status: RESOLVED FIXED
Alias: None
Product: Squid
Classification: Unclassified
Component: other (show other bugs)
Version: 3.4
Hardware: All All
: P5 blocker
Assignee: SQUID BUGS ALIAS
URL:
Depends on:
Blocks:
 
Reported: 2016-04-22 08:32 UTC by Jianjun Chen
Modified: 2016-07-27 11:46 UTC (History)
3 users (show)

See Also:
Browser: ---
Fixed Versions: 4.0.10, 3.5.18
Needs:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jianjun Chen 2016-04-22 08:32:25 UTC
Hi,

I'm a PhD student from Tsinghua University.

Recently We have discovered a new systemic vulnerability, which we called “Host of Troubles”. The problem is that deployed systems are generally incorrect (non-compliant with RFC 7230) and inconsistent in parsing and interpreting “Host” headers in HTTP requests. This problem can be exploited by carefully crafting HTTP requests with ambiguous host information, inducing inconsistent interpretations between two parties, with varying consequences depending on the scenario. One of the exploits we found is HTTP cache poisoning attack against Squid.

The attack, which we have demonstrated for Squid-3.5.12, enables cache poisoning of ANY unencrypted HTTP website. The scenario requires an attacker who can send HTTP requests that pass through a shared transparent cache (Squid-3.5.12), “attack.com” controlled by the attacker, and “victim.com” as the victim site.  Note that attackers can readily obtain the necessary vantage point using techniques such as web ads.

The attacker first establishes a TCP connection to the HTTP server at “attack.com”.  Since the Squid proxy operates in a transparent fashion, it intercepts and mediates this connection.  The attacker then issues an HTTP request over this connection:

GET http://victim.com/ HTTP/1.1
Host: attack.com 

Squid-3.5.12 identifies the request as going to “victim.com”.  When it inspects the destination IP address for consistency, however, it mistakenly checks it against  the value of the Host header, “attack.com”, rather than “vicitim.com”.  Thus, the proxy directly passes the request to the “attack.com” server, but caches the (malicious) reply the server returns as a resource of “victim.com”.
  
Note that this attacks can be carried out remotely, e.g., by using Flash advertisements. This attack have a significant impact in the current Internet, since Squid has been widely deployed as transparent caches by ISPs.

Here is the Demo Video, https://drive.google.com/file/d/0ByM36MBckzBaQUFES0VYRlZydUE/view?usp=sharing


Thanks,
Jianjun Chen
Comment 1 Amos Jeffries 2016-04-22 11:34:26 UTC
The attack you describe was assigned CVE-2009-0801 some years back.

However, the use of absolute-URL in the request-target means this is a explicit-proxy request. Commonly seen when intercepting traffic between two proxies. The Host header is redundant on such messages and should be ignored by Squid unless the administrator configures "host_verify_strict on" - in which case the Host verification is done and should reject the request.

Unfortunately the prevalence of complete garbage in Host headers in real world Internet traffic prevents us enabling that strict configuration by default.

You should find that the request outbound from Squid contains the header "Host: victim.com". If configured to act transparently (client_dst_passthru on) the request should be passed to the proxy whose IP was in the TCP connection. Otherwise to one of the IPs in DNS for victim.com.

There is nothing we can do if the destination proxy is malicious except advise to use the host_verify_strict configuration.
Comment 2 Jianjun Chen 2016-04-22 12:50:45 UTC
Hi Amos,

Thank you for your quick reply. 

This attack is different from CVE-2009-0801 in both principle and consequence. 

CVE-2009-0801 shows that it's incorrect for intercept proxies only rely on Host header to relay requests, and the consequence is client IP abuse and partial SOP bypass.  As you mentioned, this CVE has been fixed since version 3.3. In Squid 3.5, Squid uses IP address to determine the forwarding destination, and check whether Host header match IP before cache responses. And I think it's a good solution to fix this CVE.

However, this attack is caused by the inconsistency between routing verification module and caching module in Squid 3.5.  The caching module use host in request line(victim.com) for caching key, but the verification module use Host header(attack.com) to check the inconsistency between Host and IP.  This inconsistency results in caching attack's content for victim's website.

To address this problem, Squid should use identical host to verify the match and cache responses. If Squid uses host in request line(not Host header) to verify whether Host matches IP, this attack will be prevented.

Thanks,
Jianjun Chen
Comment 3 Amos Jeffries 2016-04-25 02:19:54 UTC
Okay. I'll grant the old CVE was talking about Host as destination, this is about Host as the incorrect thing to verify against. I think I've also found the place we need to modify to fix this.

Have you applied for a CVE yet? or do you wish me to do so since this is already been made public by this bug report?

NP: marking as a 3.2 bug since it was introduced there with the original Host verify patching.
Comment 4 Jianjun Chen 2016-04-25 02:28:34 UTC
Hi Amos,

Thank you for your assistance.

We haven't applied for a CVE yet. We wish to have a CVE.Thank you for you help.

BTW, do you accept and fix similar vulnerability before version 3.2?

Thanks,
Jianjun Chen
Comment 5 Amos Jeffries 2016-05-02 15:21:57 UTC
Fix applied to Squid-4 and 3.5.
Comment 6 Amos Jeffries 2016-05-09 13:31:04 UTC
Fix applied to 3.4 also.
Comment 7 Mark Ziesemer 2016-05-22 14:47:29 UTC
Do I assume correctly that this is http://www.squid-cache.org/Advisories/SQUID-2016_8.txt and http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4554 ?

Squid 3.3 is still the most recent version packaged by the most recent versions of Enterprise Linux (Red Hat Enterprise Linux, CentOS, Oracle Linux, etc.) - and I don't see that an updated package has yet been released to address this yet.

> $ cat /etc/centos-release
> CentOS Linux release 7.2.1511 (Core)
> 
> $ rpm -q squid
> squid-3.3.8-26.el7.x86_64
>
> $ rpm -q --changelog squid | head -n1
> * Wed Oct 14 2015 Luboš Uhliarik <luhliari@redhat.com> - 7:3.3.8-26

I could attempt to raise this with them directly, but would like to please first confirm the correlation of the above details here.
Comment 8 Mark Ziesemer 2016-05-22 14:56:37 UTC
Confirming myself, and re-closing.  Cross-linking for anyone else that may be inquiring as to the same:

- https://access.redhat.com/security/cve/cve-2016-4554
- https://bugzilla.redhat.com/show_bug.cgi?id=1334241
Comment 9 Alexius 2016-06-08 07:12:30 UTC
May be, the fix in http://bazaar.launchpad.net/~squid/squid/3.4/revision/13240 is not OK, because the Host header line has to be first in the (output) list.

Is here an "update" function available instead of "delById" + "putStr"?

Thanks!
Comment 10 Alexius 2016-06-08 07:33:37 UTC
PS: we have this behaviour on centos 7:

$ rpm -qa | grep squid
> squid-3.3.8-26.el7_2.3.x86_64
Comment 11 Amos Jeffries 2016-06-08 08:19:02 UTC
(In reply to Alexius from comment #9)
> May be, the fix in
> http://bazaar.launchpad.net/~squid/squid/3.4/revision/13240 is not OK,
> because the Host header line has to be first in the (output) list.
> 

There is no such requirement.  RFC 7230 section-5.4 simply states that it SHOULD be *one of the first*. Violating a SHOULD is acceptible with reason. In this case the reason is several CVE's. Which should not be a problem for already outdated and deprecated versions of Squid.

Patches updating Host order relative to other headers are welcome, but are not relevant to this bug being resolved.


> Is here an "update" function available instead of "delById" + "putStr"?
> 

Not one that is usable for this bug.
Comment 12 Adam Majer 2016-07-27 08:06:04 UTC
Is this really fixed? There is two parts to this bug. The cache poisoning, which appears fixed. But second is the ACL bypass, which does not appear to be fixed.

   acl okacl dstdomain e132.somedomain.de
   http_access deny !okacl

then

   curl -H 'Host: e132.somedomain.de' http://anotherdomain.de

Then the proxy happily passes this request to anotherdomain.de server bypassing the ACL.
Comment 13 Adam Majer 2016-07-27 08:19:28 UTC
Just to add, in the ACL bypass case, the logs are showing request to the Host: based domain but with ORIGINAL_IP set to resolved address of the original URL.
Comment 14 Amos Jeffries 2016-07-27 11:46:42 UTC
Yes this really is fixed. The given curl comman does not send absolute-URL over port 80. Which you can see by adding '-v' to it. What Squid receives in your test is a simple request for "e132.somedomain.de" (which is *not-denied* by your ACL), but going to a wrong IP address.

curl appears not to provide any way to force the problem request to happen either. To replicate this issue accurately use:
 squidclient -p 80 -h example.com -j 132.somedomain.de http://example.com/