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.
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!
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.
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.
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:
um arquivo criptografado Dados
segmento
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.
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.
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.
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
.
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.
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.
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.
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.
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 sndDnsQuery
notamos 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 0x80
já 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.
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.
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.
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
Ficar atrás da WAN do roteador - MITM
Iniciar atualizações de domínio DDNS usando UpdateSvr1, UpdateSvr2 com domínios transbordados
Transbordar a pilha no sndDnsQuery sem interromper o aplicativo e vazar ponteiros da pilha
Calcular endereços de base para a pilha e a libc
Enviar solicitação DDNS com errorCode malicioso para sobrecarregar a pilha no quadro _checkPkt
Transbordar a pilha e iniciar a cadeia ROP
Chamar o sistema com nossa carga útil
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.
Essa vulnerabilidade permite que invasores adjacentes à rede executem códigos arbitrários nas instalações afetadas dos roteadores TP-Link Omada ER605. A autenticação não é necessária para explorar essa vulnerabilidade. No entanto, os dispositivos são vulneráveis somente se estiverem configurados para usar o serviço Comexe DDNS.
A falha específica existe no tratamento dos códigos de erro DDNS. O problema resulta da falta de validação adequada do comprimento dos dados fornecidos pelo usuário antes de copiá-los para um buffer baseado em pilha de comprimento fixo. Um invasor pode aproveitar essa vulnerabilidade para executar códigos no contexto do root.
CVSS v3: 7,5
Essa vulnerabilidade permite que invasores adjacentes à rede executem códigos arbitrários nas instalações afetadas dos roteadores TP-Link Omada ER605. A autenticação não é necessária para explorar essa vulnerabilidade. No entanto, os dispositivos são vulneráveis somente se estiverem configurados para usar o serviço Comexe DDNS.
A falha específica existe no manuseio de nomes DNS. O problema resulta da falta de validação adequada do comprimento dos dados fornecidos pelo usuário antes de copiá-los para um buffer. Um invasor pode aproveitar essa vulnerabilidade para executar código no contexto da raiz.
CVSS v3: 7,5
Essa vulnerabilidade permite que invasores adjacentes à rede acessem ou falsifiquem mensagens DDNS nas instalações afetadas dos roteadores TP-Link Omada ER605. A autenticação não é necessária para explorar essa vulnerabilidade. No entanto, os dispositivos são vulneráveis somente se estiverem configurados para usar o serviço Comexe DDNS.
A falha específica existe no executável cmxddnsd. O problema resulta da confiança na obscuridade para proteger os dados da rede. Um invasor pode aproveitar isso em conjunto com outras vulnerabilidades para executar código arbitrário no contexto da raiz.
CVSS v3: 5.0