Skip to content

Commit

Permalink
Merge pull request #17 from inikulin/sec
Browse files Browse the repository at this point in the history
fix: Avoid RCE when deserialising TypedArrays [closes #16][part of #12]
  • Loading branch information
AndreyBelym authored May 17, 2021
2 parents 8eb0892 + d9c1cdd commit 2c62624
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 26 deletions.
50 changes: 26 additions & 24 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,29 @@ var GLOBAL = (function getGlobal () {
return savedEval('this');
})();

var ARRAY_BUFFER_SUPPORTED = typeof ArrayBuffer === 'function';
var MAP_SUPPORTED = typeof Map === 'function';
var SET_SUPPORTED = typeof Set === 'function';

var TYPED_ARRAY_CTORS = [
'Int8Array',
'Uint8Array',
'Uint8ClampedArray',
'Int16Array',
'Uint16Array',
'Int32Array',
'Uint32Array',
'Float32Array',
'Float64Array'
];
var TYPED_ARRAY_CTORS = {
'Int8Array': Int8Array,
'Uint8Array': Uint8Array,
'Uint8ClampedArray': Uint8ClampedArray,
'Int16Array': Int16Array,
'Uint16Array': Uint16Array,
'Int32Array': Int32Array,
'Uint32Array': Uint32Array,
'Float32Array': Float32Array,
'Float64Array': Float64Array
};

function isFunction (value) {
return typeof value === 'function';
}

var ARRAY_BUFFER_SUPPORTED = isFunction(ArrayBuffer);
var MAP_SUPPORTED = isFunction(Map);
var SET_SUPPORTED = isFunction(Set);

var TYPED_ARRAY_SUPPORTED = function (typeName) {
return isFunction(TYPED_ARRAY_CTORS[typeName]);
};

// Saved proto functions
var arrSlice = Array.prototype.slice;
Expand Down Expand Up @@ -410,14 +417,9 @@ var builtInTransforms = [
type: '[[TypedArray]]',

shouldTransform: function (type, val) {
for (var i = 0; i < TYPED_ARRAY_CTORS.length; i++) {
var ctorName = TYPED_ARRAY_CTORS[i];

if (typeof GLOBAL[ctorName] === 'function' && val instanceof GLOBAL[ctorName])
return true;
}

return false;
return Object.keys(TYPED_ARRAY_CTORS).some(function (ctorName) {
return TYPED_ARRAY_SUPPORTED(ctorName) && val instanceof TYPED_ARRAY_CTORS[ctorName];
});
},

toSerializable: function (arr) {
Expand All @@ -428,7 +430,7 @@ var builtInTransforms = [
},

fromSerializable: function (val) {
return typeof GLOBAL[val.ctorName] === 'function' ? new GLOBAL[val.ctorName](val.arr) : val.arr;
return TYPED_ARRAY_SUPPORTED(val.ctorName) ? new TYPED_ARRAY_CTORS[val.ctorName](val.arr) : val.arr;
}
},

Expand Down
46 changes: 46 additions & 0 deletions test/helpers/gh-16.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
const TICK_COUNT = 3;

function evilFunction () {
global.evilFlag = true;
}

function makeIIFE (code) {
return `(${code})()`;
}

function waitTick () {
return new Promise(resolve => setTimeout(resolve));
}

function waitSomeTicks (tickCount) {
let chain = Promise.resolve();

for (let i = 0; i < tickCount; i++)
chain = chain.then(waitTick);

return chain;
}

module.exports.vulnerableData = JSON.stringify([{
'@t': '[[TypedArray]]',

'data': {
'ctorName': 'setTimeout',

'arr': {
'@t': '[[TypedArray]]',

'data': {
'ctorName': 'Function',
'arr': makeIIFE(evilFunction.toString())
}
}
}
}]);

module.exports.checkIfBroken = function () {
return waitSomeTicks(TICK_COUNT)
.then(function () {
return !!global.evilFlag;
});
};
15 changes: 13 additions & 2 deletions test/test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
var Replicator = require('../');
var assert = require('assert');
const Replicator = require('../');
const assert = require('assert');
const helpersGH16 = require('./helpers/gh-16');


it('Should add and remove transforms', function () {
var replicator = new Replicator();
Expand Down Expand Up @@ -407,4 +409,13 @@ describe('Regression', function () {
assert.strictEqual(actual.foo, 'bar');
assert.strictEqual(actual.ans, 42);
});

it('Should not allow RCE when deserializing TypedArrays', function () {
replicator.decode(helpersGH16.vulnerableData);

return helpersGH16.checkIfBroken()
.then(function (result) {
assert.strictEqual(result, false);
});
});
});

0 comments on commit 2c62624

Please sign in to comment.