mongo-express is a MongoDB Admin Web management interface, written using NodeJS, Express, and Bootstrap3. Currently, mongo-express should be the MongoDB admin management interface with the most stars on Github. Easy to deploy and simple to use, it has become the choice of many people to manage mongo.
Reading the official GitHub security announcement, we found The vulnerability affects all versions below 0.54.0. We chose 0.49 as an example for testing. Since this vulnerability environment also requires a MongoDB database, we can quickly build it by executing the following docker command:
Build a MongoDB database<br>
docker run --name test -d mongo:3.2
Build mongo-express containing the vulnerability and connect to the above MongoDB database:<br>
docker run -d -p 8081:8081 --link test:mongo mongo-express:0.49
Check the log to confirm that the connection is successful.
There is a trick here. If you want to debug nodejs, you need to add the --inspect parameter when starting up. Make the following modifications to the docker startup script
##docker restart 183Use docker exec -it 183 bash to connect to docker to check whether the debug service is turned on Just open port 9229 as shown in the picture above. As long as the external host can connect to the 9229 port, you can use the chrome plug-in for debugging. You can use frp to forward the port, or use the docker -p 9229:9229 parameter for processing. 0x3 Chrome DevTools<br>
<br>
##0x03 Vulnerability debugging and principle analysis
string is the parameter of toBSON. BSON is a common data format in MongoDB and is a close relative of JSON, but There are many differences from the data format of JSON. However, all BSON-related operations in mongo-express, such as creating a new document (similar to insertion operations in other databases), need to go through the toBSON() function.
For example, the following operation
When the code flow reaches bson.toBSON, the eval function will be triggered. Because nodejs can be used as a back-end language, the eval function is Running on the server side can cause command injection and harm the system.
<br>
<br>
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'); };
<br>
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;};
According to code source analysis, the parameter string of toBSON is the document in req.body, so we can control this part. You can find the vm.runInNewContext function, which is a virtual sandbox. Therefore, we will analyze how to bypass sandbox protection in the next section.
A sandbox is an independent environment that can safely execute untrusted code without affecting the actual external code. Code execution is often restricted in a sandbox. The VM module provides an API for compiling and running code in the context of a VM virtual machine. Use the VM module to run code in a sandbox environment. The running code uses a different V8 context, that is, its global variables are different from other code. But code in the sandbox can still access the Node process. We often use this method to bypass.
vm.js
<br>
<br>
"use strict";const vm = require("vm");const xyz = vm.runInNewContext(` this.constructor.constructor('return this.process.env')()`);console.log(xyz);
You can see this.process.env The nodejs process information is obtained, which shows that it is completely possible to switch back to the main program to execute system commands.
In javascript this points to the object it belongs to, so when we use it, it already points to an object outside the VM context. Then the .constructor that accesses this returns Object Constructor, and the .constructor that accesses Object Constructor returns Function constructor. Function constructor is like the highest function in javascript which allows global access. The Function constructor allows generating functions from strings, thereby executing arbitrary code. So we can use it to return to the main process. We can then use it to access the main process and perform RCE.
<br>
<br>
"use strict";const vm = require("vm");const xyz = vm.runInNewContext(`const process = this.constructor.constructor('return this.process')(); process.mainModule.require('child_process').execSync('cat /etc/passwd').toString()`);console.log(xyz);
Similarly, the vm2 function can also be bypassed, Let’s study by referring to the original text https://pwnisher.gitlab.io/nodejs/sandbox/2019/02/21/sandboxing-nodejs-is-hard.html
Here are two pictures to illustrate everything. Use mongo-query-parser to parse BSON data and replace it directly from the source.
The above is the detailed content of Remote code execution vulnerability case analysis. For more information, please follow other related articles on the PHP Chinese website!