Tuesday, April 3, 2007

Are 130 byte enought to solve JavaScript JSON Hijacking problems? (Unlikely not this time)

This is the second time I open this post because I didn't do a good debug but my solution, a sort of personal brainstorming, was good enough to open one more time this post after few changes :)

This is my proposal:

(function(m){function $(c,t){t=c[m];delete c[m];try{eval(""+c)}catch(e){c[m]=t;return 1}};return $(Array)&&$(Object)})("toString")

exactly 130 byte to solve (I suppose) Array and Object modified constructor problems.

(function(m){function $(c,t){t=c[m];delete c[m];try{new(function(){}).constructor("",""+c)}catch(e){c[m]=t;return 1}};return $(Array)&&$(Object)})("toString")

exactly 158 byte to solve (I suppose) Array and Object modified constructor problems.

Let me explain this function concept.

Step 1 - There's no way to know if a constructor is native
This is the first problem, we can't believe on a generic object constructor for, at least, these two reason:

  1. a constructor, as I wrote on MDC too, is not read only

  2. there isn't any official method to know if a part of code is native or not, and if it is implemented, it should be changed by malicious arbitrary code

Since a constructor should be redefined in some browser (first of all, FireFox)
function Array(){ /*doStuff*/ };

is really hard to know if this new constructor is native code or not.
You could create a new original, empty, scope (using for example an iframe), then You can check if a variable constructor, in this new scope, is equal to original one, for example, a generic Array in a generic window.
The only way to know if a constructor was inherited from JavaScript core is its string rappresentation, usually something like:

