Vm2: while(1){}에 λ©΄μ—­λ˜μ§€ μ•ŠμŒ

에 λ§Œλ“  2019λ…„ 01μ›” 02일  Β·  19μ½”λ©˜νŠΈ  Β·  좜처: patriksimek/vm2

λ‹€μŒ μ½”λ“œλŠ” μ‹œκ°„ μ΄ˆκ³Όλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

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

λͺ¨λ“  19 λŒ“κΈ€

이에 λŒ€ν•œ 쒋은 해결책은 없을 κ²ƒμž…λ‹ˆλ‹€. NodeJSλŠ” 단일 ν”„λ‘œμ„ΈμŠ€μž…λ‹ˆλ‹€. while (1) {} λ³΄ν˜Έμ—λŠ” 검사기가 while (1) {}에 μ˜ν•΄ μ°¨λ‹¨λ˜μ§€ μ•Šλ„λ‘ 닀쀑 ν”„λ‘œμ„ΈμŠ€κ°€ ν•„μš”ν•©λ‹ˆλ‹€. μŠ€νŒŒμ΄λ”λ…Έλ“œ ν”„λ‘œμ νŠΈμ— λ‹€μ‹œ λΆˆμ„ 뢙일 수 μžˆλ‹€λ©΄.......

이것은에 μ˜ν•΄ λ°œμƒ Decontextify.value 둜 게슀트 객체의 ν”„λ‘œν†  νƒ€μž…μ„ ν…ŒμŠ€νŠΈ instanceOf . Node.js vm λͺ¨λ“ˆμ€ λ¬Όλ‘  이것에 영ν–₯을받지 μ•ŠμŠ΅λ‹ˆλ‹€. κ°€λ‚œν•œ μ‚¬λžŒμ˜ νŒ¨μΉ˜λŠ” Proxy λ₯Ό λ°±λ„μ–΄ν•˜μ—¬ μƒŒλ“œλ°•μŠ€μ—μ„œ ν”„λ‘μ‹œ 개체λ₯Ό 감지할 수 μžˆλ„λ‘ ν•˜λŠ” 것일 수 μžˆμ§€λ§Œ 이상적인 μ ‘κ·Ό 방식은 μƒŒλ“œλ°•μŠ€μ—μ„œ κ°œμ²΄μ™€ κΈ°λŠ₯을 μ ˆλŒ€ μ‹ λ’°ν•˜μ§€ μ•Šκ³  contextify.jsλ₯Ό μƒŒλ“œλ°•μŠ€μ— λ„£λŠ” κ²ƒμž…λ‹ˆλ‹€. κΈ°λ³Έ 값을 μ‚¬μš©ν•˜μ—¬ ν†΅μ‹ ν•˜κ³  게슀트 개체 μ°Έμ‘°λ₯Ό μ²˜λ¦¬ν•©λ‹ˆλ‹€.

μ‚¬λžŒλ“€μ΄ λ³Ό 수 μžˆλ„λ‘ λΈŒλΌμš°μ €λ¦¬μŠ€λŠ” μžμ‹ ν”„λ‘œμ„ΈμŠ€μ™€ λ©”μ‹œμ§€ 전달을 μ‚¬μš©ν•˜μ—¬ μ‹ λ’°ν•  수 μ—†λŠ” μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜λŠ” μžμ‹κ³Ό λŒ€ν™”ν•©λ‹ˆλ‹€. μ•½κ°„μ˜ μ„€μ • μž‘μ—…μ΄μ§€λ§Œ 일단 μ™„λ£Œλ˜λ©΄ while(1){} 곡격에 λ©΄μ—­μ΄λ©λ‹ˆλ‹€. μΆœμ²˜λŠ” μ—¬κΈ° μž…λ‹ˆλ‹€.

이 ν”„λ‘œμ νŠΈμ˜ μš”μ μ€ 전체λ₯Ό λ³„λ„λ‘œ μƒμ„±ν•˜μ§€ μ•ŠλŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.
OS ν”„λ‘œμ„ΈμŠ€. 그렇지 μ•ŠμœΌλ©΄ λ§Žμ€ μ†”λ£¨μ…˜μ„ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
더 μ•ˆμ „ν•©λ‹ˆλ‹€.

그렇지 μ•ŠμœΌλ©΄ 훨씬 더 μ•ˆμ „ν•œ λ§Žμ€ μ†”λ£¨μ…˜μ„ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ–΄λŠ 것? NodeJSμ—μ„œ VM2에 λŒ€ν•œ 더 λ‚˜μ€ λŒ€μ•ˆμ΄ μžˆλŠ”μ§€ ν™•μ‹€ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 적어도 μ œκ°€ λ³Έ 것은 μ•„λ‹™λ‹ˆλ‹€.

이 라이브러리의 κ΄€λ¦¬μžλŠ” 문제 #80μ—μ„œ 이 λŒ€μ•ˆμ„ μ§€μ ν–ˆμŠ΅λ‹ˆλ‹€.

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

λ‚˜λŠ” 아직 그것을 슀슀둜 μ‹œλ„ν•˜μ§€ μ•Šμ•˜λ‹€.

μžμ‹ ν”„λ‘œμ„ΈμŠ€μ—μ„œ μ‹ λ’°ν•  수 μ—†λŠ” μ½”λ“œλ§Œ μ‹€ν–‰ν•©λ‹ˆλ‹€. 특히 단일 μŠ€λ ˆλ“œλΌλŠ” 것을 μ•Œκ³  μžˆλŠ” 경우 κΈ°λ³Έ V8 μΈμŠ€ν„΄μŠ€μ—μ„œ μ‹€ν–‰ν•  μœ„ν—˜μ΄ μ—†μŠ΅λ‹ˆλ‹€.

V8 엔진을 직접 ν˜ΈμΆœν•˜λŠ” λ¬Έμ œλŠ” import λͺ¨λ“ˆμ΄ μ—†λ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. 제 κ²½μš°μ—λŠ” HTTP μž‘μ—…μ„ ν—ˆμš©ν•˜κΈ° μœ„ν•΄ μš”μ²­ λͺ¨λ“ˆμ„ 가져와야 ν•©λ‹ˆλ‹€. λ˜ν•œ 비동기식이어야 ν•©λ‹ˆλ‹€.

λ‚˜λŠ” vm2 + child_processκ°€ 쒋은 쑰합이라고 μƒκ°ν•©λ‹ˆλ‹€.

μ•Ό,

저와 @harelmo λŠ” while(1) {} 면역이 μžˆλŠ” vm2 μœ„μ— 라이브러리λ₯Ό λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.

tian-maκ°€ μ–ΈκΈ‰ν•œ 것과 μœ μ‚¬ν•˜μ§€λ§Œ μžμ‹ ν”„λ‘œμ„ΈμŠ€ λŒ€μ‹  node.js μž‘μ—…μž μŠ€λ ˆλ“œλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

https://www.npmjs.com/package/isolated-runtime을 μ‚΄νŽ΄λ³΄κ³  μ—¬λŸ¬λΆ„μ˜ 생각을 μ•Œλ €μ£Όμ„Έμš” :)

또 λ‹€λ₯Έ ν•΄κ²° 방법은 μƒŒλ“œ λ°•μŠ€ λ‚΄μ—μ„œ Proxy λΉ„ν™œμ„±ν™”ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

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

Promiseλ₯Ό μ‚¬μš©ν•˜λ©΄ μ‹œκ°„ μ΄ˆκ³Όλ˜μ§€ μ•ŠλŠ” μ½”λ“œλ₯Ό μž‘μ„±ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

"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);
}

μ—¬κΈ°μ„œ λ¬Έμ œλŠ” .then이 λ‚˜μ€‘μ— λ§ˆμ΄ν¬λ‘œνƒœμŠ€ν¬ λŒ€κΈ°μ—΄μ—μ„œ 호좜될 ν•¨μˆ˜λ₯Ό λŒ€κΈ°μ—΄μ— λ„£κ²Œ λœλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.
이 문제λ₯Ό ν•΄κ²°ν•˜λ €λ©΄ 자체 Promise.then 및 κ΄€λ ¨ ν•¨μˆ˜λ₯Ό μž‘μ„±ν•˜κ±°λ‚˜ Promiseλ₯Ό λΉ„ν™œμ„±ν™”ν•΄μ•Ό ν•©λ‹ˆλ‹€.

λ˜ν•œ 이것은 μž‘λ™ν•©λ‹ˆλ‹€.

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

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

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

λ”°λΌμ„œ Promiseλ₯Ό μž¬μ •μ˜ν•˜λŠ” κ²ƒλ§ŒμœΌλ‘œλŠ” μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
이 문제λ₯Ό ν•΄κ²°ν•˜λŠ” 방법을 λͺ¨λ¦…λ‹ˆλ‹€.

아직 μ—΄λ € μžˆμ§€λ§Œ README에 μ„€λͺ…을 μΆ”κ°€ν•˜μ—¬ 잠재적 인 μ‚¬μš©μžμ—κ²Œ κ²½κ³ ν•΄μ•Όν•©λ‹ˆλ‹€. 이 취약점은 μƒŒλ“œλ°•μŠ€λ₯Ό νƒˆμΆœν•  수 있게 ν•˜μ—¬ 라이브러리의 λͺ©μ μ„ λ¬΄νš¨ν™”ν•©λ‹ˆλ‹€.

μΆ”κ°€ 정보가 μ—…λ°μ΄νŠΈλ˜μ—ˆμŠ΅λ‹ˆλ‹€ https://github.com/patriksimek/vm2/commit/77f5265ab53b87864a312156ee62b1082787e9b0#diff -04c6e90faac2675aa89e2176d2eec7d8. 그리고 이것이 μƒŒλ“œ λ°•μŠ€λ₯Ό νƒˆμΆœν•˜λŠ” 데 μ–΄λ–»κ²Œ μ‚¬μš©λ  수 μžˆλŠ”μ§€ λͺ¨λ₯΄κ² μŠ΅λ‹ˆλ‹€. μŠ€ν¬λ¦½νŠΈκ°€ μ‹€ν–‰λ˜μ–΄μ•Όν•˜λŠ” μ˜λ„ 된 μ‹œκ°„ ν”„λ ˆμž„ 만 λ²—μ–΄λ‚  수 μžˆμŠ΅λ‹ˆλ‹€.

