Skip to content
Browse files

[fix] leaky functions and globals

  • Loading branch information...
1 parent f04975c commit d30285f321c56f3bdaff0c395daf1ea2d57522e6 @bmeck bmeck committed Jan 1, 2012
Showing with 79 additions and 29 deletions.
  1. +20 −0 example/example.js
  2. +59 −29 lib/shovel.js
View
20 example/example.js
@@ -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" )
+})
+
View
88 lib/shovel.js
@@ -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.
Something went wrong with that request. Please try again.