javascript DoS
Date: October 01, 2006 09:06PM
I was going through the blog archives on ha.ckers, and bumped on this http://ha.ckers.org/blog/20060830/internet-explorer-dos/ regarding some IE DoS.
If the goal is simply to disable the browser, it's remarkably easy to do.
- Every browser runs javascript in a single thread. Netscape did some work that'd have allowed multithreading at some point, but even then a single html document could only use one single thread.
- There are enough UI events that javascript needs to react to synchronously that you can effectively freeze your browser UI by making sure javascript keeps busy.
Now, most browsers also have this defense mechanism that pops up a dialog similar to "A script is taking a long time to run. Kill it?", but those are pretty far from perfect.
They are good enough to catch something as obvious as:
javascript:while(1);
Let's take a quick look at 2 resource eaters here.
We're limiting ourselves to core ecmascript features, as those are (somehwat) guaranteed to work consistently across browsers.
1: String manipulation.
In javascript, every string operation equates a string creation. Not terribly efficient, but usually good enough.
javascript:a='a';while(a+=a);
Same basic loop, but with a new ever growing string creation on each iteration.
On firefox, this stops fairly quickly with an "Out of memory" error, after eating 100MB or so of RAM.
IE keeps going a while longer (longer than my patience anyway), and uses about as much RAM.
javascript:(function t(s){return t(s+s)})('a')
Same concept, but using recursion instead of a loop.
on firefox, same "out of memory" error, same 100MB limit.
on IE, this uses twice as much memory as the earlier version, but triggers an "out of stack space" error fairly quickly.
2: Asynchronous callbacks.
This is a lot better at freezing browsers. The idea is to schedule callbacks at a fast rate, and watch the browser struggle to handle them, leaving behind everything else (like handling UI events)
javascript:(function t(){setTimeout(t,0);setTimeout(t,0)})()
Here, every time t() gets called, 2 asynchronous callbacks to t() are scheduled to run as soon as possible.
on both IE and firefox, this kept the browser frozen longer than I felt like waiting.
Of course, why schedule only 2 callbacks at a time:
javascript:(function t(){while(setTimeout(t,0));})()
Same visible results on both browsers, although this is likely to be a bit more painful to handle.
To conclude, let's combine both resource eaters for maximum effect:
javascript:(function t(s){while(setTimeout(t,0,s))s+=s;})('a')
On firefox, this keeps the CPU at 100%, eats 1GB of RAM on my box (which happens to have 1GB of physical RAM), then swaps like crazy.
on IE, it ends up triggering a "not enough storage to complete an operation" error after eating a bit of RAM, but keeps the CPU usage at 100%.
There are plenty of variations on those techniques, and that's without looking at anything in the DOM yet.
For example, if your resource-wasting code is wrapped in a try{}catch{} block, you may be able to survive some of those errors mentioned above.
Overall it's safe to say that once you run javascript on someone's browser, you can easily deny them the use of their browser, and quite possibly the use of their computer for a little while.