从信任到威胁:被劫持的Discord邀请用于多阶段恶意软件分发
关键要点
Check Point Research发现了一个活跃的恶意软件活动,利用过期和已释放的Discord邀请链接。攻击者通过自定义链接注册劫持这些链接,能够将用户从可信来源静默重定向到恶意服务器。
攻击者结合了ClickFix钓鱼技术、多阶段加载器和基于时间的规避技术,悄无声息地分发AsyncRAT和针对加密货币钱包的定制版Skuld窃取程序。
有效载荷分发和数据外泄完全通过可信云服务进行,如GitHub、Bitbucket、Pastebin和Discord,帮助操作融入正常流量并避免触发警报。
该操作持续演变,威胁行为体现在可以通过使用适配工具如ChromeKatz来绕过Chrome的应用绑定加密(ABE),从新版Chromium浏览器中窃取cookie。
引言
Discord是一个被广泛使用、深受信任的平台,受到游戏玩家、社区、企业等需要安全快速连接的人群的青睐。但如果你信任的平台不知不觉变成了陷阱呢?
Check Point Research发现了Discord邀请系统中的一个缺陷,允许攻击者劫持过期或删除的邀请链接,并秘密将不知情的用户重定向到恶意服务器。几个月前由可信社区在论坛、社交媒体或官方网站上发布的邀请链接,现在可能悄悄将你带入网络犯罪分子的手中。
我们观察到了真实世界的攻击,网络犯罪分子利用被劫持的邀请链接部署复杂的钓鱼方案和恶意软件活动,包括旨在逃避防病毒工具和沙箱安全检查的多阶段感染。
在本报告中,我们详细介绍了利用Discord邀请系统缺陷的新发现恶意软件活动。攻击者精心策划了多个感染阶段,并分发诸如针对加密货币钱包的Skuld窃取程序和获得受感染系统完全远程控制的AsyncRAT等有效载荷。值得注意的是,通过结合多种规避技术,攻击者能够悄无声息地分发恶意有效载荷,同时绕过Windows安全功能并避开许多防病毒引擎的检测。
理解Discord邀请链接
我们最近对Discord邀请链接劫持的调查显示,网络犯罪分子积极利用Discord的邀请系统进行钓鱼攻击。最初,我们讨论了攻击者如何利用Discord的自定义(个性化)邀请链接——这些特殊的邀请URL仅适用于拥有高级订阅(Level 3 Boost)的服务器。犯罪分子针对那些在失去Boost后自定义邀请链接过期的服务器,并将这些可识别的邀请URL据为己用。
进一步的研究表明,这个问题不仅限于自定义个性化链接,还包括标准邀请链接(例如,discord.gg/y1zw2d5)。
Discord生成随机邀请链接,使得合法服务器几乎不可能回收先前过期的邀请。然而,我们发现了一些实例,其中常规的随机生成邀请代码,最初由合法社区在网站或Telegram频道发布,现在将用户重定向到恶意的Discord服务器。这是如何实现的呢?
所有Discord邀请链接都遵循以下格式:
|
|
Discord中有三种主要类型的邀请链接:
1. 临时邀请链接
除非另有说明,否则Discord默认生成临时邀请链接。当通过Discord应用程序创建邀请时,可以选择30分钟、1小时、6小时、12小时、1天或7天(默认)的过期时间。
通过Discord的API生成时,可以选择任何自定义过期时间,最多7天。邀请代码是随机生成的,通常包含7或8个字符,结合大写字母、小写字母和数字。例如:
|
|
图1 – 在Discord应用程序中生成随机邀请代码。
2. 永久邀请链接
这些是通过明确选择“过期时间:永不”选项创建的。为永久邀请生成的代码包含10个随机生成的字母数字字符(大写、小写、数字)。
图2 – 在Discord应用程序中生成永久邀请链接。
永久邀请链接示例:
|
|
3. 自定义个性化邀请链接
这些仅适用于拥有高级订阅(Level 3 Boost)的Discord服务器。个性化邀请链接允许服务器管理员手动选择邀请代码,前提是该代码在所有Discord服务器中是唯一的。代码可以包含小写字母、数字或破折号,所有字母自动转换为小写。一个服务器一次只能有一个个性化链接。如果服务器失去其Boost,其自定义个性化链接可以被另一个Boosted服务器重新使用。
邀请代码重用与利用
创建常规随机生成的邀请链接后,一旦过期或删除,就无法再次获得相同的邀请链接。邀请代码是随机生成的,生成完全相同邀请代码的概率极低。
然而,创建自定义邀请链接的机制令人惊讶地允许你重用过期的临时邀请代码,并且在某些情况下,删除的永久邀请代码:
图3 – 在Discord应用程序中,将先前使用的来自另一个服务器的邀请代码分配为Boosted服务器的自定义个性化邀请链接。
攻击者积极利用这种行为。一旦临时邀请过期,其代码可以被注册为另一个拥有Level 3 Boost的Discord服务器的自定义邀请。如果一个合法的Discord服务器使用自定义个性化链接但后来失去其Boost状态(例如,由于未支付订阅费用),个性化邀请再次可用,攻击者可以将其声明为自己的恶意服务器。这造成了严重风险:遵循先前可信邀请链接(例如,在网站、博客或论坛上)的用户可能不知不觉被重定向到威胁行为者创建的虚假Discord服务器。
最安全的选择是使用永久邀请,它们更抗劫持。特别是,如果永久邀请代码包含任何大写字母,即使在删除后也无法重用。然而,在极少数情况下,如果删除的永久邀请仅由小写字母和数字组成(约占所有情况的0.44%),该代码可能再次可用,注册为个性化邀请。
下表总结了每种类型邀请的劫持风险:
邀请类型 | 是否可被劫持? | 解释 |
---|---|---|
临时邀请链接 | 是 | 过期后,代码变为可用,可以被另一个拥有Level 3 Boost的服务器重新注册为自定义个性化URL。 |
永久邀请链接 | 有条件 | 如果删除,仅包含小写字母和数字的代码可以被另一个拥有Level 3 Boost的服务器重新注册为自定义个性化URL。 |
自定义个性化邀请 | 是(如果丢失) | 如果原始服务器失去其Level 3 Boost状态,个性化邀请失效,可能被另一个Boosted服务器声明。 |
在Discord客户端的Web和桌面版本中,邀请代码管理行为创造了额外的风险因素。当用户通过服务器菜单中的“邀请人员”选项创建新的临时邀请并勾选“将此链接设置为永不过期”时,它不会修改已生成的临时邀请的过期时间。下图显示,当你点击“将此链接设置为永不过期”复选框时,Discord客户端显示链接设置似乎已更改,但邀请代码仍然是临时的(如我们所见,它由8个字符组成)。
图4 – 当你为现有链接设置“永不过期”时,其过期设置实际上并未改变。
用户经常错误地认为,只需勾选此框,他们就使现有邀请变为永久(正是这种误解在我们观察到的攻击中被利用)。结果,临时邀请在错误假设它们永不过期的情况下发布。这些链接最终在没有警告的情况下过期,使其代码易受劫持和恶意重用。
示例
让我们探讨攻击者如何在不同的条件下劫持Discord邀请链接。
案例1:仅包含小写字母和数字的临时邀请
假设一个合法服务器分享一个邀请链接如:https://discord.gg/yzqks3d
此代码仅包含小写字母和数字。只要邀请处于活动状态,攻击者就无法将其注册为个性化邀请。然而,一旦邀请过期或手动删除,代码变为可用。监控已知邀请代码的攻击者可以迅速将其声明为恶意Boosted服务器的个性化邀请。从那时起,任何使用此邀请(yzqks3d)的人将被重定向到攻击者的服务器。
案例2:包含大写字母的临时邀请
现在考虑另一个邀请代码:https://discord.gg/uzwgPxUZ
此代码包括大写字母。在这种情况下,攻击者可以使用相同代码的小写版本(uzwgpxuz)注册个性化邀请,即使原始邀请仍然有效。Discord允许这样做,因为个性化代码总是以小写形式存储和比较。
当原始邀请仍然有效时,遵循链接的用户将登陆正确的服务器。但一旦此邀请过期,点击先前合法链接(uzwgPxUZ)的用户被无缝重定向到攻击者的服务器,该服务器现在拥有该代码的小写个性化版本。
请注意,如果包含大写字母的原始邀请在其过期前手动删除,Discord继续将该代码视为保留,直到达到计划的过期时间。遵循原始链接(uzwgPxUZ)的用户在那之前不会被重定向到攻击者的服务器。
从可信链接到恶意Discord服务器
使用上述方法,攻击者劫持最初由合法社区分享的Discord邀请链接。遵循这些在社交媒体帖子或官方社区网站上找到的可信链接的用户,不知不觉地最终进入精心设计以看起来真实的恶意服务器。
加入后,新成员通常看到大多数频道被锁定,只有一个频道(通常名为“verify”)可访问。在此频道中,一个名为“Safeguard”的机器人提示用户完成验证步骤以获得完全服务器访问权限。
图5 – 用户点击被劫持的邀请链接后登陆的恶意Discord服务器。
检查机器人的信息显示,恶意机器人“Safeguard#0786”创建于2025年2月1日:
图6 – 恶意“Safeguard”机器人描述。
当用户点击“verify”按钮时,他们被要求授权机器人,重定向他们到一个外部网站:https://captchaguard[.]me。同时,机器人获得用户配置文件详细信息,如用户名、头像和横幅。
图7 – Safeguard机器人将用户重定向到钓鱼网站。
钓鱼网站
用户授权机器人后,Discord启动OAuth2认证流程。Discord生成一个一次性代码,并以如下格式的URL打开:https://captchaguard.me/oauth-pass?code=zyA11weHhTZxaY3Fs3EWBg6qfO7t6j。同时,使用此代码,网站从Discord获取用户名和服务器名称。成功从Discord检索用户数据后,服务器将用户重定向到另一个格式的URL:
|
|
在此URL中,“key”变量包含从Discord检索的BASE64编码数据,包括用户名、Discord公会和图标ID。该页面是静态的,并不实际验证在“key=”变量中接收的数据。因此,任何人都可以使用空值打开它:
|
|
重定向后,用户显示一个模仿Discord UI的精美网页。中心是一个“Verify”按钮,伴随一个绿色盾牌标志。
图8 – 钓鱼网站显示虚假验证消息。
点击“Verify”执行JavaScript,静默将恶意PowerShell命令复制到用户的剪贴板:
|
|
攻击者使用一种精致的UX技巧,称为“ClickFix”,一种服务最初显得损坏的技术,提示用户采取手动操作来“修复”它。在这种情况下,显示一个虚假的Google CAPTCHA加载失败,并显示手动“验证”说明。
此页面呈现一系列清晰、视觉引导的步骤以通过“验证”:打开Windows运行对话框(Win + R),粘贴预加载到剪贴板的文本,然后按Enter。网站避免要求用户手动下载或运行任何文件,移除了一个常见的危险信号。通过使用熟悉的Discord视觉元素和精美的布局,攻击者创造了一种虚假的合法性感。
图9 – 社会工程技术欺骗用户执行恶意命令。
实际上,此操作导致用户的计算机下载并执行托管在Pastebin上的PowerShell脚本:
|
|
Pastebin是一个公共Web服务,用户可以在线存储和分享纯文本,通常用于分享代码片段、日志或配置数据。当你创建一个新的“paste”时,它可以通过短链接如“https://pastebin[.]com/raw/{resource_id}”访问。通常,分享某些数据不需要注册。注册用户能够删除和编辑他们先前发布的数据。
使用Pastebin、GitHub和Bitbucket的多阶段有效载荷分发
我们在研究中发现的恶意软件活动遵循精心设计的多阶段感染链。威胁行为者利用Discord、钓鱼网站、社会工程、公共服务如Pastebin以及云平台如GitHub和Bitbucket的组合来分发其有效载荷。
下图总结了初始阶段,涉及通过被劫持的Discord邀请和上述详细说明的ClickFix技术进行钓鱼:
图10 – 感染链概述:从被劫持的Discord邀请到PowerShell下载器的执行。
在此阶段结束时,一个PowerShell脚本在受害者的机器上执行。此脚本从GitHub下载并运行一个第一阶段下载器(installer.exe),启动攻击的下一阶段。
在此阶段结束时执行的脚本从GitHub下载并运行一个第一阶段下载器(installer.exe),启动攻击的下一阶段。此阶段涉及从Bitbucket检索的多个加载器和有效载荷,最终部署恶意有效载荷,包括AsyncRAT和Skuld窃取程序:
图11 – 感染链概述:从PowerShell到最终恶意软件有效载荷分发。
现在让我们详细检查第二阶段的每个组件。
下载器PowerShell脚本
从Pastebin链接下载的脚本未混淆或加密。从其代码中我们可以看到,它从GitHub URL下载并运行一个可执行文件:
|
|
我们注意到几乎没有任何防病毒供应商将此脚本标记为恶意:
图12 – 恶意PowerShell脚本在VirusTotal上的检测率极低。
网络犯罪分子积极利用编辑Pastebin上发布信息的能力,更改从中下载可执行文件的GitHub URL。这可能允许他们绕过GitHub的阻止。如果存储库被删除,攻击者只需创建一个新账户和一个新存储库,将文件上传到其中。然后将新URL放入Pastebin脚本中。
在监控活动期间,我们观察到地址的以下变化:
|
|
第一阶段下载器:installer.exe
下载的可执行文件installer.exe(SHA256:673090abada8ca47419a5dbc37c5443fe990973613981ce622f30e83683dc932)的检测率极低。在我们研究时,VirusTotal上只有一个防病毒供应商将其标记为恶意:
图13 – 第一阶段下载器在VirusTotal上的检测率极低。
在持续监控活动期间,我们确定了加载器的一个新变体(SHA256:160eda7ad14610d93f28b7dee20501028c1a9d4f5dc0437794ccfc2604807693),在提交时在所有防病毒引擎中实现零检测。
图14 – 第一阶段下载器在VirusTotal上零检测。
此二进制文件充当下载器,从远程服务器检索其第二阶段有效载荷。
用C++编写,大小约4.8MB,该二进制文件未打包。然而,大量使用垃圾代码使其静态分析复杂化。此外,C++二进制文件固有地使分析复杂化,因为它们使用虚拟函数表、间接函数调用和复杂的运行时结构,使得快速识别相关代码路径具有挑战性。
乍一看,下载器似乎包含纯文本字符串;然而,几乎所有容易可见的字符串都属于旨在分散分析人员注意力的垃圾代码。实际上,与恶意功能相关的关键字符串通过作为立即值序列在运行时直接推送到堆栈上而被隐藏。每个字符串还使用单字节密钥的简单XOR密码进行加密。每个加密字符串使用不同的XOR密钥,通常在将加密字节写入堆栈的过程之前加载到CL寄存器中。相同的方法用于混淆重要的Windows API函数名称,其地址恶意软件使用GetProcAddress动态解析。
图15 – 加载器中的字符串和API调用混淆。
当