Caja hacking

As you probably know I love JavaScript sandboxes and I spend a lot of spare time playing around with them on the net. One of them is Google Caja, if you don’t know what it is here is the description from the project “The Caja Compiler is a tool for making third party HTML, CSS and JavaScript safe to embed in your website. It enables rich interaction between the embedding page and the embedded applications. Caja uses an object-capability security model to allow for a wide range of flexible security policies, so that your website can effectively control what embedded third party code can do with user data.” it’s pretty damn good and has been designed by some clever people.

I attempted a full bypass e.g. executed any code by breaking the sandbox. I failed 🙁 but I found a few interesting breaches of the sandbox which I’ll detail here.

DOM Clobbering global variables

The first one is quite simple, on IE and Opera you can clobber global variables by using the “name” attribute. This escapes Caja’s protection of the window object by allowing you to create global variables. You can also create a property of that global variable as long as the element has that property/attribute. For example:


<input name=xyz value=123>

This will clobber a global variable call xyz and a property of “value”. In javascript window.xyz.value will now equal 123. Interestingly Caja doesn’t allow you to use underscore in the name attribute so you can’t create “xyz__” as the name will be removed.

Repro steps
1. <input name=xyz>
2. Cajole
3. Enter the following the the url: javascript:alert(xyz)
4. Result:[object HTMLInputElement]

DOM Clobbering global variables with underscore

We can get round the underscore restriction by using a DOM method to set the name. Setting the “name” attribute via the DOM allows underscores where the HTML parsing would not.


<input id=x name=x>
<script>document.getElementById('x').name='a___';</script>

That results in a global variable called “a___” on Opera and IE.

Repro steps
1. <input id=x name=x><script>document.getElementById(‘x’).name=’a___’;</script>
2. Cajole
3. Enter the following the the url: javascript:alert(a___)
4. Result:[object HTMLInputElement]

arguments without a function

Another minor vulnerability is that Caja assumes there is a function present when you use the arguments object. If you use the arguments object in a script block without the function you get access to create a variable “a___” since arguments is rewritten to that value. You can’t really do anything with it though since you can’t modify arguments or give it interesting properties. To create it you simply have to increment the arguments object without a function for example:


//input
++arguments;alert(arguments);//NaN

//cajoled output from caja
try {
{ ++a___;//makes a global variable called a___ since no arguments object is present
moduleResult___ = (IMPORTS___.alert_v___? IMPORTS___.alert:
___.ri(IMPORTS___, 'alert')).i___(a___);
}

That’s it for now hope you can take this research further or it will inspire you to find other problems.

4 Responses to “Caja hacking”

  1. Mike Stay writes:

    Hey, thanks for attacking Caja! We always appreciate it. One point of correction: you can’t “clobber” global variables using the name property; if a real global exists with that name, then that binding takes precedence. You can introduce apparently new globals into the taming frame with this method, but since all the code that runs in that frame only makes reference to globals that exist by default, they’re harmless.

    You can mask expando properties of form objects, but we haven’t figured out how to mount a real attack that way.

    For discussion of both of these, see issue 1371 here:
    http://code.google.com/p/google-caja/issues/detail?id=1371

    Note that if you *do* get a real attack, it’s eligible for cash through Google’s Vulnerability Rewards Program: http://www.google.com/about/company/rewardprogram.html

  2. AnonLurker writes:

    I don’t think the claim about “DOM Clobbering global variables” is accurate. I think you might want to edit the post to remove that claim, or update it to reflect that it is not accurate.

    The potential risk with NAME=… was reported on the Caja issue tracker in 2008 and fixed within a month. See issue #447:
    https://code.google.com/p/google-caja/issues/detail?id=447

    So, I suggest editing the post to retract the claim that this attack will work against Caja.

  3. Gareth Heyes writes:

    @AnonLurker

    I will be doing no such thing just because you bug states it’s fixed does not make it so. My repro steps clearly indicate that you can create global variables using input elements on IE and Opera.

  4. Gareth Heyes writes:

    @Mike

    By clobbering I mean I can assign a variable to the window object via a DOM element. You prevent access to this in caja and this bypasses this restriction. I know this isn’t directly exploitable and that’s why I blogged it but still it is a breach of your sandbox because sandboxed code shouldn’t be allowed to introduce global variables.