
Análisis técnico y prueba de concepto para CVE-2024-45200, un desbordamiento de búfer basado en pila en la librería de red Pia P2P de Mario Kart 8 Deluxe, que permite un bloqueo remoto y una potencial ejecución remota de código (RCE) en Nintendo Switch.
Información y prueba de concepto de la vulnerabilidad de desbordamiento de búfer basado en pila "KartLANPwn" de Mario Kart 8 Deluxe
Escrito por Chad Hyatt
| CVE | CVE-2024-45200 |
| CVSS 3.1 | Indeterminado (Nintendo.. afirma que es un 4.3/10) |
| Recompensa pagada | $512 |
| Informe H1 | #2611669 |
| Descubierto | 2 de julio de 2024 |
| Corregido | 11 de septiembre de 2024 (v3.0.3) |
| Divulgado | 29 de septiembre de 2024 |
KartLANPwn es una vulnerabilidad en el uso incorrecto que hace Mario Kart 8 Deluxe de la biblioteca de red P2P Pia, en la que a veces se invoca a implementaciones individuales de "CopyAppData" con un outBufSize mayor que el propio búfer out. Esto puede conducir potencialmente a la ejecución remota de código (RCE) en modo usuario en las consolas de los pares si se encadena con una fuga de información. KartLANPwn afecta al uso de las implementaciones de Pia para el multijugador LAN/LDN y el multijugador online NEX.
Esta vulnerabilidad afecta a todas las versiones de Mario Kart 8 Deluxe hasta la v3.0.1 inclusive (v3.0.2 para China/Tencent), y se ha demostrado específicamente a través de la función "LAN Play" en la versión minorista v3.0.1 de MK8DX.
A partir del 2024/09/11, Nintendo ha desplegado un parche para KartLANPwn junto con la v3.0.3 para todas las regiones, excepto China. A partir del 2024/09/27, la v3.0.3 también se ha publicado para China. Hemos divulgado esta información de forma segura después de recibir permiso de Nintendo.
La biblioteca de red propietaria Pia es utilizada por los juegos de Nintendo Switch de primera parte con soporte para juego local u online para proporcionar implementaciones de netcode peer-to-peer para LAN/LDN (multijugador local) y el protocolo NEX, utilizado para el multijugador online.
Para fines de demostración, nos centraremos específicamente en el protocolo LAN de Pia. La consola del anfitrión de la sala abre un socket UDP de "descubrimiento" en :30000 en una dirección de broadcast local (255.255.255.255) y se supone que otras consolas en la misma red anuncian "solicitudes de exploración" desde su propio socket (también en :30000) al router para que las reenvíe a otros dispositivos en la misma red.
El anfitrión de la sala (nuestro 'servidor') envía de vuelta una "respuesta de exploración" inicial que se supone que contiene información sobre la sala (el nombre visible del anfitrión, los datos de Mii, el nº de jugadores, etc.). Dentro del paquete de respuesta de exploración, la longitud de los datos de aplicación que se copiarán en el búfer out puede controlarse con un valor de hasta 150, aunque out solo tiene 128 bytes de ancho. Esto permite desbordar valores en el marco de pila (en este caso concreto, para un pop {r4-r8, pc})
Al menos en el caso de la versión de Pia que usa MK8DX, para lo que nos ocupa, los paquetes de respuesta de exploración para LAN se construyen de la siguiente manera:
(Todos los tipos int están codificados como big-endian)
| Índice | Pseudo-Tipo | Descripción |
|---|---|---|
| 0 | u8 | Tipo de paquete (0x1) |
| 1 | u32 | Tamaño del cuerpo de la información de sesión (1266 en nuestro caso) |
| 5 | (42 bytes) | Campos diversos de información de sesión, irrelevantes para nosotros |
| 47 | (0x180 bytes) | Inicio del espacio para los datos de aplicación |
| 431 | u32 | Longitud de los datos de aplicación |
El resto de la información de sesión continúa, aunque no es importante para elaborar un paquete para KartLANPwn
LAN_CopyAppData"Con fines de demostración, a continuación se muestra un pseudocódigo aproximado de la implementación LAN de "CopyAppData". Aunque esta función por sí sola no tiene nada inherentemente incorrecto, un uso incorrecto (en el caso de MK8DX) puede permitir que el marco de pila sea sobrescrito por nuestros datos de aplicación de entrada en packet.
(función ubicada en +0xA0F8C0 en main para MK8DX v3.0.1)
void LAN_CopyAppData(int* r0, int packet, int out, uint outBufSize) {
int u1 = 68612;
if (out != NULL) {
// The actual length to read from the `packet` buffer at the start of our
// application data (which our 'server' controls)
uint appDataLength = *(uint *)(packet + 432);
// In some cases, outBufSize is input as a larger number than the bounds of the
// `out` buffer, which allows a stack buffer overflow (in our specific case, `*out`
// is 128 bytes long, and outBufSize is 150!)
if (appDataLength <= outBufSize) {
memcpy(out, packet + 48, outBufSize); // packet[47], start of application data
u1 = 0;
}
*r0 = u1;
return;
}
*r0 = 68615;
return;
}
Hemos proporcionado un sencillo script de PoC escrito en Python, que actúa como un anfitrión de sala falso que responde a las consolas de los pares con un paquete de "respuesta de exploración" especialmente manipulado que bloqueará el proceso del juego cuando abras el menú "LAN Play" en MK8DX desde una consola en la misma red que el ordenador que ejecuta el script.
O bien descarga el zip del repositorio directamente desde GitHub, o clónalo usando git:
git clone https://github.com/latte-soft/kartlanpwn.git && cd kartlanpwn
python3 kartlanpwn-poc.py
Ver demostración en vídeo (YouTube):
Y para los frikis de ARM, aquí tenéis una captura de pantalla de GDB del segfault resultante del proceso:

