2026 年 10 月 18 日,加州理工本科生 Sammy Hajhamid(网名 pepsipu)在个人博客发布《jailbreaking the switch 2》,公开了名为 ns2jb 的 Switch 2 纯软件越狱方案;10 月 21 日,exploit 代码在 GitLab 开源。它工作在任天堂当前最新固件 23.0.1 上,是公开出现的首个 Switch 2 软件越狱。ns2jb 属于系留式(tethered)越狱:重启后失效,不安装持久化自定义固件,但在一次开机会话内,它能以任意普通 sysmodule(系统模块)的身份运行原生代码,包括内置的 fs(文件系统)模块本身。自制软件、游戏 mod、存档备份、经 MMIO 访问主机外设,都因此成为可能。
文章发布后登上 Hacker News 首页,拿到超过 670 分与两百多条讨论。作为能力演示,OpenAI 的编码智能体 Codex 用越狱成果给 Switch 2 独占游戏《马力欧卡丁车世界》加了新角色:玉桂狗、索尼克、加菲猫、初音未来,连同物理学家基普·索恩、彼得·格里芬一起出现在同一场比赛的排行榜上,加州理工 Dabney 宿舍的朋友负责挑选角色和试玩。
一台被 AI 远程驾驶的主机
博客配图里的硬件编排架是整个项目最先被讨论的部分:两台 JetKVM 设备经 USB 向 Switch 1 和 Switch 2 注入手柄输入,画面经 HDMI 采集回传给 AI;主机崩溃后需要按下电源键重启,这个动作由一只从亚马逊购入的蓝牙灯泡开关完成,杠杆压下时正好按下电源键,随后杠杆的剩余力矩会把开关机构抬回原位。

这里需要把分工写准。中文网络流传的版本是「AI 用一句提示词自主越狱 Switch 2」,作者在原文中澄清:那条病毒式传播的提示词只是配图玩笑,他确实给 Codex 设过「拿到用户态代码执行」的自主目标,但没有成功。越狱本体花了他约两周的高强度工作,Codex 的贡献贯穿全程:SmileBASIC 解释器里的整数溢出漏洞是 Codex 找到的,BufferedStorage 这个堆攻击落脚点是 Codex 找到的,ROP 链是 Codex 拼出来的,连发布安装包都是 Codex 打的,README 第一行写着「感谢 Codex 尽责地打包了这些 exploit」。《马力欧卡丁车世界》的 mod 倒确实是 Codex 一天「氛围编程」出来的,纯属娱乐。
入口为什么是一款 Basic 编程游戏
WebKit 是游戏主机越狱的传统目标,Switch 2 的 WebKit 可以经伪造的 Wi-Fi 强制门户离线触达,任天堂的漏洞赏金计划也覆盖这个方向。Codex 的 WebKit 会话确实拿到了成果:利用一个 n-day 实现了 UAF 到 addrOf 再到任意读写,把 Math.expm1 重定向到 XHR 的 PAC 签名 NativeExecutable,目标计时 42 分钟内日志打出了 NATIVE_CONTROL_23_0_0,全程未伪造 PAC 指针。

