Logotipo da Team82 Claroty
Retornar ao blog

Pwn2Own: demonstração de exploração de WAN para LAN, parte 1

/

Resumo executivo

  • Claroty A Team82 participou no último outono do concurso de hackers de IoT Pwn2Own 2023 Toronto e explorou roteadores TP-Link ER605 e câmeras IP Synology BC500

  • Demonstramos por meio desta pesquisa como um invasor pode comprometer um dispositivo conectado à rede de área ampla e passar para a rede local a fim de comprometer um dispositivo IoT conectado.

  • Na primeira parte desta série, explicamos nossa pesquisa e ataque aos roteadores TP-Link ER605. A segunda parte abordará como passamos do roteador para a rede local para comprometer a câmera IP Synology BC500. 

  • A TP-Link corrigiu as vulnerabilidades que relatamos na versão de firmware ER605 (UN) V22. 2.4 Build 20240119

  • A Synology corrigiu as vulnerabilidades que relatamos na versão de firmware 1.0.7-0298 e lançou um aviso de segurança.

Pwn2Own Toronto 2023: Edição IoT | Exploit SOHO Mashup

Introdução

Quase todas as pessoas que se conectam à Internet a partir de uma rede de pequeno escritório/escritório doméstico (SOHO) o fazem a partir de um layout de rede semelhante. O dispositivo mais essencial para fazer a ponte entre a rede local e a Internet é o roteador. Os roteadores não apenas ajudam a rotear o tráfego de rede, mas também atuam como uma proteção que divide a rede local interna (LAN) e a Internet externa, a rede de longa distância (WAN), impedindo o acesso externo indesejado aos dispositivos internos. Portanto, explorar roteadores da WAN e ignorar a tradução de endereços de rede (NAT) é perigoso e representa um risco significativo para a rede local.

Na competição Pwn2Own Toronto 2023, demonstramos nosso ataque de pivô de WAN para LAN, explorando um roteador TP-Link a partir da WAN. Em nossa pesquisa, analisamos as maneiras pelas quais um invasor pode se infiltrar da WAN para a LAN, descobrindo vulnerabilidades nos roteadores TP-Link que permitem que os invasores contornem a proteção NAT. Depois de obter a execução remota de código (RCE) no roteador, passamos para a LAN e desenvolvemos uma exploração contra uma câmera IP Synology, movendo-nos lateralmente dentro da rede.

Neste blog, apresentaremos nossa pesquisa, incluindo técnicas avançadas de exploração incorporada, e nossa abordagem e metodologias para descobrir um novo desvio de NAT e vulnerabilidades de dispositivos IoT.

Na primeira parte desta série de duas partes, abordaremos nossas técnicas de exploração de roteadores; na segunda parte, explicaremos como usamos os roteadores para passar da WAN para a LAN. 

Portanto, apertem os cintos, pois teremos uma longa viagem!

Exploração de WAN: Roteador TP-Link ER605

O roteador TP-Link ER605 é apresentado como um roteador VPN para consumidores e pequenas empresas.

O dispositivo é descrito como tendo medidas de segurança, como políticas de firewall e defesas contra negação de serviço (DoS). Esse roteador também tem interfaces de gerenciamento baseadas na nuvem.

Detalhes técnicos

Como queríamos obter a exploração da WAN, procuramos superfícies de ataque relacionadas à WAN. Um recurso suportado pelo roteador é o serviço de DNS dinâmico (DDNS). O DDNS permite que um dispositivo com IP dinâmico mantenha um registro de nome de domínio que muda dinamicamente quando seu IP muda. Um dos provedores de DDNS que a TP-Link optou por suportar é o Comexeque usa um protocolo DDNS personalizado para se comunicar com o servidor do provedor. Para interagir com o provedor do serviço, o dispositivo usa um binário localizado em /usr/sbin/cmxddnsd. Enquanto pesquisava o cmxddnsd binário, encontramos três vulnerabilidades que, quando encadeadas, nos permitiram obter a execução remota de código a partir do lado da WAN.

Vulnerabilidade nº 1: validação inadequada da autenticidade do servidor(CVE-2024-5242)

Começamos examinando o binário cmxddnsd. Durante a inicialização e periodicamente depois disso, o binário tenta acessar seus servidores DDNS para iniciar uma conexão DDNS e atualizar seu endereço IP externo. Por padrão, o roteador é configurado com dois servidores Comexe DDNS Dns1.comexe.net, Dns1.comexe.cn.

