+------ | Update 2004-01-05: You may read _much_ more in my newly published | book: "Innocent Code: A Security Wake-up Call for Web Programmers" | http://innocentcode.thathost.com/ +------ Client-side Trojans (or "Browsial Engineering"?) ================================================= Sverre H. Huseby shh@thathost.com 2001-11-03, updated 2002-06-28 Original: http://shh.thathost.com/text/client-side-trojans.txt In May 2000, when the Web was 10 years old or so, Jim Fulton in the Zope application server community started focusing on a very simple, but rather scary security issue. The problem is that an attacker may be able to fool other users into doing things they never intended to do just by sending them a mail or pointing them to a web page. The Zope people named the problem "Client-side Trojans", a somewhat confusing term. This text will try to explain the problem, and suggest a solution to it. Examples -------- The problem is most easily described using examples. Before talking about online banks (yes, it works there too), we start with something more simple. Imagine a voting web site allowing users to choose among different alternatives in order to collect statistics. The voting web page may contain the following HTML:
Alternative 1
Alternative 2
:
Since the form uses the GET method, users voting will visit URLs like this when they submit the form: http://www.example.com/vote.asp?alt=2 Now, what stops an attacker from copying the above URL and mailing it to lots of people, telling them it links to a cool game, nude women, horrible news, funny joke or whatever is needed to mislead people into following the link? Nothing stops him. If several of the targeted people follow the link, they all give a vote after the attackers liking, and the statistics get all wrong. You may have several objections to this example. First, you may say that many users will not follow a link like that because it looks suspicious. That's no problem. The attacker may use redirection to hide the URL from more advanced users. Instead of pointing directly to the voting site, he points to a page on eg. his own server: http://www.badguy.com/nicejoke.html Of course the nicejoke.html page doesn't contain any jokes, contrary to what the user probably expects. Instead it contains the following HTML: Once browsers read the meta tag, they redirect their attention to the voting URL before the user knows what was happening. The same could have been accomplished using a script or a Location header. Using a GET request is, as some people know, wrong in this situation. And that's probably your second objection. According to RFC 2616 which defines HTTP, one should use POST requests when the action has side effects. And using POST will make it impossible to encode the voting details in a URL, as parameters in a POST requests are hidden in the request itself. But that doesn't stop the attacker from reaching his goal. Instead of tricking browsers into visiting the above URL, he tricks them into viewing an auto-posting form:
The form, which was given the name "f", contains a hidden field in which the "alt" parameter is already set to the attackers choice. Below the form is a small JavaScript. The script actually submits the form, just as if the user had pressed the non existing submit button. The bad guy may insert this code in a web page and trick users into visiting it. Before they know it, they have given their vote. An even fancier approach is to embed the above form in an HTML encoded mail. Several popular mail clients are capable of viewing HTML mails, and they will even execute the JavaScript code. Unfortunate users may thus give their (or rather: the attacker's) vote by just reading their mail, or even without reading the mail if the mail program automatically previews incoming messages. (For advanced readers: Microsoft Outlook utilizes an Internet Explorer (MSIE) component when rendering HTML encoded E-mails. Testing on Windows 2000 by the author shows that the MSIE instance used by Outlook shares everything with an already open MSIE, including session cookies. You should keep that in mind when we come to online banks below, as it paves the way for some cool remote control E-mails. (Fortunately, the newer Windows XP defaults to not running scripts embedded in HTML encoded E-mails. (At least not the kind of script inclusion i tested. (Whee! Four levels of parentheses! And this isn't even Lisp.)))) So far, we've been looking at a toy-like voting application. What's really scary with Client-side Trojans is that they work with authentication too. As these trojans function by tricking a user or his browser into visiting a site, things will be done on behalf of the user if he is already logged in to the target site. Let's say that a user is logged in to his online bank. If a bad guy wants to get rich on behalf of that user, all he needs to do may be to fool the user into viewing this in his browser:
Now if the victim is already logged in to the bank, and the bank accepts that kind of forms (oh yes, several banks I know of do), the user will unintentionally transfer some money to the attacker. Or to someone the attacker wants to give trouble with the authorities. For this to work, one will have to reach the victim while he is logged in to the target site. Sometimes that is quite easy: If the user has clicked a "remember me" option, he will always be logged in. Likewise if the target site is an intranet solution based on domain authentication (such as NTLM on a Microsoft IIS). But banks and other "serious" sites do, (un)fortunately, not offer auto-authentication. If the user isn't always logged in, the attacker will somehow have to make sure the victim is signed on to the target site before tricking him into viewing the malicious HTML. For a site where the user may add content, eg. a discussion forum, that may be easy: Just add a very tempting note, asking people to take a look at a link. In many cases, however, the attacker will not be able to insert messages on the target web site. He'll have to take other measures. Social Engineering to the rescue! Let's say the target site is our bank named bank.example.com, and that the attacker wants to trick a user into viewing the above mentioned money-transfer form after logging in. The bad-guy may send the victim a mail that appears to come from the bank: To: victim From: security@bank.example.com Subject: Emergency: please read immediately! Dear John Doe Due to recent issues, we kindly ask you to help us check your account. Please immediately log in to your account. Once logged in, click on this link and follow the instructions: http://bank.example.com@167772161/check.html Sincerely, Cliff Johnson, Chief Security Officer at Example Bank Inc. Most users will think the included URL points to the bank's web server, but it doesn't. Using the at-sign, this URL actually tells the browser to connect to the site 167772161 with a user name of bank.example.com. The long number is the attacker's IP address 10.0.0.1 encoded as a single 32-bit integer, and check.html is a page containing the HTML that automatically posts the transfer request. If the victim took the bait, the attacker suddenly got rich. Some banks require a two-step process for performing a money transfer. In the first step, you give all the details. Source and destination accounts, amount, due date, etc. All information is temporarily stored in the user's session. Following information gathering, they require a confirmation step in which the user is asked to accept the details as correct. Please do not think that these banks are automatically more secure than the others when it comes to Client-side Trojans. Depending on how the confirmation step is implemented, these sites may be tricked just as easily as the one-step sites: Make the victim browse a site containing frames, one frame for each step: The info.html file contains an auto-posting form that fills in the details. And confirm.html contains a script that posts the confirmation page, with a suitable delay, to make sure it reaches the server after info.html. And that's it, as long as no secrets need to be shared among the two forms. Whatever method the attacker chooses, the victim will be able to understand that something fishy is going on once he sees the page generated by the money transfer. Hiding that page is just a matter of embedding it in a frame that is so tiny that the user won't notice it, and put some fake information in another frame. Or alternatively, if the target site lacks HTML output sanitizing somewhere, using Cross-site Scripting to immediately redirect the browser to another page once the transfer is complete. The Problem ----------- Most current web sites, including banks, shops, discussion sites, and whatnot are vulnerable to some kind of Client-side Trojan trickery, as they lack protective mechanisms. To see how to design a web solution that is not vulnerable, we need to understand the problem. When someone browses our site, we typically generate web pages that contain URLs and forms offering the user to do something towards our web. Client-side Trojans work because it is possible for attackers to give victims these offers on our behalf. To avoid the threat, we need to make sure the action a user takes really is based on an offer we once gave him, rather than on an offer given to him by someone else. Many developers think that the Referer header is a good thing to check to make sure the visitor came from our site. In general, Referer header shouldn't be used for security, as it comes from the client side. But in the Client-side Trojan case it could have been useful, if it wasn't for the fact that many filter it out for privacy reasons. Referer headers are thus often missing in totally legitimate requests, so we need to find a method that doesn't include checking it. An approach that would work, would be to require reauthentication of the user for every action that changes something. This solution includes adding a password field to every form presented to the client. Unfortunately, giving passwords all the time is cumbersome, so we'll try a different approach. A Solution ---------- To protect against Client-side Trojans, developers should implement a "ticket system". Central to this system are non predictable, random numbers, called tickets. It works like this: * A web page may typically contain one or more offers to do an action that has side effects. For each such offer, generate a unique, random string, and associate it with the offer: If the offer is a form, include the ticket as a hidden field. If the offer is a link, append the ticket to the list of URL parameters. * For each ticket generated, add a string naming the action it refers to, and store the string in a "ticket pool" in the session of the user who receives the offer. If the action in question is to eg. confirm deletion of a note numbered 1234, and the ticket is represented as "c90624gHu", the string to store could be "delnote-1234-c90624gHu". We now have the same ticket on both the client side and the server side. * Whenever a request to perform an action arrives from the user, extract the ticket from the request. Then prepend the name of the action that is about to be performed, and look for a match in the session ticket pool. If a matching ticket is found, you know that the offer was given by your web site. In that case, perform the action, and remove the ticket from the pool. The ticket system works because attackers will not be able to guess what ticket values you may have given to the user, and they will not be able to insert tickets into the victim's ticket pool on the server side. There are, however, a couple of gotchas. First of all, if you include the tickets in GET requests, so that they become part of URLs, you risk ticket leakage thru Referer headers if the user follows a link from your site to other web servers. Referer leakage will also occur if your web page includes images or other objects from foreign sites. If you use unique tickets, and remember to remove the ticket from the pool at the end of a request, this should not be a problem. GET requests shouldn't be used for actions which change data anyway, so there's actually no need for tickets in such requests. Also, the system will break if your application is vulnerable to Cross-site Scripting. If an attacker is able to insert JavaScript in a page generated by your server, he will be able to extract tickets from the page. And he may also be able to trick a browser into doing the two step process of first requesting a ticket, and then using it without user intervention. As you can see, to protect against Client-side Trojans, you will need to do some extra programming. And you will need to think. Web development thus becomes a little more challenging, and a little less boring. Summary ------- Attackers may give their victims offers on behalf of a target web site and thereby trick them into doing something they never intended to do. The offers may be URLs or auto-submitting forms, and they may be given through any channel available, such as mails and web pages outside of the target site. To protect a web site and it's users from these Client-side Trojans, web developers will need to implement special security mechanisms. As of this writing, such mechanisms are not commonly in use, making lots of web sites vulnerable. Appendix: Sending HTML Encoded E-mails with Forged Sender Address ----------------------------------------------------------------- Forging the sender address of an E-mail is one of the oldest tricks in the book. And sending HTML formatted mail is no problem at all. Some mail clients support both forging and HTML encoding natively. If you lack access to a program that supports it, just telnet to the victim's mail server at port 25 (or write a program to do it for you), and issue the following lines, which include both a false sender and HTML encoded contents: HELO www.badguy.com MAIL FROM:st.claus@northpole.com RCPT TO:victim@example.com DATA From: st.claus@northpole.com To: victim@example.com Subject: Cool joke MIME-Version: 1.0 Content-Type: text/html
. QUIT HELO, MAIL FROM, RCPT TO, DATA, the single dot and QUIT are SMTP commands understood by the mail server. The rest is the content of the mail including the headers. The Content-Type header indicates that this mail contains HTML rather than plain text. Links ----- * The Zope discussion on Client-side Trojans http://www.zope.org/Members/jim/ZopeSecurity/ClientSideTrojan * RFC 2616, "Hypertext Transfer Protocol -- HTTP/1.1" http://www.ietf.org/rfc/rfc2616.txt * RFC 821, "Simple Mail Transfer Protocol" http://www.ietf.org/rfc/rfc0821.txt