猫史档案馆


整活帖:NomenSandbox-Nomen沙盒,为不受信任的代码提供安全的运行空间

用户:NomenNomen查看:16 回复:11 评论:16 创建时间:2023-05-14T11:43:14


Box3-Tools有了一个初始界面:

box3-tools.rth1.me/

======

这里是没有开场白的Nomen,闲来无事,写了一个神奇的东西(至于整活作品中的bug,关我啥事)

本体内容:

class NomenSandbox {
    constructor(config, _code) {
        this.timeout = config.timeout || 10 * 1000;
        this.permision = config.permission || {};
        this.finish = false;
        this._cancel = false;
        this.pgm = `try {
            return (async () => {
                let __st = setTimeout(() => {
                    if (sandbox.__finish__) { clearTimeout(__st); return; }
                    sandbox.__complete(new Error('[NomenSandbox] Sandbox Execute Timeout'));
                    throw new Error('[NomenSandbox] Sandbox Execute Timeout');
                }, ${this.timeout});
                with (sandbox) {
                    (async () => { return await ${(typeof _code == "function") ? '(' + _code.toString() + ')()' : _code} })()
                        .then(v => __complete(v))
                        .catch(e => __complete('[NomenSandbox: Error When execute user script]'+e))
                        .finally(() =>  __finish__ = true)
                };
            })()
        } catch (err) { __complete('[NomenSandbox: Error When Runing NomenSandbox]'+err) }`;
    }
    run() {
        if (this.finish) return;
        return (async () => {
            let r = this;
            Object.assign(this.permision, {
                get __finish__() { return r.finish || r._cancel },
                r,
                setInterval,
                clearInterval,
                setTimeout,
                clearTimeout,
                Error,
                Promise,
            })
            try {
                let result = await new Promise(resolve => {
                    r.permision.__complete = (v) => resolve(v)
                    const sandbox = new Proxy(r.permision, {
                        has() { return true },
                        get(target, key) { return (key == Symbol.unscopables) ? undefined : target[key] }
                    });
                    const cd = new Function('sandbox', r.pgm);
                    cd(sandbox)
                        .then(v => {
                            this.finish = true;
                        }).catch(e => { })
                });
                return result
            } catch (err) {
                return err;
            }
        })()
    }
}

附带示例:

const config = {
    timeout: 5 * 1000, // 超时,单位毫秒(超时后会强行终止用户脚本
    // 但是由于顶级函数的某些vm特性(@吉吉 看你干的好事),会在之后二次抛出其他错误,但是不致命,放心使用)
    permission: { // 允许脚本使用的内容
        Promise, // 向内提供Promise
        str: 'NomenYYDS', //在内部环境可以直接读取的字符串
        log: (t) => console.log(t) // 向内提供了一个方法
    },
};

async function main() {
    var code = async () => {
        let result = await new Promise(resolve => { setTimeout(() => resolve(null), 3 * 1000); });
        return 'awa';
    }; // 一个用户脚本,可以是字符串或函数
    // 并且可以是异步函数

    let ns = new NomenSandbox(config, code);// 初始化沙盒
    try {
        let res = await ns.run(); // 启动沙盒
        console.log(res);  // 获取用户脚本返回的
    } catch (err) {
        console.log('Error When Main' + err); // 要try-catch不然会致命
    }
}
main()

=====

这个工具会出现在Box3-Tools仓库中,希望大家多多支持


回复

上一页1 页 / 共 1下一页
145a145a

sofa

点赞1


评论


NomenNomen

还没有沙发的话,我来讲讲怎么用吧:

首先,我们需要一段人畜无害的die码,可以是字符串或者函数:

const config = {
    timeout: 5 * 1000, // 超时,单位毫秒(超时后会强行终止用户脚本
    // 但是由于顶级函数的某些vm特性(@吉吉 看你干的好事),会在之后二次抛出其他错误,但是不致命,放心使用)
    permission: { // 允许脚本使用的内容
        Promise, // 向内提供Promise
        str: 'NomenYYDS', //在内部环境可以直接读取的字符串
        log: (t) => console.log(t) // 向内提供了一个方法
    },
};

async function main() {
    var code = async () => {
        voxels.setVoxel(11,45,14,'NomenYYDS!')
    }; // 此处可以是某些加密了的毁图boom
    let ns = new NomenSandbox(config, code);// 初始化沙盒
    try {
        let res = await ns.run(); // 启动沙盒
        console.log(res);  // 获取用户脚本返回的
    } catch (err) {
        console.log('Error When Main' + err); // 要try-catch不然会致命
    }
}
main()