Para obter o endereço IP do servidor, cmxddnsd tenta resolver o nome DNS do servidor DDNS consultando o resolvedor de DNS do roteador. Depois de recuperar o endereço IP, o binário inicia uma conexão UDP com o servidor DDNS por meio de UDP/9994. O protocolo usado para se comunicar com os servidores DDNS é proprietário, portanto, tivemos que pesquisar o binário para entender melhor o protocolo. 

Após algumas pesquisas, descobrimos que o protocolo usado para a comunicação DDNS é o seguinte: cada mensagem é composta de dois segmentos:

  1. um arquivo criptografado Dados segmento

  2. um segmento de mensagem chamado 'C' (C=1 por exemplo) indicando a direção da mensagem (servidor para cliente ou cliente para servidor). Para separar as diferentes partes da mensagem, a Comexe usou um único byte de \x01 para separar as diferentes partes. 

Uma solicitação e resposta DDNS, contendo o segmento de dados criptografados da solicitação.

Para criptografar/descriptografar o segmento de dados da mensagem, a Comexe usa o 3DES para criptografia simétrica, usando uma chave de 8 bytes codificada:  \x53\x76********* [CENSURADO]. Após a rotina de criptografia, os dados são codificados usando Base64 com um mapeamento de caracteres base64 personalizado. Após a conclusão do processo de descriptografia, o conteúdo descriptografado é armazenado no segmento DATA. O conteúdo descriptografado é estruturado com várias partes da mensagem, como o tipo de mensagem (solicitação de autenticação, resposta de autenticação etc.), parâmetros baseados em ASCII (como par de nome de usuário/senha, endereço IP etc.) e o código de erro da solicitação.


Ao pesquisar o cmxddnsd binário, descobrimos que nenhuma validação de host real ocorre como parte do protocolo DDNS da Comexe. A única coisa necessária para se passar por um cliente/servidor nesse protocolo DDNS é conhecer o procedimento de criptografia e a chave codificada usada pelas diferentes partes. Isso significa que poderíamos nos passar pelo servidor do provedor para receber e enviar solicitações ao dispositivo cliente.

Constantes de criptografia/descriptografia usadas em nossos scripts.

Para que um cliente valide a identidade de um servidor durante a conexão, a maioria dos protocolos usa SSL ou um algoritmo de criptografia assimétrica para validar a verdadeira identidade de cada lado. No entanto, como o Comexe usa um algoritmo de criptografia simétrica, é possível que qualquer pessoa com conhecimento da chave de criptografia (que está embutida no dispositivo) se faça passar por cada lado.

Vulnerabilidade nº 2: execução remota de código devido a estouro de pilha(CVE-2024-5243)

Depois de obter a capacidade de personificar o provedor de DDNS, começamos a investigar o fluxo de análise e a funcionalidade de DDNS em cmxddnsd. Logo identificamos a função que manipula o processamento de pacotes DDNS dentro do binário: _chkPkt.

Parte da função _chkPkt, que lida com a descriptografia de dados.

Como parte do protocolo de comunicação, o servidor envia uma carga útil baseada em ASCII composta de vários segmentos, cada segmento relevante para um tipo de mensagem e parâmetro específicos. Por exemplo, o servidor DDNS pode enviar uma mensagem errorCode que indica o erro específico que ocorreu, ou um parâmetro updateSvr que diz ao cliente para atualizar sua versão do domínio do servidor do provedor, por exemplo, de Dns1.comexe.cn para mynewdomain.com.

Descobrimos que, durante as rotinas de análise de partes específicas da mensagem, o servidor copia os buffers de parâmetros recebidos sem verificação de limites nem validação de segurança. Por exemplo, envolvendo o errorCode o servidor usa o parâmetro strncpy para copiar o buffer em uma variável de pilha de 4 bytes. No entanto, a cópia usa o comprimento do parâmetro recebido e não o buffer de destino, que pode ser menor. Isso significa que, se o roteador receber um parâmetro errorCode dados de tamanho maior que 4 caracteres, ocorrerá uma sobrecarga do buffer.

O código que causa o bug de estouro que exploramos, dentro da função _chkPkt.

