Vm2: Nicht immun gegen while(1){}

Erstellt am 2. Jan. 2019  ·  19Kommentare  ·  Quelle: patriksimek/vm2

Der folgende Code wird nicht ablaufen.

const {VM} = require('vm2');
new VM({timeout:1}).run(`
        function main(){
        while(1){}
    }
    new Proxy({}, {
        getPrototypeOf(t){
            global.main();
        }
    })`);
bug confirmed help wanted

Alle 19 Kommentare

Dafür gibt es wahrscheinlich keine gute Lösung. NodeJS ist ein einzelner Prozess. Der while(1){}-Schutz erfordert mehrere Prozesse, damit der Checker nicht durch while(1){} blockiert wird. Vielleicht könnten wir das SpiderNode-Projekt wieder aufleben lassen.......

Dies wird dadurch verursacht, dass Decontextify.value den Prototyp des Gastobjekts mit instanceOf testet. Das Modul Node.js vm ist dagegen natürlich immun. Ein Patch für arme Leute könnte darin bestehen, Proxy backdoor, damit wir alle Proxy-Objekte aus der Sandbox erkennen können, aber ein idealer Ansatz wäre, niemals irgendwelchen Objekten und Funktionen daraus zu vertrauen und contextify.js in die Sandbox zu legen. Verwenden von primitiven Werten für die Kommunikation und Handles für die Referenzierung von Gastobjekten.

Nur damit die Leute es sehen, verwendet browserlos einen Child-Prozess und Message-Passing, um mit dem Kind zu sprechen, das den nicht vertrauenswürdigen Code ausführt. Es ist eine kleine Setup-Aufgabe, aber sobald Sie fertig sind, sind Sie immun gegen while(1){} Angriffe. Die Quelle ist hier .

Der springende Punkt dieses Projekts scheint darin zu bestehen, kein separates Ganzes hervorzubringen
OS-Prozess. Ansonsten gibt es viele Lösungen die viel sind
sicherer.

Ansonsten gibt es viele Lösungen, die viel sicherer sind.

Welche? Ich bin mir nicht sicher, ob es in NodeJS eine bessere Alternative zu VM2 gibt, zumindest nicht die ich gesehen habe

Der Betreuer dieser Bibliothek hat in Ausgabe #80 auf diese Alternative hingewiesen:

https://github.com/laverdet/isolated-vm

Ich selbst habe es noch nicht probiert.

Ich führe nur nicht vertrauenswürdigen Code im Kindprozess aus. Sie können es nicht riskieren, es in der V8-Hauptinstanz auszuführen, insbesondere wenn Sie wissen, dass es sich um einen einzelnen Thread handelt.

Das Problem beim direkten Aufrufen des V8-Motors ist das Fehlen eines Importmoduls. In meinem Fall muss ich das Anforderungsmodul importieren, um HTTP-Operationen zuzulassen. Es muss auch asynchron sein.

Ich finde vm2 + child_process eine gute Kombination.

Hallo,

Ich und while(1) {} .

Ähnlich wie von tian-ma erwähnt, aber wir verwenden node.js-Worker-Threads anstelle von untergeordneten Prozessen.

schau mal hier: https://www.npmjs.com/package/isolated-runtime und lass uns deine Meinung wissen :)

Eine andere Problemumgehung wäre, einfach Proxy in der Sandbox zu deaktivieren, oder?

const vm = new VM({
    sandbox: {
        Proxy: undefined
    },
    timeout: 100
});

Mit Promise ist es auch möglich, Code zu schreiben, der nie abläuft:

"use strict";
const {VM} = require('vm2');
const untrusted = '(' + function(){
    Promise.resolve().then(a=>{
        while(1){}
    });
}+')()';
try{
    console.log(new VM({timeout:10}).run(untrusted));
}catch(x){
    console.log(x);
}

