Caja hacking
Published 13 years 1 month ago
Published: Thu, 30 Aug 2012 07:32:21 GMT
Updated: Sat, 22 Mar 2025 15:38:19 GMT
Read time: ⏱️ 3 min read
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
- <input name=xyz>
- Cajole
- Enter the following the the url: javascript:alert(xyz)
- 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
- <input id=x name=x><script>document.getElementById('x').name='a___';</script>
- Cajole
- Enter the following the the url: javascript:alert(a___)
- 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.