关于《马力欧卡丁车8 豪华版》的"KartLANPwn"基于栈的缓冲区溢出漏洞的信息与概念验证
作者:Chad Hyatt
KartLANPwn 是《马力欧卡丁车8 豪华版》错误使用 Pia P2P 网络库而导致的漏洞,其中某些 "CopyAppData" 的实现被调用时,outBufSize 大于 out 缓冲区本身。如果与信息泄露结合,这可能导致对等方主机上的用户态远程代码执行(RCE)。KartLANPwn 影响了 Pia 在局域网/LDN 多人游戏和 NEX 在线多人游戏中的实现。
该漏洞影响所有版本直至并包括 v3.0.1 的《马力欧卡丁车8 豪华版》(中国/腾讯版为 v3.0.2),并且已通过 MK8DX 零售版 v3.0.1 的"局域网游玩"功能具体演示。
截至 2024/09/11,任天堂已随 v3.0.3 在所有地区(中国除外)部署了 KartLANPwn 的修复。截至 2024/09/27,v3.0.3 也已在中国地区发布。我们在获得任天堂许可后安全地披露了此信息。
专有的 Pia 网络库被任天堂第一方 Switch 游戏(支持本地或在线游玩)使用,为局域网/LDN(本地多人)和用于在线多人的 NEX 协议提供点对点网络代码实现。
为了演示,我们将特别关注 Pia 的局域网协议。房间主机的控制台在本地广播地址(255.255.255.255)的 :30000 端口上打开一个 UDP "发现"套接字,同一网络上的其他控制台应从自己的套接字(也在 :30000 端口)向路由器广告"浏览请求",以便转发到同一网络上的其他设备。
房间主机(我们的"服务器")回复一个初始的"浏览应答",该应答应包含房间信息(主机显示名称、Mii 数据、玩家数量等)。在浏览应答数据包中,要复制到 out 缓冲区的应用数据长度可以控制为最大 150 的值,尽管 out 只有 128 字节宽。这允许覆盖栈帧上的值(在此具体情况下,用于 pop {r4-r8, pc})
至少在 MK8DX 所使用的 Pia 版本中,对于我们所关注的内容,局域网的浏览应答数据包构造如下:
(所有整型类型编码为大端序)
会话信息的其余部分紧随其后,但对于构造 KartLANPwn 数据包并不重要
LAN_CopyAppData" 伪代码为演示起见,以下是局域网实现中 "CopyAppData" 的大致伪代码。尽管此函数本身没有内在问题,但错误使用(在 MK8DX 的情况下)允许我们的输入应用数据(在 packet 中)覆盖栈帧。
(在 MK8DX v3.0.1 的 main 中,函数位于 +0xA0F8C0)
void LAN_CopyAppData(int* r0, int packet, int out, uint outBufSize) {
int u1 = 68612;
if (out != NULL) {
// 从 `packet` 缓冲区中应用数据起始处读取的实际长度(由我们的 '服务器' 控制)
uint appDataLength = *(uint *)(packet + 432);
// 在某些情况下,outBufSize 被传入一个大于 `out` 缓冲区边界的数字,
// 从而允许发生栈缓冲区溢出(在我们的具体场景中,`*out` 长度为 128 字节,
// 而 outBufSize 为 150!)
if (appDataLength <= outBufSize) {
memcpy(out, packet + 48, outBufSize); // packet[47],应用数据起始处
u1 = 0;
}
*r0 = u1;
return;
}
*r0 = 68615;
return;
}
我们提供了一个用 Python 编写的简单 PoC 脚本,它充当一个虚假的房间主机,用特制的"浏览应答"数据包回复对等方的控制台;当您在与运行脚本的计算机同一网络的控制台上打开 MK8DX 的"局域网游玩"菜单时,该数据包将使游戏进程崩溃。
直接从 GitHub 下载 repo 的 zip 文件,或使用 git 克隆:
git clone https://github.com/latte-soft/kartlanpwn.git && cd kartlanpwn
python3 kartlanpwn-poc.py
查看视频演示(YouTube):
对于 ARM 爱好者,以下是从 GDB 截取的结果进程段错误截图:

弄清楚漏洞本身的细节只花了几天的功夫,但真正利用这个溢出?那是另一回事了。任天堂 Switch 内核的用户态可不是闹着玩的;它在每一个可能的角落都极其严格。我们花了很多小时交换和处理不同的想法和线索,最终没能实现真正的(任意)代码执行。在我们的具体场景中,即使是可靠的 ROP 似乎也不太可行,因为几乎所有与网络相关的函数都是基于类的,而且我们只能直接写入 r4-r8。(*_this 我的爱)另外,没有先前的信息泄露,仅仅跳过 mov r4, r0 之类来控制 _this 指针也不太可行。有趣的事情!
就报告而言,这次从提交报告到披露,与任天堂的沟通整体上还算顺利。虽然 $512 的赏金远低于我的预期(不都是这样吗?),但总比"任天堂忍者"找上门来要好……
任天堂肯定从 Wii、3DS 甚至 Wii U 的简单时代吸取了教训。他们做足了功课;要在 Switch 上从用户态成功利用任何超越拒绝服务崩溃的手段几乎是不可能的。ASLR、强制 No-eXecute 页面(您不能直接写入可执行内存页,游戏需要使用专用系统模块进行 JIT!)、无法 ROP,以及其他许多痛点。(等着模组社区很快打脸……) 另一方面,在过去的几个月里,我在很短的时间内学到了大量关于一个全新平台和架构(对我而言)的知识,更不用说我在 KartLANPwn 上合作过的那些棒极了的人!(感谢 Pablo 和 fishguy 😄)
KartLANPwn © 2024 根据 CC BY 4.0 许可。
要查看此许可协议的副本,请访问 https://creativecommons.org/licenses/by/4.0/
| 索引 | 伪类型 | 描述 |
|---|
| 0 | u8 | 数据包类型(0x1) |
| 1 | u32 | 会话信息体大小(此处为 1266) |
| 5 | (42 字节) | 杂项会话信息字段,与我们无关 |
| 47 | (0x180 字节) | 应用数据空间的起始位置 |
| 431 | u32 | 应用数据的长度 |
| 日期 | 信息 |
|---|
| 2024/07/18 | 通过 HackerOne 向任天堂提交报告 |
| 2024/07/31 | 报告进入内部分类 |
| 2024/09/11 | 修复伴随《马力欧卡丁车8 豪华版》v3.0.3 在所有地区(中国除外)发布 |
| 2024/09/12 | 任天堂支付赏金 |
| 2024/09/12 | 其他研究人员很快发现了 v3.0.3 的二进差异中关于"游戏网络代码安全漏洞"的修复 |
| 2024/09/27 | 中国地区发布《马力欧卡丁车8 豪华版》v3.0.3 |
| 2024/09/29 | 任天堂同意披露,本仓库公开 |
| 2024/09/30 | CVE-2024-45200 被 NVD 发布 |