Projeto
Para executar: ./script.sh
Repositório no GitHub - https://github.com/LaCinquette/practice-22-23
Andamento
-
Para buscar uma vulnerabilidade, escolhi o projeto FFmpeg. Encontrei nele um commit, que atendia aos requisitos, a saber:
- Correspondia ao tipo CWE-476 - desreferenciamento de ponteiro nulo
-
Criei um Dockerfile, no qual:
- Escolhi como imagem base Ubuntu 22.04
- Configurei
DEBIAN_FRONTEND=nointeractive para evitar interação com a linha de comando durante a instalação de pacotes e outros comandos
- Instalei as dependências necessárias listadas na wiki oficial
- Preparo o ambiente de trabalho (pasta workdir)
- Baixo, descompacto e movo o commit com a vulnerabilidade ainda não corrigida para o ambiente de trabalho
- Executo a compilação do programa usando a ferramenta make
- Crio o script copy_out.sh, que procura o arquivo objeto necessário com o erro e o copia para o diretório workspace/out
- Deixo uma instrução para executar o script copy_out.sh, que deve ser executada ao iniciar o contêiner
-
Para automação, crio o script script.sh, que constrói a imagem e inicia o contêiner, do qual então copio o arquivo e o movo para o diretório atual:
- Removo a pasta atual out (se existir)
- Construo a imagem com o nome ffmpeg_image
- Inicio o contêiner baseado na imagem construída, onde passo os seguintes parâmetros:
--rm para remoção automática do contêiner após a conclusão
-v $PWD/out:/workspace/out para montar um diretório temporário, através do qual o arquivo objeto é transferido para o host
- Copio o arquivo necessário da pasta out
- Removo a pasta out
Análise da Vulnerabilidade
Fontes:
- Commit com o erro corrigido
- Página no GitHub sobre a vulnerabilidade
- Carta do pesquisador de segurança sobre a vulnerabilidade
Análise:
Problema:
- Usando o comando
ffmpeg -c:v dnxhd -i poc.mov -y output.ts, um arquivo .mov especialmente criado é fornecido como entrada ao programa
- Para analisar o formato DNxHD, a função dnxhd_parse é chamada no arquivo dnxhd_parser
- Esta, por sua vez, chama a função dnxhd_find_frame_end (no mesmo arquivo), que sob certas condições não encontra o final e retorna um número negativo, que não é um código de erro
- Esse número, junto com outros parâmetros, é então passado para a função ff_combine_frame (localizada no arquivo parser) para combinar os quadros
- Como esse número não é um código de erro, ff_combine_frame o interpreta como um deslocamento e tenta ler novamente esses bytes no buffer, mas como o buffer está vazio nesse momento, ocorre uma desreferência de ponteiro nulo, resultando em uma falha de segmentação (Segmentation fault)
Em assembly:
0x08000d4e - início da seção
-
movsxd rcx, dword [rbx + 0xc]
No registrador rcx, obtemos a referência para pc->buffer
-
add rcx, rdi
Adicionamos next a pc->buffer
-
add rcx, qword [rbx]
Adicionamos pc->last_index a next e pc->buffer
-
movzx edi, byte [rcx]
Calculamos o byte no endereço rcx, mas como pc->buffer é inicialmente null, pegamos um Segmentation fault
Solução:
Prevenir o acesso a uma região de memória não alocada, tratando corretamente o caso excepcional. Ao detectar um número negativo de bytes restantes, continuar o processamento do arquivo pulando o ciclo.