用户:
Nomen查看:286 回复: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仓库中,希望大家多多支持
Nomen还没有沙发的话,我来讲讲怎么用吧:
首先,我们需要一段人畜无害的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
评论
可恶晚了一步,但是我有天台(
七式草莓还有这个都防不住()
new [].constructor(10 ** 7).fill(' '.repeat(100))
点赞0
评论
好的,下次禁一下constructor,但是经过测试地图仍在正常运行,没有抛出超时和内存泄漏等致命问题
直接给对象上代理,检测到违规访问直接屏蔽(((
一个delete Math啥也没了()
点赞0
评论
所以说只要不给不受信任的代码授权Math,它就无法攻击你的其他内容,只会获得一个人畜无害的报错
把访问的对象用代理替换,过滤掉c喵tructor和其他的禁止访问元素(防火墙)就可以辽
这样恶意代码只会把沙盒开放给自己的接口阉掉,《皇上自宫了》
没尾巴的鲸鱼_只要添加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
评论
解析javascript语法树,插入一个加法函数,检测执行了多少次,超出预期就抛错,最近我在研究这个语法树的问题
还不如就写一个有限制的解释器,while循环执行前判断能不能break,for同理
还不如写一个虚拟机(划掉)《我在岛三写汇编》
用Proxy拦截c喵tructor测试:new Proxy([1,2,3,4,5],{set (a,b,c) {a[b]=c},get(a,b){return 0}}).c喵tructor ~》0
语义树以前尝试弄了一个shell语法解析,结果bug一大堆(((
解释器难搞,翻了几个都是万行起步
其实吧,这个砂箱的目的就是防止管喵乱搞。。。