Skip to content

Commit

Permalink
[fix] leaky functions and globals
Browse files Browse the repository at this point in the history
  • Loading branch information
bmeck committed Jan 2, 2012
1 parent f04975c commit d30285f
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 29 deletions.
20 changes: 20 additions & 0 deletions example/example.js
Expand Up @@ -26,3 +26,23 @@ s.run( "while (true) {}", function( output ) {
console.log( "Example 5: " + output.result + "\n" )
})

// Example 6 - Caller Attack Failure
s.run( "(function foo() {return foo.caller.caller;})()", function( output ) {
console.log( "Example 6: " + output.result + "\n" )
})

// Example 7 - Argument Attack Failure
s.run( "(function foo() {return [].slice.call(foo.caller.arguments);})()", function( output ) {
console.log( "Example 7: " + output.result + "\n" )
})

// Example 8 - Type Coersion Attack Failure
s.run( "(function foo() {return {toJSON:function x(){return x.caller.caller.name}}})()", function( output ) {
console.log( "Example 8: " + output.result + "\n" )
})

// Example 9 - Global Attack Failure
s.run( "x=1;(function() {return this})().console.log.constructor('return this')()", function( output ) {
console.log( "Example 9: " + output.result + "\n" )
})

88 changes: 59 additions & 29 deletions lib/shovel.js
Expand Up @@ -4,51 +4,81 @@
/* ------------------------------ INIT ------------------------------ */
var util = require( 'util' )
, code
, console
, result
, console
, sandbox
, Script
, stdin
, stdin;

if ( ! ( Script = process.binding( 'evals').NodeScript ) )
if ( ! Script = process.binding('evals').Script )
Script = require( 'vm' )
if ( ! ( Script = process.binding('evals').Script ) )
Script = require( 'vm' );

/* ------------------------------ Sandbox ------------------------------ */
// Sandbox methods
console = []
sandbox =
{ console:
{ log: function() { var i, l
for ( i = 0, l = arguments.length; i < l; i++ )
console.push( util.inspect( arguments[i] ) )
}
}
}
sandbox.print = sandbox.console.log
var console = [];

// Get code
code = ''
stdin = process.openStdin()
code = '';
stdin = process.openStdin();
stdin.on( 'data', function( data ) {
code += data
code += data;
})
stdin.on( 'end', run )
stdin.on( 'end', run );

function getSafeRunner() {
var global = this;
// Keep it outside of strict mode
function UserScript(str) {
// We want a global scoped function that has implicit returns.
return Function('return eval('+JSON.stringify(str+'')+')');
}
// place with a closure that is not exposed thanks to strict mode
return function run(comm, src) {
// stop argument / caller attacks
"use strict";
var send = function send(event) {
"use strict";
//
// All comm must be serialized properly to avoid attacks, JSON or XJSON
//
comm.send(event, JSON.stringify([].slice.call(arguments,1)));
}
global.print = send.bind(global, 'stdout');
global.console = {};
global.console.log = send.bind(global, 'stdout');
var result = UserScript(src)();
send('end', result);
}
}

// Run code
function run() {
result = (function() {
try {
return Script.runInNewContext( this.toString(), sandbox )
}
catch (e) {
return e.name + ': ' + e.message
}
}).call( code )
var context = Script.createContext();
var safeRunner = Script.runInContext('('+getSafeRunner.toString()+')()', context);
var result;
try {
safeRunner({
send: function (event, value) {
"use strict";
switch (event) {
case 'stdout':
console.push.apply(console, JSON.parse(value).slice(1));
break;
case 'end':
result = JSON.parse(value)[0];
break;
}
}
}, code);
}
catch (e) {
result = e.name + ': ' + e.message;
}

process.stdout.on( 'drain', function() {
process.exit(0)
})
process.stdout.write( JSON.stringify( { result: util.inspect( result ), console: console } ) )
});

process.stdout.write( JSON.stringify( { result: util.inspect( result ), console: console } ) );
}

0 comments on commit d30285f

Please sign in to comment.