
Artigo técnico e código de exploração para CVE-2019-11932, uma vulnerabilidade de double-free no WhatsApp para Android que leva à execução remota de código através de um arquivo GIF manipulado.
Vou compartilhar sobre uma vulnerabilidade de double-free que descobri no WhatsApp para Android, e como a transformei em um RCE. Informei isso ao Facebook. O Facebook reconheceu e corrigiu oficialmente na versão 2.19.244 do WhatsApp. O Facebook ajudou a reservar o CVE-2019-11932 para este problema.
Usuários do WhatsApp, por favor, atualizem para a versão mais recente do WhatsApp (2.19.244 ou superior) para se manterem seguros deste bug.
Os passos são os seguintes:
Um deles poderia ser como Documento via WhatsApp (ou seja, pressionando o botão Clipe e escolhendo Documento para enviar o GIF corrompido) Se o atacante estiver na lista de contatos do usuário (ou seja, um amigo), o GIF corrompido é baixado automaticamente sem qualquer interação do usuário.
Observe que o usuário não precisa enviar nada, pois apenas abrir a Galeria do WhatsApp acionará o bug. Nenhum toque adicional após pressionar a Galeria do WhatsApp é necessário.
Quando um usuário do WhatsApp abre a visualização da Galeria no WhatsApp para enviar um arquivo de mídia, o WhatsApp o analisa com uma biblioteca nativa chamada libpl_droidsonroids_gif.so para gerar a pré-visualização do arquivo GIF. libpl_droidsonroids_gif.so é uma biblioteca de código aberto com códigos-fonte disponíveis em https://github.com/koral–/android-gif-drawable/tree/dev/android-gif-drawable/src/main/c.
Um arquivo GIF contém vários quadros codificados. Para armazenar os quadros decodificados, um buffer chamado rasterBits é usado. Se todos os quadros tiverem o mesmo tamanho, rasterBits é reutilizado para armazenar os quadros decodificados sem realocação. No entanto, rasterBits seria realocado se uma das três condições abaixo for atendida:
Realocação é uma combinação de free e malloc. Se o tamanho da realocação for 0, é simplesmente um free. Digamos que temos um arquivo GIF contendo 3 quadros com tamanhos 100, 0 e 0.
Isso resulta em uma vulnerabilidade de double-free. O local de acionamento pode ser encontrado em decoding.c:
int_fast32_t widthOverflow = gifFilePtr->Image.Width - info->originalWidth; int_fast32_t heightOverflow = gifFilePtr->Image.Height - info->originalHeight; const uint_fast32_t newRasterSize = gifFilePtr->Image.Width * gifFilePtr->Image.Height; if (newRasterSize > info->rasterSize || widthOverflow > 0 || heightOverflow > 0) { void *tmpRasterBits = reallocarray(info->rasterBits, newRasterSize, <<-- double-free here sizeof(GifPixelType)); if (tmpRasterBits == NULL) { gifFilePtr->Error = D_GIF_ERR_NOT_ENOUGH_MEM; break; } info->rasterBits = tmpRasterBits; info->rasterSize = newRasterSize; }
Como um bug de double-free no WhatsApp se transforma em RCE 14 minutos de leitura NESTA PÁGINA DEMO VULNERABILIDADE DE DOUBLE-FREE EM DDGIFSLURP EM DECODING.C EM LIBPL_DROIDSONROIDS_GIF CONTROLANDO O REGISTRADOR PC LIDANDO COM ASLR E W^X JUNTANDO TUDO VERSÕES AFETADAS VETORES DE ATAQUE Neste post do blog, vou compartilhar sobre uma vulnerabilidade de double-free que descobri no WhatsApp para Android, e como a transformei em um RCE. Informei isso ao Facebook. O Facebook reconheceu e corrigiu oficialmente na versão 2.19.244 do WhatsApp. O Facebook ajudou a reservar o CVE-2019-11932 para este problema.
Usuários do WhatsApp, por favor, atualizem para a versão mais recente do WhatsApp (2.19.244 ou superior) para se manterem seguros deste bug.
Demo https://drive.google.com/file/d/1T-v5XG8yQuiPojeMpOAG6UGr2TYpocIj/view
Link do Google Drive para baixar se o link acima não estiver acessível https://drive.google.com/open?id=1X9nBlf5oj5ef2UoYGOfusjxAiow8nKEK
Os passos são os seguintes:
0:16 Atacante envia arquivo GIF para o usuário por qualquer canal Um deles poderia ser como Documento via WhatsApp (ou seja, pressionando o botão Clipe e escolhendo Documento para enviar o GIF corrompido) Se o atacante estiver na lista de contatos do usuário (ou seja, um amigo), o GIF corrompido é baixado automaticamente sem qualquer interação do usuário. 0:24 Usuário quer enviar um arquivo de mídia para algum amigo do WhatsApp. Então o usuário pressiona o botão Clipe e abre a Galeria do WhatsApp para escolher um arquivo de mídia para enviar ao amigo. Observe que o usuário não precisa enviar nada, pois apenas abrir a Galeria do WhatsApp acionará o bug. Nenhum toque adicional após pressionar a Galeria do WhatsApp é necessário. 0:30 Como o WhatsApp exibe pré-visualizações de todas as mídias (incluindo o arquivo GIF recebido), isso acionará o bug de double-free e nosso exploit de RCE. Vulnerabilidade de double-free em DDGifSlurp em decoding.c em libpl_droidsonroids_gif Quando um usuário do WhatsApp abre a visualização da Galeria no WhatsApp para enviar um arquivo de mídia, o WhatsApp o analisa com uma biblioteca nativa chamada libpl_droidsonroids_gif.so para gerar a pré-visualização do arquivo GIF. libpl_droidsonroids_gif.so é uma biblioteca de código aberto com códigos-fonte disponíveis em https://github.com/koral–/android-gif-drawable/tree/dev/android-gif-drawable/src/main/c.
Um arquivo GIF contém vários quadros codificados. Para armazenar os quadros decodificados, um buffer chamado rasterBits é usado. Se todos os quadros tiverem o mesmo tamanho, rasterBits é reutilizado para armazenar os quadros decodificados sem realocação. No entanto, rasterBits seria realocado se uma das três condições abaixo for atendida:
largura * altura > larguraOriginal * alturaOriginal largura - larguraOriginal > 0 altura - alturaOriginal > 0 Realocação é uma combinação de free e malloc. Se o tamanho da realocação for 0, é simplesmente um free. Digamos que temos um arquivo GIF contendo 3 quadros com tamanhos 100, 0 e 0.
Após a primeira realocação, temos o buffer info->rasterBits de tamanho 100. Na segunda realocação de 0, o buffer info->rasterBits é liberado. Na terceira realocação de 0, info->rasterBits é liberado novamente. Isso resulta em uma vulnerabilidade de double-free. O local de acionamento pode ser encontrado em decoding.c:
int_fast32_t widthOverflow = gifFilePtr->Image.Width - info->originalWidth; int_fast32_t heightOverflow = gifFilePtr->Image.Height - info->originalHeight; const uint_fast32_t newRasterSize = gifFilePtr->Image.Width * gifFilePtr->Image.Height; if (newRasterSize > info->rasterSize || widthOverflow > 0 || heightOverflow > 0) { void *tmpRasterBits = reallocarray(info->rasterBits, newRasterSize, <<-- double-free here sizeof(GifPixelType)); if (tmpRasterBits == NULL) { gifFilePtr->Error = D_GIF_ERR_NOT_ENOUGH_MEM; break; } info->rasterBits = tmpRasterBits; info->rasterSize = newRasterSize; } No Android, um double-free de uma memória de tamanho N leva a duas alocações de memória subsequentes de tamanho N retornando o mesmo endereço.