6

Say I have the following code:

var secrets;
Array = function() {
  secrets = this;
};

The author of the above sample says that the code is redefining the Array constructor. First, I am not sure what the this refers to. Can anyone please advise?

Second: would the following code be equivalent?

var secrets;
function Array() {
  secrets = this;
}

By the way the above code is taken from the following article about a Json vulnerability: see here

balteo
  • 20,469
  • 52
  • 196
  • 362
  • 3
    You are asking two questions here. How `this` works is explained [in the MDN documentation](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/this) (in short: the value depends on how the function is called) and whether `Array = function()...` or `function Array()...` are the same is answered [in this question](http://stackoverflow.com/q/336859/218196). – Felix Kling Mar 13 '13 at 12:45
  • thanks Felix. Regarding `this` I have read the documentation but was not able to figure out what `this` refers to **in the above context**... Can you or someonelse please help?? Regarding the second part of my question, I read the post you provided and I better understand now. – balteo Mar 13 '13 at 12:59
  • 1
    If you call `Array` with `new`, then it will refer to an empty object inheriting from `Array.prototype`. If it is called without `new`, it will refer to `window`. If it is called via `.call` or `.apply`, it will refer to the element which is passed as first argument. In order to know how it is called, you have to have a look at `JSON.parse`. – Felix Kling Mar 13 '13 at 13:05
  • @FelixKling: `Array` is not called by `JSON.parse` – Bergi Mar 13 '13 at 13:10
  • @Bergi: I did not expect it does, but obviously something called it, otherwise the exploit wouldn't have worked backed then. I should have said "have a look at whatever is used to parse the JSON (back then)". – Felix Kling Mar 13 '13 at 13:15

2 Answers2

5

In both examples you're defining the variable Array to be a function that assigns this to secrets. It just so happens that there already exists a global object called Array that other JS in the page might or might not use as a Constructor to make arrays. If you pop into your console and re-assign Array to be something else, you might start getting errors from code that explicitly depends on Array. However, arrays made literally with [] continue to work just fine, and in fact, their __proto__ still points to what was Array.prototype. So:

var arr1 = new Array('a','b','c');
// arr[0] -> 'a'

var arr2 = ['d','e','f'];
// arr[0] -> 'd'

var secrets;
Array = function() { secrets = this; };

var arr3 = new Array('g','h','i'); // nothing wrong here, because Array is a function
// arr3[0] -> undefined
// Array is just a function, you can't make arrays with new Array anymore
// and arr3 is just a function


var arr4 = ['j','k','l'];
// arr4[0] -> 'j'
// making array literals still works

as for this, nothing strange, still follows the rules of this. the fact that you're assigning a function to Array doesn't change how this behaves. so this points to the global object which in the browser is window unless you instantiate with new or use call or apply

the difference between both samples is the difference between a function expression and function declaration, see: What is the difference between a function expression vs declaration in Javascript?

Community
  • 1
  • 1
zertosh
  • 5,113
  • 1
  • 15
  • 9
1

Yes, both snippets are equivalent. Both redefine the array constructor, in an attempt to intercept all array data used by the website where it's injected, as explained in the linked article. The value of this is supposed to be the newly constructed array.

This seems to have been allowed by ECMAScript 3, but disallowed by ECMAScript 5, now available on all modern browsers. So the exploit described in the article should no longer work.

bfavaretto
  • 69,385
  • 15
  • 102
  • 145
  • The exploit just does not work any more because standard-conform JSON.parse or literals do not call `Array`. See my answer to http://stackoverflow.com/q/13040367/1048572 – Bergi Mar 13 '13 at 13:13
  • Yes, that's what I meant. Previously something like `eval('[1,2,3]')` would call the redefined constructor. – bfavaretto Mar 13 '13 at 13:16
  • @Glutamat But that's sort of useless, since they won't be actual arrays. `new Array('foo')` will not add 'foo' to index 0 with the redefined constructor. – bfavaretto Mar 13 '13 at 13:28
  • @bfavaretto that wouldn't that only need a slight modifications to the constructor,like defining an array using `[]`,push it to a global var,and return it. sth like [this](http://jsbin.com/ucutuv/1/edit) ? – Moritz Roessler Mar 13 '13 at 13:34
  • @Glutamat In any case, the exploit was related to literal evaluation and json parsing. But you're right, there are ways to overwrite the constructor and get data from arrays created with `new Array`. – bfavaretto Mar 13 '13 at 13:39
  • @bfavaretto I just wonder why it works even with using `'use strict';` I thought ECMAScript 5's strict mode would make things like this safer – Moritz Roessler Mar 13 '13 at 13:47