μ•„λ§ˆλ„ 이것은 자체 문제일 수 μžˆμ§€λ§Œ NodeVM이 "μ‹œκ°„ 초과"λ₯Ό μ§€μ›ν•˜μ§€ μ•ŠλŠ” μ΄μœ λŠ” λ¬΄μ—‡μž…λ‹ˆκΉŒ?

@crowder NodeVMμ—λŠ” setTimeout, setInterval 및 setImmediateκ°€ 있기 λ•Œλ¬Έμ— μ‹œκ°„ μ œν•œμ„ ν”Όν•˜λŠ” 것이 μ‰½μŠ΅λ‹ˆλ‹€. λ‹€λ₯Έ μ΄μœ λ„μžˆμ„ 수 μžˆμ§€λ§Œ NodeVM은 μ‚¬μš©ν•˜μ§€ μ•Šκ³  VM 만 μ‚¬μš©ν•©λ‹ˆλ‹€.

@XmiliaH λŠ” μ΅œμ†Œν•œ μ˜λ„ν•˜μ§€ μ•Šμ€ λ¬΄ν•œ 루프λ₯Ό λ°©μ§€ν•˜λŠ” μ‹œκ°„ 초과λ₯Ό κ΅¬ν˜„ν•˜μ§€ μ•ŠμŠ΅λ‹ˆκΉŒ?
μ•…μ˜μ  인 while (true) + setTimeout 쑰합은 μ—¬μ „νžˆ β€‹β€‹λ¬Έμ œκ°€ 될 수 μžˆμ§€λ§Œ μ‹€μˆ˜λ‘œ μˆ˜ν–‰ 된 λ‹¨μˆœν•˜κ³  μ˜λ„ν•˜μ§€ μ•Šμ€ λ¬΄ν•œ λ£¨ν”„λŠ” μ‹œκ°„ μ œν•œμ„ μ§€μ›ν•˜μ—¬ 처리 ν•  수 β€‹β€‹μžˆμŠ΅λ‹ˆλ‹€.

λ‚΄ κ΄€μ‹¬μ‚¬λŠ” NodeVM이 호슀트 λͺ¨λ“ˆμΌ 수 μžˆλŠ” λͺ¨λ“ˆμ„ μš”κ΅¬ν•  수 있고 μ „μ—­ μƒνƒœλ₯Ό λ³€κ²½ν•˜λŠ” λ™μ•ˆ μ‹œκ°„μ΄ μ΄ˆκ³Όλ˜λŠ” 것이 쒋지 μ•Šμ„ 수 μžˆλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. λ˜ν•œ NodeVM은 λͺ¨λ“ˆμ„ λ°˜ν™˜ν•˜κ³  μ‚¬μš©μžλŠ” λͺ¨λ“ˆμ— μ˜ν•΄ λ…ΈμΆœλœ ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•  κ°€λŠ₯성이 λ†’μ§€λ§Œ μ‹œκ°„ μ΄ˆκ³ΌλŠ” ν•¨μˆ˜ 호좜이 μ•„λ‹Œ λͺ¨λ“ˆ λ‘œλ”©μ—λ§Œ μ μš©λ©λ‹ˆλ‹€.
μ‹œκ°„ μ΄ˆκ³Όκ°€ μžˆλŠ” ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ €λ©΄ λ‹€μŒκ³Ό 같이 직접 κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

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;
    }
}

쒋은 지적 @XmiliaH 그리고 예λ₯Ό λ“€μ–΄ μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€.
κ·€ν•˜μ˜ μ˜ˆκ°€ vm2κ°€ μ•„λ‹Œ vm νŒ¨ν‚€μ§€λ₯Ό μ‚¬μš©ν•˜κ³  μžˆμŒμ„ μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.
vm2λ₯Ό μ‚¬μš©ν•  수 있고 μ—¬μ „νžˆ μ‹œκ°„ μ΄ˆκ³Όν•  수 있으면 쒋을 κ²ƒμž…λ‹ˆλ‹€.

@szydan λ‚΄κ°€ κ²Œμ‹œν•œ μ½”λ“œλŠ” VM2μ—μ„œ VM μ‹œκ°„μ„ μ΄ˆκ³Όν•˜λŠ” 데 μ‚¬μš©λ©λ‹ˆλ‹€. NodeVM에도 μ‹œκ°„ μ΄ˆκ³Όκ°€ μžˆλŠ” 경우 λ™μΌν•œ κΈ°λŠ₯을 μ‚¬μš©ν•©λ‹ˆλ‹€.

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