然后就会返回voxels不存在的错误,因为你还没有为其授权voxels,它甚至连global都无法获取,包括property,proccess,world之类的东西(包括require,JSON之类的原生)

如果你要为他授权,只需要在config.permission里加上这个东西:

const config = {
    timeout: 5 * 1000,
    permission: {
        str: 'NomenYYDS', //用户脚本在内部可以像引用局域变量一样引用这个字符串
        log: (t) => console.log(t),
        voxels, //然后用户脚本就可以读取voxels了
    },
};

点赞0


评论


小宏XeLa小宏XeLa

前排

点赞1


评论


七式草莓七式草莓

一个while(true){}不就完啦))

点赞0


评论


七式草莓七式草莓

还有这个都防不住()

new [].constructor(10 ** 7).fill(' '.repeat(100))

点赞0


评论


一个STUB用户_6715468一个STUB用户_6715468

一个delete Math啥也没了()

点赞0


评论


22why22why

wow()虽然看不懂但我大受震撼(doge)

点赞0


评论


小宏XeLa小宏XeLa

ddd

点赞0


评论


没尾巴的鲸鱼_没尾巴的鲸鱼_

只要添加3个config项,添加一下这个对象代理替换代码就可以解决constructor的问题(

if (this.constructorVisit) {
    for (el in this.permision) {
        this.permision[el] = new Proxy(this.permision[el], {
            get(target, key) {
                if (target[key] == target.constructor) { return undefined };
                if (r.bannedGet[el].includes(key)) { return undefined };
                return target[key];
            },
            set(target, key, val) {
                if (target[key] == target.constructor) { return undefined };
                if (r.bannedSet[el].includes(key)) { return undefined };
                target[key] = val;
            }
        })
    }
}

点赞0


评论


没尾巴的鲸鱼_没尾巴的鲸鱼_

弄门🚪,我给沙盒执行提供的接口对象装上了代理,自带防构造器攻击,可以做到隔离特定成员,但while喵循环执行超时咋解决啊,是object有方法监听循环入口事件吗?

class SwingSandbox {
    constructor(config, _code) {
        this.timeout = config.timeout || 10 * 1000;
        this.permision = config.permission || {};
        this.constructorVisit = config.constructorVisit || false;
        this.bannedSet = config.bannedSet || {};
        this.bannedGet = config.bannedGet || {};
        this.finish = false;
        this._cancel = false;
        this.pgm = `try {
            return (async () => {
                let __st = setTimeout(() => {
                    if (sandbox.__finish__) { clearTimeout(__st); return; }
                    sandbox.__complete(new Error('[SwingSandbox] Sandbox Execute Timeout'));
                    throw new Error('[SwingSandbox] Sandbox Execute Timeout');
                }, ${this.timeout});
                with (sandbox) {
                    (async () => { return await ${(typeof _code == "function") ? '(' + _code.toString() + ')()' : _code} })()
                        .then(v => __complete(v))
                        .catch(e => __complete('[SwingSandbox: Error When execute user script]'+e))
                        .finally(() =>  __finish__ = true)
                };
            })()
        } catch (err) { __complete('[SwingSandbox: Error When Runing SwingSandbox]'+err) }`;
    }
    
    __run__() {
        if (this.finish) return;
        return (async () => {
            let r = this;
            Object.assign(this.permision, {
                get __finish__() { return r.finish || r._cancel },
                r,
                setInterval,
                clearInterval,
                setTimeout,
                clearTimeout,
                Error,
                Promise,
            })
            if (this.constructorVisit) {
                for (el in this.permision) {
                    this.permision[el] = new Proxy(this.permision[el], {
                        get(target, key) {
                            if (target[key] == target.constructor) { return undefined };
                            if (r.bannedGet[el].includes(key)) { return undefined };
                            return target[key];
                        },
                        set(target, key, val) {
                            if (target[key] == target.constructor) { return undefined };
                            if (r.bannedSet[el].includes(key)) { return undefined };
                            target[key] = val;
                        }
                    })
                }
            }
            try {
                let result = await new Promise(resolve => {
                    r.permision.__complete = (v) => resolve(v)
                    const sandbox = new Proxy(r.permision, {
                        has() { return true },
                        get(target, key) { return (key == Symbol.unscopables) ? undefined : target[key] }
                    });
                    const cd = new Function('sandbox', r.pgm);
                    cd(sandbox)
                        .then(v => {
                            this.finish = true;
                        }).catch(e => { })
                });
                return result
            } catch (err) {
                return err;
            }
        })()
    }
}

点赞0


评论


烟魂烟魂

哈哈哈。。。有我的贡献。。。哈哈哈

点赞0


评论