这条路随后被放弃。在 JavaScript 里把一个函数对象替换成另一个,无法泛化成任意的 IPC 调用,而后者才是攻击微内核服务所需要的。作者转向另一类思路:找一款 Switch 1 时代发布、在 Switch 2 上以兼容模式运行的老游戏作为跳板。一款内嵌浏览器引擎的老游戏(类比 Electron 应用)的发现暂不能公开;另一款入选者是大名鼎鼎的 SmileBASIC 4,一个装在游戏卡带里的 Basic 解释器。理由有二:它是体量巨大的 C++ 代码库,前作 smilehax 曾在 3DS 时代拿到过用户态代码执行;解释器这类解析复杂输入的代码,历史上就是内存破坏漏洞的高发区。
整数溢出出现在 REMOVE 命令里。删除数组元素时,解释器检查 position + count <= array.length,但这个 32 位有符号加法可以回绕成负数,检查形同虚设;随后填补空隙的 memmove 的三个长度参数都乘以 8,同样回绕,最终实际执行的是 memmove(backing, backing - 8, 32),把数组前面的 8 个字节拉进数组内部。关键在于,SmileBASIC 中任何数组前面的 8 字节都存着一个指向数组自身的指针。此后对 R[0] 的操作会把它当作字符串处理,指针占据了长度字段的位置,字符串长度大到失控,越界读写靠子串拷贝完成。命令照样会报 Out of memory 错误,但拷贝已经发生。README 把触发语句 REMOVE NSR,&H60000000,&H3FFFFFFF 直接写进了运行步骤,并注明这个报错属于预期行为。
fs 模块:从堆溢出到任意读写
拿到用户态的原语后,下一个目标是特权进程。作者给多个 Codex 实例下达了「拿下 sysmodule 代码执行」的目标,它们大多选择了 audio 和 ldn(两者在 Switch 2 上都出过漏洞),还有人盯上了 NV 服务。作者本人则研究内置的 fs 模块:Switch 1 时代它就有成熟的分析积累,文件系统 API 跨代变化不大,而且就算打不穿,也能借它解密其他 sysmodule 的代码,交给 Codex 离线审计。
攻击点在 IFileSystem 句柄的 IPC 命令 GetEntryType 上。传入的路径字符串经 Path::Normalize 归一化,含反斜杠的父目录组件(如 /..\)会调用一个分配 0x301 字节临时堆缓冲区的辅助函数,而拷贝进去的路径可以比缓冲区更长,缓冲区溢出成立。溢出需要一个合适的受害者分配:Codex 发现 BufferedStorage 对象会为文件分配缓存条目,dirty 位置位后,文件的读写会跟随一个指向缓存数据的指针。劫持这个指针,就得到了 fs 进程内的任意读写。作者随后扫描内存定位 SmileBASIC 的连接对象,把其中保存的 PID 改成 1,进程由此获得 FullPermission,转储了内部存储和全部普通 sysmodule 的代码。
信任链的缺口:签名校验放在了错误的一层
Switch 2 的用户态防御相当齐全:转储结果显示所有 sysmodule 都启用了 CFI(控制流完整性)、PAC(指针认证)和 XOM(仅执行内存),唯一有权映射可执行内存的普通 sysmodule 是 ro。正面强攻 ro 的内存破坏不划算,作者选择了逻辑漏洞。
游戏和普通 sysmodule 以 NCA(Nintendo Content Archive)格式分发,内含名为 ExeFS 的文件系统镜像,其中有主程序 main 和元数据 main.npdm。加载程序 ldr 启动一个进程时,向 fs 请求打开 ExeFS,fs 交回 IPC 句柄,同时提交 NCA 头的 SHA-256 哈希与开发者对该哈希的签名。ldr 用这些信息做两道校验:main.npdm 声明的进程权限是否合法、开发者公钥是否有效。
密码学本身挑不出毛病,缺口在前提上:「fs 交出的文件系统与 NCA 头哈希一致」由 fs 负责保证,而攻击者的任意读写恰好就在 fs 里。ldr 拿到句柄后,用任意读写把句柄背后的 ExeFS 对象换成自己的临时文件系统:main.npdm 用合法开发者的原版,第一道校验照常通过;主程序 main 则完全任意,因为哈希和签名早在对象替换前就以原版文件系统的内容提交了。两处写操作必须发生在 ldr 请求文件系统之后、fs 处理后续文件请求之前。fs 进程维护着 IPC 连接列表,逐个处理新消息;把 fs 等待 ldr 连接消息的那个句柄换成 SmileBASIC 可控制的事件句柄,消息的处理时机就由攻击者掌握。这是一个教科书式的 TOCTOU(检查与使用的时间差)漏洞。
启动任意代码还差一步:一个权限足够的 NPDM。任意读写可以借 ldr 的 fsp-srv 连接复制任何 sysmodule 或游戏的 NPDM,选择全部都在。ro 的 NPDM 授权调用 MapProcessMemory 等内核 SVC,可以对 fs 已有代码建立可写视图,dump 或打补丁。这些调用需要 fs 的 KProcess 句柄:用任意读写把 IEventNotifier 的 4 字节句柄改写成 0xffff8001,内核把这个值解释为「当前进程的句柄」,于是 SmileBASIC 调用 GetEventHandle 拿到的就是 fs 的 KProcess 句柄,转交给自定义 ro 进程,由它给 fs 打上补丁。
完整攻击链如下:
| 阶段 | 目标组件 | 漏洞或技巧 | 产物 |
|---|---|---|---|
| 入口 | SmileBASIC 4(Switch 1 兼容游戏) | REMOVE 整数回绕 + 数组头指针 | 用户态越界读写 |
| 横向 | 内置 fs sysmodule | Path::Normalize 0x301 溢出 + BufferedStorage 劫持 | fs 进程内任意读写 |
| 提权 | fs 连接对象 | PID 改写为 1(FullPermission) | 内部存储与模块代码转储 |
| 信任链绕过 | ldr 加载校验 | ExeFS 对象替换(TOCTOU) | 任意代码以任意 NPDM 启动 |
| 控制 | 内核句柄语义 | 0xffff8001「当前进程」句柄 | ro 进程给 fs 打补丁 |
它现在能做什么,不能做什么
README 把使用门槛写得清楚:需要 SmileBASIC 4.4.9、系统固件 23.0.1、macOS 或 Linux 上的 Node.js 22+、存档区 20 MiB 空闲空间,主机与电脑处于同一可达网络(连接走 39380 端口)。演示内容是在 fs 进程里运行两个小原生函数、校验结果、恢复原始指令。2026 年 10 月 21 日的物理实测通过了全部检查,但成功发生在第三次冷启动:前两次停在验证检查并自动清理。时序敏感是当前版本的现实。演示跑完后重启主机即恢复原状,不安装自定义固件,没有持久化。payload 用 Zig 0.15.2 构建,仓库里附了原生辅助代码的源码。
在 Hacker News 的讨论里,有开发者提出,既然 fs 的读写是解密后的,Switch 2 游戏转储可能很快出现;配合近一个月兴起的重编译(recompilation)路线,把主机独占游戏移植到任意硬件运行,对任天堂是最坏情形。反对意见同样具体:Switch 1 的模拟器生态成熟多年也未动摇任天堂基本盘,1.5 亿台对 600 万台的装机量差距摆在那里。长期参与 3DS 社区的开发者 TuxSH 补充了赏金背景:任天堂赏金计划 5 万美元档针对的是 PSC 或 TSEC 协处理器级别的核心妥协,本次发布的内容不在其中;也有评论问到,漏洞如果是 Codex 找到的,赏金应该归 OpenAI 还是归提交者。
作者对后续路线的规划列了三条:把 fs 漏洞接回 WebKit 路径,因为浏览器攻击面离线可达,任天堂无法像下架 eShop 游戏那样把它撤掉;继续审计其他内置 sysmodule,fs 是内置模块,服务管理器 SM 对它跳过服务 ACL 检查,同类能力值得继续找;编排 fs 掌管的加密硬件,例如 NCA4 解密。他还写了对任天堂长期方向的判断:把代码映射改成只有内核或安全监控器能解密的加密 blob,让用户态永远看不到 RX 映射。任天堂已经移除了 JIT sysmodule,这个方向并非空想。


对越狱社区的直接意义在于侦察阶段的完成:全部普通 sysmodule 的代码已可转储,硬件外设可以在不逐个攻破驱动的前提下经 MMIO 探测,CFW(自定义固件)的路径第一次在 Switch 2 上显形。对任天堂的意义同样明确:SmileBASIC 4.4.9 和 fs 的两处缺陷大概率出现在下一版固件的修复清单里,而在修复推送之前,每一台零售 Switch 2 都暴露在同一条攻击链下。
来源: