
Informações e PoC sobre a vulnerabilidade ENLBufferPwn
| CVE: | CVE-2022-47949 |
| CVSS v3.1: | 9.8/10 (Crítico) |
| Autores: | PabloMK7, Rambo6Glaz, Fishguy6564 |
| Reportado: | 8 de agosto de 2021 (Mario Kart 7) 14 de abril de 2022 (para os jogos de WiiU e Switch afetados) |
| Divulgado: | 22 de dezembro de 2022 |
ENLBufferPwn é uma vulnerabilidade no código de rede comum de vários jogos first-party da Nintendo desde o Nintendo 3DS que permite a um atacante executar código remotamente no console da vítima apenas ao jogar uma partida online com ela (execução remota de código). Ela foi descoberta por várias pessoas de forma independente durante 2021 e reportada à Nintendo durante 2021 e 2022. Desde o relato inicial, a Nintendo corrigiu a vulnerabilidade em muitos jogos afetados. As informações neste repositório foram divulgadas com segurança após obter permissão da Nintendo.
A vulnerabilidade obteve uma pontuação de 9.8/10 (Crítico) na calculadora CVSS 3.1.
Aqui está uma lista de jogos que se sabe terem tido a vulnerabilidade em algum momento (todos os jogos de Switch e 3DS listados receberam atualizações que corrigem a vulnerabilidade, portanto não são mais afetados):
A vulnerabilidade ENLBufferPwn explora um estouro de buffer na classe C++ NetworkBuffer presente na biblioteca de rede enl (Net no Mario Kart 7) usada por muitos jogos first-party da Nintendo. Essa classe contém dois métodos, Add e Set, que preenchem um buffer de rede com dados provenientes de outros jogadores. No entanto, nenhum desses métodos verifica se os dados de entrada realmente cabem no buffer de rede. Como os dados de entrada são controláveis, um estouro de buffer pode ser acionado em um console remoto apenas ao participar de uma sessão de jogo online com o atacante. Se feito corretamente, o usuário vítima pode nem notar que uma vulnerabilidade foi acionada em seu console. As consequências desse estouro de buffer variam conforme o jogo, desde simples modificações inofensivas na memória do jogo (como abrir e fechar repetidamente o menu inicial no 3DS) até ações mais graves, como assumir o controle total do console, conforme mostrado abaixo.
O restante do relatório se concentrará no Mario Kart 7, pois, devido à falta de medidas de segurança (ASLR, por exemplo) do 3DS, é o caso mais severo da vulnerabilidade. No entanto, pode ser possível contornar a ASLR em jogos de Switch sequestrando o NetworkBuffer usado para enviar dados de volta ao atacante (e fazendo-o vazar ponteiros para o heap e para o código).
O vídeo a seguir demonstra um caso severo da vulnerabilidade no Mario Kart 7, onde um console controlado por um atacante (lado esquerdo) assume totalmente um console não modificado (lado direito). A única interação feita pelo usuário é entrar em uma sessão de jogo online com o atacante, neste caso, usando o recurso de "comunidades" (observe que uma "comunidade" foi usada para testar a vulnerabilidade com segurança, de forma isolada, e não afetar outros usuários jogando em salas públicas). A tomada de controle é feita copiando um payload de ROP para o console remoto e, em seguida, executando-o. Esse payload de ROP usa então outras vulnerabilidades no sistema operacional para elevar privilégios e obter controle total. No vídeo, o console remoto é forçado a executar um instalador de CFW (SafeB9SInstaller). Usando as mesmas técnicas, seria teoricamente possível roubar informações de conta/cartão de crédito ou fazer gravações não autorizadas de áudio/vídeo usando o microfone/câmeras integrados do console.
Como mencionado anteriormente, a vulnerabilidade vem de uma falha em dois métodos da classe NetworkBuffer. Aqui está uma implementação da classe e dos métodos em 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;
}
Como você pode ver, nem Set nem Add verificam se o newDataSize recebido cabe no tamanho do buffer (dataSize). Como essa classe NetworkBuffer é usada como um contêiner genérico para trocar dados entre jogadores online, o conteúdo de newData e o valor de newDataSize podem ser controlados por um atacante, e um estouro de buffer pode ser realizado.
Outro detalhe da biblioteca de rede é que ela é assíncrona, para que os jogos possam realizar outras operações enquanto os dados estão sendo preenchidos no buffer. Para conseguir isso, uma técnica de buffer duplo é usada. Dessa forma, o jogo pode acessar dados já recebidos em um NetworkBuffer ao mesmo tempo em que novos dados estão sendo recebidos. Depois que o segundo NetworkBuffer é preenchido, os buffers são trocados e o ciclo se repete.
Para este PoC, o NetworkBuffer duplo usado para receber dados de Mii (bufferType = 9) será explorado. Devido à ordem de alocação no heap, acontece justamente que o objeto NetworkBuffer e seu conteúdo são colocados lado a lado. Além disso, ambos os buffers do buffer duplo são contíguos na memória. O diagrama a seguir representa como fica a memória após a alocação do buffer:

A partir de agora, o buffer no topo da imagem será referenciado como Buffer0, enquanto o buffer na parte inferior será Buffer1. Usando esse conhecimento, um atacante pode acionar o estouro de buffer em Buffer0 para sobrescrever os atributos de Buffer1, incluindo seu membro dataPtr. Como os jogos de 3DS não implementam ASLR, todos os endereços de memória no console remoto são conhecidos, então dataPtr pode ser apontado para um local arbitrário. Quando o jogo troca os buffers, os novos dados serão copiados para o local arbitrário. Seguindo os passos abaixo, um payload de qualquer tamanho pode ser copiado para o console remoto:
Buffer0. Ele acionará um estouro no console remoto, sobrescrevendo dataPtr de Buffer1.Buffer1 com dados arbitrários. Ele será copiado para o endereço arbitrário apontado por dataPtr de Buffer1 do console remoto.1.Abaixo está uma animação do funcionamento normal do jogo, seguida pela realização dos passos descritos acima.

Este repositório contém um PoC que explora esta vulnerabilidade para realizar as seguintes operações, dependendo das flags do compilador:
Tenha em mente que este PoC não implementa nenhum tipo de detecção de perda de pacotes, pois as comunicações entre consoles são feitas usando UDP. Para obter os melhores resultados, o tratamento de perda de pacotes deve ser implementado no código do PoC, ou os consoles devem ser colocados na mesma rede para reduzir as chances de perda de pacotes.
Uma possível correção da classe NetworkBuffer vulnerável também é fornecida.
A vulnerabilidade também está presente nas versões WiiU e Switch do Mario Kart 8, mas foi demonstrada apenas para o lançamento WiiU do jogo.
Embora esta vulnerabilidade tenha sido descoberta por vários usuários de forma independente, muitos deles decidiram manter as informações sobre a vulnerabilidade em sigilo. No entanto, as seguintes pessoas são responsáveis por divulgar a vulnerabilidade à Nintendo com segurança:
Na medida do possível, nos termos da lei,
PabloMK7, Rambo6Glaz e Fishguy6564
renunciaram a todos os direitos autorais e direitos conexos ou vizinhos sobre
ENLBufferPwn.
Este trabalho é publicado de:
Espanha.