Como o invasor controla totalmente a carga útil, ele pode enviar conteúdo com tamanhos grandes dentro do errorCode sendo limitado apenas pelo tamanho máximo do pacote 0x800. Isso acionará um estouro de buffer baseado em pilha e, como resultado, poderá afetar o fluxo de execução de código do aplicativo.

O estado da pilha antes do nosso estouro no fluxo de análise do errorCode em _chkPkt. Podemos ver que um endereço de aplicativo válido é salvo antes do ponteiro de pilha atual e dentro do registro $ra.
O estado da pilha após nosso estouro no fluxo de análise de errorCode em _chkPkt. Podemos ver que conseguimos transbordar o registro do endereço de retorno com um valor que controlamos (0x77fa62f0), o que significa que ultrapassamos o fluxo de execução.

Vulnerabilidades semelhantes de estouro de buffer existiam em diferentes comandos dentro do protocolo DDNS. Por exemplo, dentro da manipulação do comando UpdateSvr1 e UpdateSvr2 um buffer controlado pelo usuário é copiado em um pequeno buffer na seção globals com comprimento constante de 0x80 bytes, transbordando a seção global do programa com novos parâmetros controlados pelo usuário. Comexe Domínios de servidores DNS.

Abusando do UpdateSvr1, um invasor pode enviar uma carga útil maior que 0x80 para transbordar a seção de memória global e sobrescrever outros structs.

Depois de verificar diferentes transbordamentos de buffer baseados em pilha, optamos por nos concentrar no transbordamento do errorCode parâmetro (cmxddnsd ! 0x2d8a) enquanto sobrescreve a pilha inteira no _checkPkt frame. Como não há canários de pilha protegendo-o, agora temos a capacidade de controlar o fluxo de execução e saltar para o nosso quadro controlado $pc (contador de programas).

Nosso plano para exploração bem-sucedida e execução remota de código era criar uma cadeia ROP (programação orientada a retorno) que levasse a um sistema (COMMAND). O problema que enfrentamos é a randomização do layout do espaço de endereço (ASLR); não podíamos adivinhar os endereços de base da pilha/heap/libs e precisávamos encontrar uma maneira de vazá-los para derrotar o ASLR, uma atenuação em muitos sistemas operacionais contra ataques de execução de código baseados em memória.

Vulnerabilidade nº 3: desvio do ASLR devido à leitura OOB(CVE-2024-5244)

Depois de conseguir controlar o fluxo de execução do programa, poderíamos fornecer endereços para os quais o programa pularia e continuar a execução a partir deles. No entanto, em um sistema operacional moderno, o ASLR atenua ataques como esse ao randomizar o layout de endereço do programa, carregando diferentes seções como bibliotecas, heap e pilha em locais aleatórios em cada execução. Para explorar com sucesso a vulnerabilidade acima e executar código arbitrário, tivemos que contornar o ASLR para ter endereços válidos para nossa cadeia ROP.

Para contornar a proteção ASLR, tivemos que vazar endereços válidos da memória do programa, apontando para as seções de memória aleatórias. Isso foi feito para que pudéssemos calcular o endereço base das bibliotecas a partir desses ponteiros vazados. Para atingir esse objetivo, procuramos uma maneira de exfiltrar a memória fora dos limites que contém ponteiros para endereços válidos. 

Começamos examinando as seções de código no programa que enviava dados para servidores remotos. Logo descobrimos que a seção cmxddnsd binary só se comunica em dois protocolos: DDNS (proprietário da Comexe) UDP/9994) e DNS (UDP/53). Para encontrar vazamentos de memória nesses protocolos, começamos a examinar as funções e os procedimentos que lidam com essas solicitações.

Ao inspecionar a função sndDnsQuerynotamos que ele era vulnerável a um estouro de buffer baseado em pilha. O estouro nessa função ocorre quando o programa lê um nome de DNS de uma seção global da memória e o copia para a pilha, um caractere por vez.

Embora normalmente o nome DNS seja limitado a um tamanho de 0x80já que conseguimos transbordar a variável de seção global usando UpdateSvr1 e UpdateSvr2 conseguimos fornecer um nome de DNS muito maior.

Durante sua execução, a função copiará um byte por vez da nossa variável global transbordada para a pilha, o que poderia levar a um estouro de buffer baseado em pilha. A única interrupção na cópia de cada byte ocorre quando a função encontra um caractere de barra (/) ou um byte nulo (\x00). Como controlamos o nome do DNS e seu tamanho, podemos estourar qualquer coisa na pilha no quadro sndDnsQuery.

