
Informations et PoC sur la vulnérabilité ENLBufferPwn
| CVE: | CVE-2022-47949 |
| CVSS v3.1: | 9.8/10 (Critique) |
| Auteurs : | PabloMK7, Rambo6Glaz, Fishguy6564 |
| Signalé : | 8 août 2021 (Mario Kart 7) 14 avril 2022 (pour les jeux WiiU et Switch concernés) |
| Divulgué : | 22 décembre 2022 |
ENLBufferPwn est une vulnérabilité présente dans le code réseau commun de plusieurs jeux Nintendo first-party depuis la Nintendo 3DS, qui permet à un attaquant d'exécuter du code à distance sur la console de la victime en ayant simplement une partie en ligne avec elle (exécution de code à distance). Elle a été découverte indépendamment par plusieurs personnes en 2021 et signalée à Nintendo en 2021 et 2022. Depuis le signalement initial, Nintendo a corrigé la vulnérabilité dans de nombreux jeux concernés. Les informations contenues dans ce dépôt ont été divulguées en toute sécurité après avoir obtenu l'autorisation de Nintendo.
La vulnérabilité a obtenu un score de 9.8/10 (Critique) dans le calculateur CVSS 3.1.
Voici une liste des jeux connus pour avoir été vulnérables à un moment donné (tous les jeux Switch et 3DS listés ont reçu des mises à jour corrigeant la vulnérabilité, ils ne sont donc plus concernés) :
La vulnérabilité ENLBufferPwn exploite un débordement de tampon dans la classe C++ NetworkBuffer présente dans la bibliothèque réseau enl (Net dans Mario Kart 7), utilisée par de nombreux jeux Nintendo first-party. Cette classe contient deux méthodes, Add et Set, qui remplissent un tampon réseau avec des données provenant d'autres joueurs. Cependant, aucune de ces méthodes ne vérifie que les données d'entrée tiennent réellement dans le tampon réseau. Étant donné que les données d'entrée sont contrôlables, un débordement de tampon peut être déclenché sur une console distante en ayant simplement une session de jeu en ligne avec l'attaquant. S'il est bien exécuté, l'utilisateur victime peut même ne pas remarquer qu'une vulnérabilité a été déclenchée sur sa console. Les conséquences de ce débordement de tampon varient selon le jeu, allant de simples modifications inoffensives de la mémoire du jeu (comme ouvrir et fermer à plusieurs reprises le menu d'accueil sur la 3DS) à des actions plus graves, comme prendre le contrôle total de la console, comme illustré ci-dessous.
Le reste du rapport se concentrera sur Mario Kart 7, car en raison de l'absence de mesures de sécurité (ASLR, par exemple) sur la 3DS, il s'agit du cas le plus grave de la vulnérabilité. Cependant, il pourrait être possible de contourner l'ASLR sur les jeux Switch en détournant le NetworkBuffer utilisé pour renvoyer des données à l'attaquant (et en lui faisant fuiter des pointeurs vers le tas et le code).
La vidéo suivante illustre un cas grave de la vulnérabilité dans Mario Kart 7, où une console contrôlée par un attaquant (côté gauche) prend entièrement le contrôle d'une console non modifiée (côté droit). La seule interaction effectuée par l'utilisateur consiste à rejoindre une session de jeu en ligne avec l'attaquant, en l'occurrence en utilisant la fonctionnalité « communautés » (à noter qu'une « communauté » a été utilisée pour tester la vulnérabilité en toute sécurité, de manière isolée, afin de ne pas affecter les autres utilisateurs jouant dans des lobbies publics). La prise de contrôle s'effectue en copiant une charge utile ROP sur la console distante, puis en l'exécutant. Cette charge utile ROP exploite ensuite d'autres vulnérabilités de l'OS pour élever les privilèges et obtenir le contrôle total. Dans la vidéo, la console distante est forcée d'exécuter un installeur de CFW (SafeB9SInstaller). En utilisant les mêmes techniques, il serait théoriquement possible de voler des informations de compte/carte de crédit ou de réaliser des enregistrements audio/vidéo non autorisés à l'aide du micro/caméras intégrés de la console.
Comme indiqué précédemment, la vulnérabilité provient d'un oubli dans deux méthodes de la classe NetworkBuffer. Voici une implémentation de la classe et de ses méthodes en 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;
}
Comme vous pouvez le voir, ni Set ni Add ne vérifient que le newDataSize entrant tient dans la taille du tampon (dataSize). Cette classe NetworkBuffer étant utilisée comme conteneur générique pour échanger des données entre joueurs en ligne, le contenu de newData et la valeur de newDataSize peuvent être contrôlés par un attaquant, et un débordement de tampon peut être réalisé.
Un autre détail de la bibliothèque réseau est qu'elle est asynchrone, afin que les jeux puissent effectuer d'autres opérations pendant que les données remplissent le tampon. Pour y parvenir, une technique de double tampon est utilisée. Ainsi, le jeu peut accéder aux données déjà reçues dans un NetworkBuffer en même temps que de nouvelles données sont reçues. Une fois le second NetworkBuffer rempli, les tampons sont permutés et le cycle recommence.
Pour ce PoC, le double NetworkBuffer utilisé pour recevoir les données Mii (bufferType = 9) sera exploité. En raison de l'ordre d'allocation du tas, il se trouve que l'objet NetworkBuffer et son contenu sont placés côte à côte. De plus, les deux tampons du double tampon sont contigus en mémoire. Le diagramme suivant représente l'état de la mémoire après l'allocation des tampons :
