Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[fix] leaky functions and globals #10

Merged
merged 1 commit into from
Jan 2, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions example/example.js
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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 } ) );
}