Das Problem hierbei ist, dass .then die später aufzurufende Funktion in die Microtask-Warteschlange einreiht.
Um dies zu beheben, müssen wir unsere eigenen Promise.then & verwandte Funktionen schreiben oder Promise deaktivieren.

Auch das funktioniert:

const {VM} = require('vm2');

const script = '(' + function() {
    (async function x(){
        await {then: y=>y()};
        while(1){}
    })();
}+')()';

new VM({timeout:10}).run(script);

Das Überschreiben von Promise funktioniert also nicht.
Keine Ahnung wie man das beheben kann.

Während dies offen bleibt, sollten wir der README-Datei eine Klarstellung hinzufügen, um potenzielle Benutzer zu warnen. Diese Schwachstelle ermöglicht es einem, der Sandbox zu entkommen und verfehlt somit den Zweck der Bibliothek.

Readme wurde aktualisiert https://github.com/patriksimek/vm2/commit/77f5265ab53b87864a312156ee62b1082787e9b0#diff -04c6e90faac2675aa89e2176d2eec7d8. Und ich weiß nicht, wie dies verwendet werden könnte, um der Sandbox zu entkommen, Sie können nur dem vorgesehenen Zeitrahmen entkommen, in dem das Skript ausgeführt werden soll.

Vielleicht sollte dies ein eigenes Problem sein, aber warum unterstützt NodeVM kein "Timeout"?

@crowder da in NodeVM das setTimeout, setInterval & setImmediate existiert, wäre es einfach, das Timeout zu umgehen. Vielleicht gibt es auch andere Gründe, aber ich arbeite nicht mit NodeVM, nur mit VM.

@XmiliaH würde kein Timeout implementieren, um zumindest unbeabsichtigte Endlosschleifen zu verhindern?
Die bösartige Kombination while(true) + setTimeout wäre immer noch ein Problem, aber jede einfache unbeabsichtigte Endlosschleife könnte durch die Unterstützung von Timeout behandelt werden

Meine Sorge ist, dass NodeVM es zulässt, Module zu erfordern, bei denen es sich möglicherweise um Hostmodule handelt, und das Timing, während sie den globalen Status ändern, könnte schlecht sein. Außerdem gibt die NodeVM ein Modul zurück und Benutzer würden wahrscheinlich Funktionen aufrufen, die vom Modul bereitgestellt werden, jedoch würde die Zeitüberschreitung nur für das Laden des Moduls und nicht für die Funktionsaufrufe gelten.
Wenn Sie eine Funktion mit einem Timeout aufrufen möchten, können Sie dies einfach selbst implementieren wie

function doWithTimeout(fn, timeout) {
    let ctx = CACHE.timeoutContext;
    let script = CACHE.timeoutScript;
    if (!ctx) {
        CACHE.timeoutContext = ctx = vm.createContext();
        CACHE.timeoutScript = script = new vm.Script('fn()', {
            filename: 'timeout_bridge.js',
            displayErrors: false
        });
    }
    ctx.fn = fn;
    try {
        return script.runInContext(ctx, {
            displayErrors: false,
            timeout
        });
    } finally {
        ctx.fn = null;
    }
}

Guter Punkt @XmiliaH und danke für das Beispiel
Ich sehe, dass Ihr Beispiel ein VM-Paket und nicht VM2 verwendet
Wäre schön, vm2 verwenden zu können und trotzdem in der Lage zu sein, das Zeitlimit zu überschreiten

@szydan Der von mir gepostete Code wird von VM2 verwendet, um das Zeitlimit für die VM zu überschreiten. Wenn die NodeVM auch ein Timeout hätte, würde sie dieselbe Funktionalität verwenden.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

somebody1234 picture somebody1234  ·  4Kommentare

ghost picture ghost  ·  23Kommentare

patriksimek picture patriksimek  ·  5Kommentare

KonradLinkowski picture KonradLinkowski  ·  10Kommentare

vshymanskyy picture vshymanskyy  ·  8Kommentare