Thursday, February 09, 2006

How to crash IE with just 4 levels of recursion in CSS and JavaScript

I can crash your Internet Explorer 6.0 (with all the latest patches) anytime you visit my page, with no warning at all.  Fun stuff.  I'm explaining how to do it here, not so that you can go crashing other people's pages, but so that I have a URL reference to give Microsoft for a bug report, and so that others who run into this bug accidentally (as I did) may have a page to find that explains exactly what is going wrong and how they can workaround it.  This isn't a security hole, as far as I can tell, so I don't think it's unsafe for me to post this.
DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
    <head>
        <link rel="stylesheet" type="text/css" href="1deep.css" />
        <script type="text/javascript" src="css_bug.js">script>
    head>
    <body>
        The CSS and JavaScript will soon crash this page!<br/>
        If you see a scripting warning in IE, let script run.  This 
        warning does NOT come up when this web page is accessed over 
        the Internet (just over your hard drive, ironically!)<br/>
        <input type="button" onclick="alert('CSS depth: ' + discoverCssDepth())" 
            value="Click me to calculate CSS depth (and crash)"/><br/>
        Sometimes IE won't crash immediately after clicking the button.
        You may have to click around, or even close IE, for the crash to occur.
    body>
html>
1deep.css
@import url(2deep.css);
2deep.css
@import url(3deep.css);
3deep.css
@import url(4deep.css);
4deep.css

css_bug.js
function discoverCssDepth(sheet) {
    var maxDepth = 0;
    if( !sheet ) { // if this is the outermost call
        var depth = 0;
        for( var i = 0; i < document.styleSheets.length; i++ ) {
            depth = discoverCssDepth( document.styleSheets[i] );
            if (depth > maxDepth) maxDepth = depth;
        }
        return maxDepth;
    } else {
//        alert('looking at ' + sheet.href);
        maxDepth = 0;
        var depth = 0;
        // Enumerate over subsheets, if any
        if( sheet.imports ) {
//            alert('Has ' + sheet.imports.length + ' sub css files.');
            for( var i = 0; i < sheet.imports.length; i++ ) {
                depth = discoverCssDepth( sheet.imports[i] );
                if (depth > maxDepth) maxDepth = depth;
            }
        } else if (sheet.cssRules) { // Mozilla style
            for( var i = 0; i < sheet.cssRules.length; i++ ) {
                if (sheet.cssRules[i].styleSheet) {
                    depth = discoverCssDepth( sheet.cssRules[i].styleSheet );
                    if (depth > maxDepth) maxDepth = depth;
                }
            }
        }
        return 1+maxDepth;
    }
}
Note that if you try this on your local hard drive, you'll see IE give an Active Scripting warning that you must approve before the code will run and the browser will crash. But over the Internet, the warning does not show up, and the code just executes!

No comments:

Post a Comment