CVE-2022-24785 描述
Moment.js 是一个 JavaScript 日期库,用于解析、验证、操作和格式化日期。路径遍历漏洞会影响1.0.1和版本之间的 Moment.js npm(服务器)用户2.29.1,尤其是当直接使用用户提供的语言环境字符串切换 Moment 语言环境时。此问题已在 中得到修补2.29.2,修补程序可应用于所有受影响的版本。解决方法是,在将用户提供的语言环境名称传递给 Moment.js 之前对其进行清理。
识别漏洞
我们决定通过 npm 在本地下载受影响的 MomentJS 版本。
内部Moment-JS/node_modules/moment/src/lib/locale/locales.js有一个名为的函数loadLocale,其值为name:
function loadLocale(name) {
var oldLocale = null,
aliasedRequire;
// TODO: Find a better way to register and load all the locales in Node
if (
locales[name] === undefined &&
typeof module !== 'undefined' &&
module &&
module.exports
) {
try {
oldLocale = globalLocale._abbr;
aliasedRequire = require;
aliasedRequire('./locale/' + name);
getSetGlobalLocale(oldLocale);
} catch (e) {
// mark as not found to avoid repeating expensive file require call causing high CPU
// when trying to find en-US, en_US, en-us for every format call
locales[name] = null; // null means not found
}
}
return locales[name];
}
问题发生在函数根据用户输入动态地需要模块的行上14(loadLocale())name。require()是一个 Node.js 函数,用于将模块或 JavaScript 文件包含并加载到 Node.js 应用程序中。
//require set to a variable `aliasedRequire`
const aliasedRequire = require;
// essentially require('./locale/' + name);
aliasedRequire('./locale/' + name);
如果我们控制name参数,我们可能会传递基于遍历的字符串:
// Suppose name is set to a malicious value
const name = '../../someMaliciousModule';
aliasedRequire('./locale/' + name);
这可能会加载./locale/../../uploads/someMaliciousModule,可能暴露敏感文件,甚至导致远程代码执行(RCE)。
概念验证
我们编写了一个使用易受攻击的函数的基本应用程序来演示该漏洞。以下是代码app.js:
const express = require('express');
const moment = require('moment');
const app = express();
const port = 1337;
app.get('/time', (req, res) => {
const locale = req.query.locale || 'en';
// CVE-2022-24785 triggers at the following line in locate() function
// locale() function passes the first parameter to require() without any sanitisation, this makes it easier to perform a path traversal attack
const currentTime = moment().locale(locale).format('LLLL');
res.send(`Current time (${locale}): ${currentTime}`);
});
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
应用程序监听并具有接受查询参数的localhost:1337端点。应用程序将的值分配给变量,如果未提供,则默认为。例如,如果查询字符串是,则将是。在后端,应用程序使用动态加载与指定语言环境相对应的模块
/timelocalereq.query.localelocale'en'req.query.locale?locale=frlocale'fr'aliasedRequire();
但是,?locale=../../../../../../../etc/passwd例如,传递不起作用。require()在 Node.js 中使用时,它会尝试加载 JavaScript 模块或文件。如果我们要传递一个像../../../../../../etc/passwdto 这样的值require('./locale/' + somevalue),Node.js 会尝试解析相对于应用程序当前工作目录的此路径。但是,Node.js 不会像/etc/passwd through那样直接读取任意文件require(),因为它需要加载模块或 JavaScript 文件。
现在,我们假设该应用程序具有文件上传功能,允许我们上传和存储笔记。我们可以利用这一点来实现 RCE。
路径遍历与上传文件的能力相结合,甚至.txt没有note扩展名,为我们提供了 RCE,因为require();。
该补丁安全吗?
让我们回顾一下 Moment JS 最新版本的补丁代码。
npm install moment@latest
function isLocaleNameSane(name) {
// Prevent names that look like filesystem paths, i.e contain '/' or ''
// Ensure name is available and function returns boolean
return !!(name && name.match('^[^/\\]*$'));
}
到目前为止,还没有办法绕过这个正则表达式。我试过多种方法。
好了,就这些了。
本质上就是这样。这是一个非常基本的漏洞!据我所知,没有人针对此漏洞进行过概念验证,所以这对每个人来说都很酷。
https://0xjay.com/how-cve-2022-24785-momentjs-path-traversal-works-detailed-exploit-guide
原文始发于微信公众号(Ots安全):CVE-2022-24785 MomentJS 路径遍历的工作原理:详细的漏洞利用指南
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论