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.