There are several scenarios in which a web application may choose to deliver both HTTP and HTTPS content. It may employ per-page mixed content, it may use HTTP pre-auth and switch to HTTPS post-auth, or it may continually switch back and forth between HTTP and HTTPS depending on the sensitivity or criticality of the functions being performed by the user (i.e. browsing media content vs. making online purchases).
For this post I’ll concentrate on the latter scenario to highlight the importance of proper CSRF token security. To do so, I’ll demonstrate how an attacker can use a man-in-the-middle attack to intercept only HTTP traffic and inject content to force a user to unknowingly execute sensitive functions over HTTPS on their behalf…even if the site uses a CSRF token to protect against request forgery.
In this example we’ll examine the e-commerce craft website Etsy.com*. First, some background on how Etsy access control and session management works. Etsy requires a username/password authentication over HTTPS and upon successful authentication, the user is passed two primary session cookies (also over HTTPS) – one to use for insecure activity over HTTP and the other (marked secure/HttpOnly) to use only for more sensitive functions over HTTPS. Possession of a valid HTTP session cookie will allow you to navigate the insecure portions of Etsy as that user, but will not give you access to the secure functions of the site.
After secure login over HTTPS, the session reverts back to HTTP and the user is presented with the main Etsy page. This page is almost identical to the pre-authentication page except for some extra user functions such as “Your Account”, “Sign Out”, ”Conversations”, etc (see pictures below). At this point, sniffing the HTTP cookie on a public network to hijack a user’s post-login session (and masquerade as that user) is trivial, but since resulting access is limited to only non-sensitive functions, this attack would not be very fruitful.
Any time a secure function such as “Your Account” or “Cart” is selected by the user, the site switches to HTTPS for the remainder of that activity and the secure cookie is required. Secure actions are also verified by the submission of an additional session-based CSRF token/nonce. Here is where the problem lies…the same CSRF token used to validate the secure (HTTPS) functions is also passed in the clear during the user’s HTTP-based activity. So, if we can compromise a user’s HTTP session and grab their CSRF token, we can force them to initiate secure actions on our behalf in an CSRF/OSRF-style attack via MiTM.
In this attack scenario we’re set up on a public wireless network (pick your favorite coffee shop, bookstore, hotel, etc) and sniffing for Etsy.com traffic. The first thing we’ll need is the user’s CSRF token. Because it’s passed during each client-server communication regardless of protocol, we can simply grab it off the wire during an HTTP communication. Remember, if we’re thinking in terms of CSRF/OSRF attacks, we don’t need the user’s session cookies because as long as we pass the required parameters in function calls, we can get the user to unknowingly perform the actions for us and pass their cookies in the process.
Once we’ve captured a valid CSRF nonce and know the source IP of the victim, it’s time to launch the MiTM attack. Here we’ll use ettercap for arp poisoning and forward all port 80 traffic to port 8080 for our intercepting proxy (Burp) to modify the HTTP content.
"]ettercap –i -T –M arp:remote /<victimIP>/ /<gatewayIP>/
"]iptables –i nat –A PREROUTING –p tcp --dport 80 –j REDIRECT --to-port 8080
Recall, for this scenario we’re only intercepting port 80/HTTP traffic. There is no downgrade attack or tricking the user into accepting an invalid certificate. I wanted this scenario to be completely independent of user interaction and demonstrate how a user can be at risk just by accessing a site that incorrectly implements session management over an untrusted network.
So, now that we’ve established a successful MiTM connection and have our CSRF nonce we’re ready to modify the intercepted HTTP responses from Etsy before they’re passed to the user and force them to execute secure functions on our behalf.
There are several secure functions available, so we’ll start with a user’s privacy settings. The settings are pretty straightforward, as illustrated below.
Changing the Privacy settings requires the following three parameters to successfully execute: 1) favorites_setting, 2) findability_setting and 3) _nonce, the latter being the CSRF token we captured earlier (please note I’ve changed the names and values of some of these identifiers). In order to force the user to execute this function on our behalf and change their privacy settings without their knowledge, we’ll embed an iframe into the HTML of the HTTP page they’re browsing using our established MiTM session.
The code could look as follows:
<form name="attackform" id="attackform" style="display:none" method="POST" action="https://www.etsy.com/your/account/privacy">
<input type="text" name="favorites_setting" value="public"/>
<input type="text" name="findability_setting" value="Yes"/>
<input type="text" name="_nonce" value='HIJACKED CSRF NONCE'/>
<iframe name="attackframe" style="display:none" id="attackframe"></iframe>
<XXX onload="loadFrame();"> <!—choose an element/attribute to load the attack Iframe-->
Using Burp Proxy, you can insert this code automatically through the Match and Replace function, placing it on every public page to ensure it executes or just on one page of your choosing. Since the execution of this “secure” function is done via the hidden iframe, the user won’t see any of this activity but unbeknownst to them, we’ve just changed their privacy settings to the least restrictive.
This attack isn’t limited to just the Privacy settings page. The conversations function of Etsy allows a user to send messages to other users over HTTPS. Once again, because it relies on the tainted CSRF token value for validation, we can exploit this function in the same manner. Aside from changing the action attribute of the hidden form and inserting the correct input parameters, the attack is nearly identical and the result is a message sent by the attacker from the unsuspecting user’s account to an Etsy recipient of their choosing.
Granted the opportunity for this attack limited as it requires the compromise of a user’s active session using MitM. However, it demonstrates that despite the use of a CSRF nonce and HTTPS to protect sensitive functions, an application can still be vulnerable to an CSRF-style attack if it fails to handle the nonce securely. It’s also interesting because from a user’s perspective even if they verify the use of HTTPS for secure functions and know enough not to accept unknown SSL certificates, they can still fall victim to this attack. So what can be done to prevent this scenario (aside from implementing HTTPS for all pages/functions)?
The responsibility for prevention primarily falls on the application developer. Regardless of where users access the site from (home, coffee shop, etc), they generally expect the application to appropriately secure sensitive, post-authentication functions if they see HTTPS in use. Though not all vulnerabilities can be prevented by securing the web application, developers should still consider all attacks that could occur between the user and the web application (including network-related vulnerabilities such as MiTM) and apply any reasonable prevention measures.
First, consider all data passed over HTTP to be tainted. Any data element that is to be used as an authenticator for secure site functions must be handled and protected appropriately. If a site must use both HTTP and HTTPS, consider implementing separate CSRF tokens for the sensitive functions. For example, Etsy could issue a separate secure CSRF token and protect it in the same manner as its secure session cookie by only passing it over HTTPS. For very sensitive functions, consider using per-request (vs per session) CSRF tokens to limit the attack scope should a token be compromised.
Also consider checking the Referer header and rejecting any request that does not originate from a valid page as it relates to the logic flow of the application. For example, the attack against the user’s Privacy settings illustrated above originated from an insecure HTTP page of the Etsy site (http://www.etsy.com/?ref=si_home). Under normal use, this function should only ever be executed from the SSL-protected Privacy Account settings page (https://www.etsy.com/your/account/privacy) and anything else should indicate an unauthorized request.
There are other prevention mechanisms that may be appropriate (such as challenge-response), depending on the application. OWASP’s site (www.owasp.org), specifically the prevention cheat sheets, is a great starting resource for developers to learn more.
Application users should access sites that mix HTTP and HTTPS over public networks with caution. On a public or untrusted network, expect all HTTP traffic to be at risk of disclosure. As illustrated in the example above, unless you are certain of the security of a given site, you should be careful about using the sensitive functionality on an untrusted network, even if it does appear to be protected with HTTPS.
* Please note that I reported these issues to Etsy under its bug bounty program responsible reporting guidelines but was informed that because it required the use of a man-in-the-middle attack, it was not considered a qualifying vulnerability. Nevertheless, I think the scenario warrants demonstration so developers understand the dangers of improperly implemented session security and users understand the inherent risks of using sites that serve both HTTP and HTTPS content if they have not been designed properly.