Função _sndDnsQuery(), vulnerável a estouro baseado em pilha ao copiar os nomes do servidor DNS em uma variável de pilha

Exploramos esse estouro de buffer baseado em pilha para transbordar e reescrever uma variável de pilha específica, sendSize. Essa variável é então usada pelo programa para determinar quantos bytes o programa enviará na consulta ao DNS. Ao modificar os dois bytes inferiores dessa variável, conseguimos sobrescrever um número muito grande, muito maior do que o domínio real e a carga útil do DNS.

Portanto, sempre que o programa tenta enviar a consulta de DNS, uma vez que o sendSize for maior, ele continuará enviando dados da pilha; enviando tantos bytes quanto o número dentro de sendSize. Essa abordagem leva à leitura de memória fora dos limites e ao vazamento de ponteiros da pilha usando o DNS.

Layout da pilha da função _sndDnsQuery. Iniciamos nosso transbordamento na variável domain_name e transbordamos os dois bytes inferiores de send_size.

Outra visão do layout da pilha da função _sndDnsQuery, incluindo nosso estouro específico para controlar o tamanho do vazamento

Usando a leitura fora dos limites, conseguimos vazar muitos ponteiros que estavam na pilha. Esses ponteiros apontam para muitas regiões diferentes da memória, incluindo a própria pilha, o heap e até mesmo para diferentes bibliotecas, como libc. Usando esses ponteiros, conseguimos calcular os endereços-base atuais dessas regiões de memória, o que nos permitiu contornar o recurso ASLR.

A cadeia completa de exploração de WAN

Para explorar totalmente a cadeia de vulnerabilidades mostrada acima, um invasor precisa primeiro fazer o tráfego main-in-the-middle (MiTM) entre o roteador e o Comexe Servidores DDNS (usando a vulnerabilidade da Questão nº 1).

Em seguida, o invasor fornecerá um UpdateSvr1 para o servidor, maior do que o tamanho máximo dessa variável. Isso causará um estouro de buffer durante o sndDnsQuery transbordando o sendSize acionando nossa vulnerabilidade de leitura fora dos limites (Problema nº 3).

Por fim, usando os endereços de base que o invasor conseguiu vazar usando o Problema nº 3, o invasor enviará uma resposta DDNS maliciosa com um errorCode acionando um estouro de buffer baseado em pilha, conforme mostrado na Questão nº 2. Isso fará com que o programa execute a cadeia ROP criada pelo atacante, transferindo o fluxo de execução para o atacante e acionando um comando do sistema operacional sob o controle do atacante. Isso significa que o invasor agora tem controle total sobre o roteador atacado, o que lhe permite executar comandos arbitrários do sistema operacional com as permissões do usuário root.

Resumo da exploração de WAN

  1. Ficar atrás da WAN do roteador - MITM

  2. Iniciar atualizações de domínio DDNS usando UpdateSvr1, UpdateSvr2 com domínios transbordados

  3. Transbordar a pilha no sndDnsQuery sem interromper o aplicativo e vazar ponteiros da pilha

  4. Calcular endereços de base para a pilha e a libc

  5. Enviar solicitação DDNS com errorCode malicioso para sobrecarregar a pilha no quadro _checkPkt

  6. Transbordar a pilha e iniciar a cadeia ROP

  7. Chamar o sistema com nossa carga útil

Preparando-se para o ataque à LAN

Agora tínhamos acesso root remoto total ao roteador. Precisávamos estabelecer o domínio, então abrimos completamente as regras do firewall (limpando iptables) e configurou um shell reverso que tentará entrar em contato conosco caso a conexão seja fechada.


Em seguida, precisávamos descobrir quais dispositivos estão localizados atrás do roteador na LAN, então ambos farejamos e fizemos arp -an e descobrimos o dispositivo de IoT que estávamos procurando, uma câmera IP Synology BC500. Uma vez detectada, criamos um "proxy" usando o SOCAT (listen-connect) no roteador que exporá a porta da Web da câmera para nós e continuaremos na fase 2, girando para a LAN.

Fique por dentro

Receba o boletim informativo da Team82

Divulgações de vulnerabilidades relacionadas

Claroty
LinkedIn Twitter YouTube Facebook