Solo nos llevó un par de días averiguar los detalles del bug en sí, pero ¿hacer uso real del desbordamiento? Eso ya es harina de otro costal. El modo de usuario del kernel de Nintendo Switch no se anda con bromas; es extremadamente estricto en cada recoveco posible. Pasamos muchas horas intercambiando y manipulando diferentes ideas y pistas, sin éxito final para una ejecución de código real (arbitraria). En nuestro caso concreto, incluso un ROP fiable no parecía muy viable, ya que prácticamente todas las funciones relacionadas con la red estaban basadas en clases, y además solo teníamos acceso de escritura directo a r4-r8. (*_this mi amado) Además, sin una fuga de información previa, no es muy viable simplemente saltarse un mov r4, r0 o lo que sea para controlar el puntero _this. ¡Menuda diversión!
En cuanto al informe, todo fue en realidad un proceso relativamente fluido esta vez con el triaje de Nintendo desde el momento del informe hasta la divulgación. Aunque el pago de la recompensa de $512 fue mucho menos de lo que anticipaba (¿no lo son siempre?), cualquier cosa es mejor que los "Nintendo Ninjas" apareciendo en mi puerta..
Nintendo definitivamente aprendió la lección, por así decirlo, de los días más simples de la Wii, la 3DS e incluso la Wii U. Hicieron los deberes; la explotación exitosa de cualquier tipo más allá del bloqueo por denegación de servicio desde el modo de usuario en la Switch es casi imposible. ASLR, páginas No-eXecute forzadas (no puedes escribir directamente en páginas de memoria ejecutables; los juegos necesitan usar un sysmodule dedicado solo para JIT), incapacidad de hacer ROP, entre otros puntos dolorosos. (esperando que la escena del modding se coma estas palabras en nada..) Por otro lado, en los últimos meses he aprendido muchísimo sobre una plataforma y arquitectura completamente nuevas (para mí, al menos) en muy poco tiempo, sin mencionar a la gente increíble con la que he tenido el placer de trabajar en KartLANPwn! (Gracias Pablo y fishguy 😄)
| Fecha | Información |
|---|---|
| 2024/07/18 | Informe enviado a Nintendo a través de HackerOne |
| 2024/07/31 | Informe clasificado internamente |
| 2024/09/11 | Parche publicado junto con Mario Kart 8 Deluxe v3.0.3 para todas las regiones, excepto China |
| 2024/09/12 | Recompensa pagada por Nintendo |
| 2024/09/12 | Otros investigadores descubrieron bastante rápido el parche para "una falla de seguridad en el netcode del juego" en el bindiff de la v3.0.3 |
| 2024/09/27 | Mario Kart 8 Deluxe v3.0.3 publicado para la región china |
| 2024/09/29 | Nintendo concedió la divulgación; este repositorio se hizo público |
| 2024/09/30 | CVE-2024-45200 publicado por el NVD |
KartLANPwn © 2024 está bajo la licencia CC BY 4.0.
Para ver una copia de esta licencia, visita https://creativecommons.org/licenses/by/4.0/