
CVE-2019-5700
Infelizmente, não tenho um nome moderno e criativo para esta vulnerabilidade. Este bug é bastante simples de explorar. Na verdade, fiquei com ele por bastante tempo até perceber que isso poderia afetar mais dispositivos do que eu pensava inicialmente.
Este bug afeta SoCs Nvidia Tegra t114-t210 que inicializam imagens de boot Android, porém há uma distinção importante a ser feita:
Dispositivos baseados em t114 são severamente mais afetados por causa do seu bootloader unificado que também carrega o TOS (TLK - monitor seguro da Nvidia), o que significa que o bootloader já está rodando em contexto seguro...
Em dispositivos t124+, a Nvidia agora usa o nvtboot como bootloader de estágio inicial que carrega o TOS antes da execução do bootloader vulnerável, que carrega e executa o kernel. Isso significa que estamos rodando em contexto não seguro.
Vamos dar uma olhada no cabeçalho da imagem de boot do Android (v1 - anterior ao Android 9):
struct boot_img_hdr
{
uint8_t magic[BOOT_MAGIC_SIZE];
uint32_t kernel_size; /* size in bytes */
uint32_t kernel_addr; /* physical load addr */
uint32_t ramdisk_size; /* size in bytes */
uint32_t ramdisk_addr; /* physical load addr */
uint32_t second_size; /* size in bytes */
uint32_t second_addr; /* physical load addr */
uint32_t tags_addr; /* physical addr for kernel tags */
uint32_t page_size; /* flash page size we assume */
uint32_t unused;
uint32_t os_version;
uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */
uint8_t cmdline[BOOT_ARGS_SIZE];
uint32_t id[8]; /* timestamp / checksum / sha1 / etc */
uint8_t extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
};
Vemos os campos para algumas imagens conhecidas: kernel, ramdisk:
uint32_t kernel_size; /* size in bytes */
uint32_t kernel_addr; /* physical load addr */
uint32_t ramdisk_size; /* size in bytes */
uint32_t ramdisk_addr; /* physical load addr */
e às vezes tags (que muitas vezes é usado para device tree ou ATAGS)
uint32_t tags_addr; /* physical addr for kernel tags */
uint32_t page_size; /* flash page size we assume */
E quanto aos campos 'second'?
uint32_t second_size; /* size in bytes */
uint32_t second_addr; /* physical load addr */
Embora eu nunca tenha visto isso ser usado em um dispositivo de produção pessoalmente, meu entendimento é que a imagem 'second' pode ser usada para um bootloader de segundo estágio ou para uma imagem adicional que precisa ser carregada. Na minha experiência de pesquisa, a maioria dos bootloaders de outros OEMs ignora esse campo - por não ser usado - ou aplica verificações de sanidade no tamanho e no endereço.
O bootloader da Nvidia REALMENTE aplica verificações de sanidade ao kernel, ramdisk e dtb - todos com endereços de carregamento fixos no código, o que significa que os endereços de carregamento no cabeçalho são ignorados. No entanto, parece que a Nvidia talvez tenha esquecido dessa imagem quase esquecida... carregando-a arbitrariamente sem verificações de sanidade no endereço ou no tamanho. Isso mesmo - você pode carregar arbitrariamente qualquer imagem, de qualquer tamanho, para qualquer endereço de memória acessível (tudo em t114, memória não segura em t124+).
Isso significa que podemos modificar livremente o bootloader na memória de acordo com nossas necessidades. Seja para pular a verificação de assinatura (que vem imediatamente após carregar todas as imagens), sequestrar o carregamento do TOS em t114 para obter execução de código em contexto seguro, ou simplesmente carregar algum shellcode para despejar informações sensíveis.
A exploração é tão simples quanto criar uma imagem de boot com a imagem secundária como seu payload/shellcode e os campos addr/len definidos apropriadamente para o tamanho do seu payload e para onde você quer que ele vá. A imagem pode ter apenas 4 bytes.
Em dispositivos t124+, não temos contexto seguro, pois o nvtboot já carregou o TOS em um estágio anterior da inicialização, que então entrega a execução a um bootloader de estágio posterior (EBT), mas ainda podemos escrever livremente nesse bootloader de estágio final na memória. O bootloader vulnerável é o que carrega o kernel, então ele ainda é bastante valioso se você quiser executar código arbitrário não assinado.
Não só o endereço de carregamento não é verificado, como também o tamanho não é, o que abre as portas para o CVE-2019-5699, já que podemos causar overflow em várias variáveis/ponteiros criando um campo secondary_size malicioso. No entanto, não posso levar o crédito por isso, pois só percebi isso em retrospectiva após a publicação do boletim de segurança inicial. Além disso, parece muito mais trabalho...
t114:
IROM->BCT->EBT->TOS->KERNEL
t124+ (pode ser ligeiramente diferente para SoCs 64-bit mais novos):
IROM->BCT->NVTBOOT->TOS->EBT->KERNEL
Este problema foi inicialmente relatado em 29 de julho de 2019 ao PSIRT da Nvidia (Product Security Incident Response Team). Eles pediram educadamente que eu adiasse a divulgação até que todos os clientes relevantes tivessem sido notificados e as correções fossem lançadas - o que fiz com prazer. Eles mantiveram comunicação durante todo o processo e foram agradáveis de trabalhar. Hoje (5 de dezembro de 2019), a Nvidia finalmente terminou de lançar a correção para o código afetado e publicou dois boletins de segurança diferentes refletindo este problema, além de me dar o sinal verde para a divulgação.
https://nvidia.custhelp.com/app/answers/detail/a_id/4875
https://nvidia.custhelp.com/app/answers/detail/a_id/4910
balika011
beaups
npjohnson
djrbliss/Dan Rosenberg por me fazer verificar meticulosamente como bootloaders analisam cabeçalhos de imagem de boot