CVE-2022-24785 MomentJS 路径遍历的工作原理:详细的漏洞利用指南

CVE-2022-24785 MomentJS 路径遍历的工作原理:详细的漏洞利用指南

Ots安全 2024-07-06 13:45

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

感谢您抽出

.

.

来阅读本文

点它,分享点赞在看都在这里