function Array() {
[native code]

This is a common native code string rappresentation, but as You know JavaScript is object oriented and every object has a native toString method that should be override/overwite as every other public method.

function Array(){};
Array.toString = function(){
return "function Array(){\n\t[native code]\n}"


This means that we can't believe on string rappresentation too ... and that's why I thought about next step.

Step 2 - native code cannot be evaluated
The uniq way to know if a method or a constructor is inherited from JavaScript core is the "[native code]" string inside its string value.
At the same time You can't evaluate a native code because it isn't a replicable JavaScript code, so a try...catch like this one should be a trick to know if code is native or not because in this last case it will not make code executable:

function isNativeCode(methodOrConstructor){
var result = false;
catch(e){result = true};
return result;

isNativeCode(Array), // true
isNativeCode(String.replace), // true
isNativeCode((1).constructor), // true
isNativeCode(function(){}) // false

As I said, overwriting toString method should produce a sort of native code simply and quickly:

function Mine(){};
Mine.toString = function(){
return "[native code]"

alert(isNativeCode(Mine)); // true

This is the reason I thought about next final step.

Step 3 - enumerable methods should be deleted!
At this point, the biggest problem is the ability to reply native code string, using for example a toString method.
Is it possible to solve? Likely sure, using a delete keyword!

function Array(){};
Array.toString = function(){
return "I'm an Array";

alert(Array); // I'm an Array

delete Array.toString;

alert(Array); // function Array(){\n}

Amazing, I can remove arbitrary toString method to know original value ... but does delete work without problems with native constructor too? Of course, it's on core ;)

// function Array(){\n\t[native code]\n}

delete Array.toString;

// function Array(){\n\t[native code]\n}

Well done ... but this should be quite obtrusive because some library (or some developer) should redefine toString method for its scope ... that's why I decieded to assign one more time toString method, after deleting them, obviously ... and this is my first proposal, with details:

// anonymous private scope function, accept one argument

// private useful dollar function
// accepts 2 arguments, one for constructor
// and one for lazy programming
function $(c,t){

// second argument is used to save old toString method

// delete removes constructor toString
delete c[m];

// check if constructor contains native code
// (not usable, not evaluable)

// if eval fails, constructor contains
// [native code]

// so I can add safely old toString method
// (is not a problem if it is native or not)

// and return a "true" value
return 1

// at this point I just need to call
// my dollar function to know
// if Array and Object are native constructors
return $(Array)&&$(Object)
// for size reasons, I send toString method name
// using "m" var multiple times inside function

How to use this runtime private scope function?
This is just an example that should be used before every JSONString to value convertion:

if((function(m){function $(c,t){t=c[m];delete c[m];try{eval(""+c)}catch(e){c[m]=t;return 1}};return $(Array)&&$(Object)})("toString"))
alert("I can decode a JSON string");
alert("JSON decoding is corrupted");

And that's all folks, You can view a basic example in this page and a failed hack example in this one.

Finally, this inline function should work with every Ajax ready browser, successfully tested on IE 5, 5.5, 6, 7, FireFox 1, 1.5, 2 and Opera 8, 9.

I'm waiting for Safari 1 or 2 behaviour, as konqueror or other browsers (but I'm quite sure, this time this proposal should work correctly).

If You find a way to crack this solution, please tell me (us) :D

Update - 04/04/2007
This is a revisited version dedicated for XMLHttpRequest native object

if((function(c,m,t){t=c[m];delete c[m];if(/^\[XMLHttpRequest\]$/.test(c)){c[m]=t;return 1}})(XMLHttpRequest,"toString"))
alert("Valid XMLHttpRequest");
alert("XMLHttpRequest is corrupted");

Same concept, same logic ... and should be as secure as first proposal for Array and Object constructors.

Try them:

function XMLHttpRequest(){};
XMLHttpRequest.toString = function(){
return "[XMLHttpRequest]"
XMLHttpRequest.constructor = Object;

if((function(c,m,t){t=c[m];delete c[m];if(/^\[XMLHttpRequest\]$/.test(c)){c[m]=t;return 1}})(XMLHttpRequest,"toString"))
alert("Valid XMLHttpRequest");
alert("XMLHttpRequest is corrupted");

Update - 04/04/2007
Do You worry about eval?

if(eval === (new function(){}).eval)
alert("OK eval");
alert("eval is corrupted");

And now we just need to pray that deprecated object.eval will survive for some year :D

Instant Update - 04/04/2007
damn ... Object.prototype.eval should redefine generic object eval method ... uhm, please let me think about a solution and sorry for precedent update.

Update - 05/04/2007
kentaromiura gives me a nice idea ... He wrote them next post.
Function can eval() code in a safe way.
You can redefine Function itself but in this case native behaviour will be lost so I suppose this should be the better way to be sure that code evaluation and Array/Object constructors are not modified.

var result, code = '[1,2,3]';
if((function(m){function $(c,t){t=c[m];delete c[m];try{new Function("",c)}catch(e){c[m]=t;return 1}};return $(Array)&&$(Object)})("toString"))
result = new Function("","return "+code)();

Is this the securest way, for JavaScript, to know if code has been cracked?

Instant Update
no man ...
function Function(a,b){
// Array = function(){} ...
eval("function f(){"+b+"}");
return f;

alert(new Function("","return [1,2,3]")());


Important Update - 05/04/2007
I found a way to solve eval problems, look here to know more.
This is the last version, it should be the best way to know if Array and / or Object were cracked.

function Array(){};
Array.toString = function(){
return "function Array(){\n\t[native code]\n}"

(function(m){function $(c,t){t=c[m];delete c[m];try{new(function(){}).constructor("",""+c)}catch(e){c[m]=t;return 1}};return $(Array)&&$(Object)})("toString")
alert("Array and Object constructors are OK");
alert("Corrupted Array and Object constructor");

With this concept I should be shure that XMLHttpRequest object is native and not re-defined.

Here You can read my last proposal for XMLHttpRequest check:

if((function(x,c,m,t){t=x[m];delete x[m];if(new(function(){})[c]("c","return ("+x+")[c]!==(function(){})[c]")(c)){x[m]=t;return 1}})(XMLHttpRequest,"constructor","toString"))
alert("XMLHttpRequest is OK");
alert("XMLHttpRequest is Corrupted");

It seems to be safe as function(){} code evaluation is.
If XMLHttpRequest is not native, it's a function and removing, using delete, its toString method, it should be a constructor and a constructor has a function(){} constructor, isn't right?

No comments:

Post a Comment