| CVE: | CVE-2022-47949 |
| CVSS v3.1: | 9.8/10(严重) |
| 作者: | PabloMK7, Rambo6Glaz, Fishguy6564 |
| 报告时间: | 2021年8月8日(马里奥赛车7) 2022年4月14日(受影响的 WiiU 和 Switch 游戏) |
| 披露时间: | 2022年12月22日 |
ENLBufferPwn 是任天堂自 3DS 以来多款第一方游戏通用网络代码中的一个漏洞,攻击者只需与受害者进行一局在线游戏,即可在受害者主机上远程执行代码(远程代码执行)。该漏洞在 2021 年期间被多人独立发现,并于 2021 年和 2022 年报告给任天堂。自最初报告以来,任天堂已修复了多款存在漏洞的游戏。本仓库中的信息已在获得任天堂许可后安全披露。
该漏洞在 CVSS 3.1 计算器中评分为 9.8/10(严重)。
以下是已知曾经存在该漏洞的游戏列表(所列出的所有 Switch 和 3DS 游戏均已收到修复该漏洞的更新,因此不再受影响):
ENLBufferPwn 漏洞利用了 C++ 类 NetworkBuffer 中的缓冲区溢出,该类位于网络库 enl(在马里奥赛车7中为 Net)中,该网络库被众多任天堂第一方游戏使用。该类包含两个方法 Add 和 Set,它们用来自其他玩家的数据填充网络缓冲区。然而,这两个方法都没有检查输入数据是否确实适合网络缓冲区。由于输入数据可控,受害者只需与攻击者进行一局在线游戏,即可在远程主机上触发缓冲区溢出。如果操作得当,受害者用户甚至可能不会注意到其主机上被触发了漏洞。此缓冲区溢出的后果因游戏而异,从对游戏内存的简单无害修改(例如在 3DS 上反复打开和关闭主菜单)到更严重的操作,例如完全控制主机,如下所示。
报告的其余部分将重点介绍马里奥赛车7,因为 3DS 缺乏安全措施(例如 ASLR),该漏洞在此游戏中的危害最为严重。然而,在 Switch 游戏中,有可能通过劫持用于向攻击者回传数据的 NetworkBuffer(并使其泄漏堆和代码的指针)来绕过 ASLR。
以下视频展示了马里奥赛车7中该漏洞的一个严重案例:由攻击者控制的主机(左侧)完全接管了一台未修改过的主机(右侧)。用户所做的唯一操作就是与攻击者加入一局在线游戏,在本例中,使用的是“社群”功能(请注意,使用“社群”是为了以隔离的方式安全测试该漏洞,而不会影响在公开大厅中游戏的其他用户)。攻击者通过将 ROP 载荷复制到远程主机,然后执行该载荷来实现接管。该 ROP 载荷随后利用操作系统中的其他漏洞来提升权限并获得完全控制权。在视频中,远程主机被强制运行 CFW 安装程序(SafeB9SInstaller)。使用相同的技术,理论上可能窃取账户/信用卡信息或利用主机内置麦克风/摄像头进行未经授权的音视频录制。
如前所述,该漏洞源于 NetworkBuffer 类两个方法中的疏忽。以下是该类及其方法的 C++ 实现:
class NetworkBuffer
{
public:
u8 bufferType;
u8* dataPtr;
u32 dataSize;
u32 currentSize;
void Set(u8* newData, u32 newDataSize);
void Add(u8* newData, u32 newDataSize);
}
void NetworkBuffer::Set(u8* newData, u32 newDataSize)
{
memcpy(this->dataPtr, newData, newDataSize);
this->currentSize = newDataSize;
}
void NetworkBuffer::Add(u8* newData, u32 newDataSize)
{
memcpy(this->dataPtr + this->currentSize, newData, newDataSize);
this->currentSize += newDataSize;
}
如您所见,Set 和 Add 都没有检查传入的 newDataSize 是否适合缓冲区大小(dataSize)。由于该 NetworkBuffer 类被用作玩家之间在线交换数据的通用容器,newData 的内容和 newDataSize 的值都可以被攻击者控制,从而可以执行缓冲区溢出。
网络库的另一个特点是它是异步的,因此游戏在数据填充到缓冲区的同时可以进行其他操作。为了实现这一点,使用了双缓冲技术。这样,游戏就可以在接收新数据的同时访问 NetworkBuffer 中已接收的数据。当第二个 NetworkBuffer 被填满后,缓冲区会交换,并重复这一循环。
对于此 PoC,将利用用于接收 Mii 数据(bufferType = 9)的双 NetworkBuffer。由于堆分配的顺序,恰好 NetworkBuffer 对象及其内容被放置在彼此相邻的位置。此外,双缓冲区中的两个缓冲区在内存中是连续的。下图展示了缓冲区分配后的内存布局:

从现在起,图中顶部的缓冲区将称为 Buffer0,底部的缓冲区将称为 Buffer1。利用这些信息,攻击者可以触发 Buffer0 中的缓冲区溢出,从而覆盖 Buffer1 的属性,包括其 dataPtr 成员。由于 3DS 游戏未实现 ASLR,远程主机中的所有内存位置都是已知的,因此 dataPtr 可以指向任意位置。一旦游戏交换缓冲区,新数据就会被复制到该任意位置。通过执行以下步骤,可以将任意大小的载荷复制到远程主机:
Buffer0 发送。它会在远程主机中触发溢出,覆盖 Buffer1 的 dataPtr。Buffer1 的内容。这些数据将被复制到远程主机 Buffer1 的 dataPtr 所指向的任意地址。1 重新开始。以下是游戏正常运行以及执行上述步骤的动画。

本仓库包含一个 PoC,可根据编译标志利用该漏洞执行以下操作:
请注意,此 PoC 未实现任何形式的丢包检测,因为主机之间的通信使用 UDP。为了获得最佳效果,应在 PoC 代码中实现丢包处理,或者将各主机置于同一网络中,以减少数据包丢失的可能性。
易受攻击的 NetworkBuffer 类的可能修复方案也已提供。
该漏洞同样存在于 WiiU 和 Switch 版的马里奥赛车8中,但仅在 WiiU 版本上进行了演示。
虽然该漏洞是由多位用户独立发现的,但其中许多人决定对漏洞信息保密。不过,以下人员负责以安全的方式向任天堂披露了该漏洞:
在法律允许的最大范围内,
PabloMK7、Rambo6Glaz 和 Fishguy6564
已放弃对
ENLBufferPwn
的所有版权及相关或相邻权利。
本作品发布自:
西班牙.