Last month Google awarded our security analyst Luka Treiber a Chromium Security Reward for a high-severity vulnerability fixed in version 16 of the Chrome web browser. Due to Chrome's automatic update mechanism we expect most browsers to be updated by now, which seems to be supported by StatCounter's Global Stats for January 2012, where Chrome 16 is the only Chrome version in the chart. Luka found this issue in Chrome 14 and we confirmed that Chrome 15 was vulnerable as well. This document presents the vulnerability in detail.
HTTPS-related vulnerabilities tend to rate high on the severity scale as they allow attackers to make web site visitors - even the savvy ones who check for HTTPS evidence such as "https://" at the beginning of the URL - believe they are visiting a legitimate web site when they're actually on a malicious look-alike site. And when users trust a malicious web site, they will give it their credentials and personal data.
This bug is a nice addition to some other HTTPS-related vulnerabilities our security researchers have found in the past: bypassing HTTPS security warnings in Internet Explorer and Netscape Navigator (yes, we were breaking HTTPS back in 1999!), and Poisoning Cached HTTPS Documents in Internet Explorer. None of these break the cryptographic model or implementation supporting HTTPS, but rather exploit the integration of SSL/TLS into the browser and browser's presentation of security-relevant information to the user. These are often the weakest link in the security HTTPS is supposed to provide.
Chrome's Trigger-Happy Address Bar
When observing the above code in execution all parts of Chrome's user interface behave consistently, meaning that as the address bar changes from URL of the source page to the target URL, the page content changes accordingly and promptly (at once). However, by altering the script like this:
one can see the address bar starts changing before the displayed page content is replaced. So for a split second the address bar displays the new address http://target while the DOM is still from the old address http://source/sample.html. The given example is composed of two tricks:
- Apparently the "view-source:" prefix causes the asynchronous behavior between the address bar and the DOM.
- The redir.php is an HTTP 302 redirection script used to cause a redirect from view-source:http://source/redir.php to http://target, thus removing the "view-source:" prefix from the URL (the goal is to spoof the address bar to a legitimate domain as will be shown later). After this redirection, the browser no longer displays the source code but renders the HTML of http://target.
All demonstrations provided below employ the above two tricks with http://target replaced by a Gmail login page address. However, to stop the redirection at the exact moment when the inconsistency between the address bar and the page contents is being exhibited, a further trick is used. Each of the three demonstrations employs a different trick to "freeze" the state of inconsistency for a long enough time for a user to enter his credentials.
Demonstration #1: Redirection To HTTPS On Port 80
In the first demonstration, https://proxy.google.com:80/ is used as target of the redir.php script to block the redirection for about 30 seconds. This occurs because Chrome is instructed to establish an HTTPS connection with a server on an HTTP port, which results in a 30-second hopeless handshake attempt between an SSL/TLS client and an HTTP server.
While the redirection using view-source:http://www.acrossecurity.com/redir.php?url=https://proxy.google.com:80/ is being fruitlessly attempted (and Chrome is already showing https://proxy.google.com:80/ in the address bar), a fake Gmail login page is displayed from attacker's web site. If username and password are entered and the submit button is pressed the data gets sent to http://www.acrossecurity.com (the "malicious" web site for the purpose of this blog post). Tests have shown that any unresponsive server script can be used instead of https://proxy.google.com:80, or even an invalid target URL such as view-source:http://xxxxxxxx.
Let's look at a video of this demonstration:
Demonstration #2: Using Google's Open Redirector
In the second demonstration, we avoid the suspicious 80 port in the URL by using some open redirector on https://*.google.com as the desired spoof URL. The demonstration is analogous to the previous one except that an additional redirect is used after the http://www.acrossecurity.com/redir.php script, and that https://proxy.google.com:80 is replaced with a download-throttling page http://www.acrossecurity.com/slow.php that delays the loading for an arbitrary amount of time. This time the URL that the redirection gets stuck on is https://www.google.com/url?q=http://www.acros.si/slow.php[...].
Demonstration #3: Delaying Redirection With A Blocked Modal Dialog
In the third and final demonstration, we manage to spoof the exact URL of the Gmail login page. To do that, a blocked modal dialog is used to stop the redirection instead of the "wrong port trick" with https://proxy.google.com:80 or the download-throttling slow.php employed in the previous demonstrations. A precondition in this case, for whatever reason, is that the user has come to the malicious web site from the spoofed-to-be host (in our case https://accounts.google.com) or another host in its 2nd level domain before address bar spoofing redirection begins. This precondition can easily be fulfilled using any one of the open redirectors on google.com servers.
An intentionally blocked modal dialog (blocked by Chrome's pop-up blocker) is used to stop the redirection after the address bar has already been updated with the new URL but the page content hasn't been refreshed yet. Like in the previous demonstrations, a fake login form is displayed, waiting for the user to provide his credentials. Curiously, any requests resulting from the form submittal are queued while the modal dialog is blocked. We solved this with a self-destruct script inside the modal dialog executing after the submit button has been pressed, thus releasing the said queue and allowing the credentials to be sent to attacker's server.
Let's see how this looks like (notice the blocked dialog icon on the right side of the address bar):
While it would certainly be possible to trick some users into logging in to Gmail (or any other targeted web site) through links provided by a 3rd party malicious web site, most users are likely to visit their favorite web sites directly (by typing the host name) or using browser bookmarks. In this case, as long as the initial URL is non-HTTPS, a man-in-the-middle attacker (i.e., the guy sitting next to you in the coffee shop with free WiFi) can actively inject malicious code into the initial web site's HTML to exploit this vulnerability and present a legitimately-looking fake HTTPS login form to the user.
Finally, the hawk-eyed among you may have noticed that the spoofing is not entirely perfect: the icon left to the spoofed URL is a grey planet as is typical for HTTP addresses - and not a green lock as is typical for valid HTTPS addresses. However, while many users may notice the presence of "https" and consider it a guarantee of trust, they are less likely to notice the absence of a lock icon - especially since the visual identification of HTTPS URLs is different in different web browsers.
So could this vulnerability realistically be used for defeating HTTPS in actual attacks? We think so and so does Google - and we're glad this bug is now fixed. When more and more web sites are depending on the cryptographic security of HTTPS, this bug is a reminder that HTTPS is much more than just cryptography.