NetCatTest

Zero-Day & Exploits

Ripple20: quando a compressão DNS corrompe a memória do firmware

Um mergulho na CVE-2020-11901: ponteiros DNS, tamanho expandido, contador de 16 bits e overflow no heap de bibliotecas incorporadas ao firmware.

Por Daniel Felipe 10 min leitura

O tamanho de uma mensagem na rede não é necessariamente o tamanho do objeto que ela produzirá na memória. A compressão de nomes DNS é um exemplo concreto: poucos bytes podem apontar para trechos já presentes na mensagem. Quando a implementação calcula mal a forma expandida, uma resposta de rede pode atingir o alocador de memória do firmware.

Ripple20 é o nome dado pela JSOF a um conjunto divulgado em junho de 2020. A nota VU#257161 do CERT/CC documenta falhas na pilha Treck incorporada a sistemas embarcados, com impactos dependentes da integração. Aqui, o foco é a CVE-2020-11901, ligada a respostas DNS e corrupção de memória. É um estudo histórico para auditorias de firmware, sem afirmar um novo incidente em 2026.

Expansão DNS: comprimento lógico e posição consumida

Um nome comprimido exige dois cursores conceituais: onde o campo original termina e onde a expansão continua lendo. Quando há um ponteiro, a posição de leitura muda, mas o campo original consumiu apenas os bytes do ponteiro. Confundir essas posições faz o parser interpretar o próximo campo do registro no lugar errado.

A rotina abaixo é uma implementação didática conservadora sobre uma mensagem sintética. Ela exige ponteiros para posições anteriores, limita saltos e recusa ciclos. Não é o código da biblioteca Treck, nem um exploit Ripple20. A RFC 9267 descreve anti-padrões relevantes para essa família de parsers.

def expandir_nome(msg, inicio):
    cursor, fim, vistos, labels = inicio, None, set(), []
    for _ in range(128):
        if cursor in vistos or cursor >= len(msg):
            raise ValueError('ciclo ou limite')
        vistos.add(cursor)
        n = msg[cursor]
        if n & 0xc0 == 0xc0:
            if cursor + 1 >= len(msg):
                raise ValueError('ponteiro truncado')
            alvo = ((n & 0x3f) << 8) | msg[cursor + 1]
            if alvo >= cursor:
                raise ValueError('ponteiro nao anterior')
            fim = cursor + 2 if fim is None else fim
            cursor = alvo
            continue
        if n & 0xc0 or n > 63 or cursor + 1 + n > len(msg):
            raise ValueError('label invalido')
        cursor += 1
        if n == 0:
            return b'.'.join(labels), cursor if fim is None else fim
        labels.append(msg[cursor:cursor + n])
        if sum(len(x) + 1 for x in labels) + 1 > 255:
            raise ValueError('nome expandido excessivo')
        cursor += n
    raise ValueError('saltos excessivos')

assert expandir_nome(b'\x03lab\x00\xc0\x00', 5) == (b'lab', 7)

A saída separa o nome lógico e o fim do campo codificado. O conjunto vistos identifica posições já visitadas; o teto limita custo; os testes de comprimento precedem cada leitura. O limite de 255 considera a representação DNS com octetos de tamanho e terminador, não somente o texto com pontos.

Um parser de produção ainda precisa validar o início de cada label referenciado, os limites de cada RDATA e as restrições do tipo de registro. Esta função cobre o mecanismo essencial para estudar um teste local; aceitar o exemplo não certifica um firmware.

Crie casos negativos de ponteiro truncado, alvo inválido, ciclo e nome expandido longo, além do caso sem compressão. A evidência desejada é uma rejeição limitada e determinística, sem leitura fora do buffer nem consumo desproporcional. Isso explica o defeito de projeto com bytes observáveis, preservando a distinção entre reconstrução e código real do fabricante.

O problema pode estar no cliente DNS do equipamento

Em uma avaliação tradicional, a equipe procura serviços escutando portas. Em dispositivos embarcados, uma biblioteca cliente também pode interpretar conteúdo não confiável. Um equipamento que consulta um nome precisa consumir a resposta recebida, mesmo que não ofereça um servidor DNS acessível ao auditor.

O mapa de exposição deve incluir quem define os resolvers, quais operações geram consultas e quais intermediários podem devolver respostas. Acesso a uma resposta compatível com a consulta não é consequência automática de estar em qualquer ponto da Internet. Rede, configuração e validações da implementação determinam quais entradas chegam ao parser.

Operação do dispositivo que precisa de um nome
        ↓
Consulta ao resolver configurado
        ↓
Resposta DNS recebida e validada
        ↓
Expansão dos nomes comprimidos
        ↓
Cálculo, alocação e cópia em memória

Compressão DNS: um ponteiro muda a forma de contar

O RFC 1035 define nomes como sequências de labels, com até 63 octetos por label e limite de 255 octetos para o nome no formato definido. Um ponteiro de compressão ocupa dois octetos: os dois bits superiores sinalizam o ponteiro, e os demais indicam um deslocamento relativo ao início da mensagem DNS.

Assim, c0 0c indica um ponteiro para o deslocamento 12. O receptor precisa distinguir bytes consumidos no local original dos bytes visitados para expandir o nome. Um contador de posição e um contador de saída têm finalidades diferentes. Misturá-los torna difícil provar que a alocação corresponde ao que será copiado.

O exemplo local abaixo calcula a interpretação de um ponteiro legítimo e o tamanho de um nome reservado para laboratório. Ele não constrói uma resposta malformada nem envia tráfego. Serve para visualizar a diferença entre dois bytes de referência e uma sequência maior de labels.

ponteiro = bytes.fromhex("c00c")
valor = int.from_bytes(ponteiro, "big")
deslocamento = valor & 0x3fff
labels = [b"sensor", b"lab", b"test"]
nome = b"".join(bytes([len(label)]) + label for label in labels) + b"\x00"

assert valor & 0xc000 == 0xc000
assert deslocamento == 12
assert len(nome) == 17
print(len(ponteiro), deslocamento, len(nome))

A saída é 2 12 17. Isso não viola o protocolo: a compressão existe para economizar espaço. A obrigação do parser é manter limites coerentes durante a expansão, inclusive quando a mensagem recebida contém referências inválidas.

De um contador de 16 bits a uma alocação insuficiente

A análise técnica produzida por McAfee ATR com a JSOF detalha uma variante da CVE-2020-11901. A função tfDnsExpLabelLength calculava o tamanho expandido usando um inteiro sem sinal de 16 bits. Uma resposta preparada podia fazer o cálculo ultrapassar sua faixa, mesmo sem conter 65.536 bytes no pacote.

Em alguns caminhos, tfGetRawBuffer usava o valor calculado para alocar o buffer. O resultado podia ser uma alocação menor que o conteúdo posteriormente copiado, com overflow no heap e potencial execução de código. Essa relação explica o risco; ela não implica exploração confiável em qualquer produto que mencione Treck.

O estudo original discute DNS sobre UDP e apresenta ressalvas sobre outras condições de transporte. Não transforme uma possibilidade considerada para detecção em demonstração universal sobre TCP ou EDNS. No relatório, mantenha o transporte efetivamente reproduzido e a versão testada.

Quatro limites que um parser precisa manter separados

O RFC 9267 analisa padrões inseguros de implementação DNS, incluindo checagem de ponteiros e expansão. Ele é útil para revisar código além de uma CVE específica. Uma checagem parcial dos bits superiores pode classificar incorretamente um byte; a validação deve reconhecer exatamente o formato esperado.

LimiteO que protegePergunta de revisão
Mensagem recebidaLeituras do pacoteO offset e cada leitura permanecem no buffer?
Nome expandidoTamanho lógico da saídaOs limites do nome são aplicados durante a expansão?
Percurso dos ponteirosTerminação e custoHá tratamento para ciclos e excesso de trabalho?
Capacidade alocadaEscritas em memóriaO tamanho validado é o mesmo utilizado na cópia?

Para uma revisão profissional, acrescente conversões de tipo e propagação de erros a essa matriz. Se uma função retorna falha, o consumidor deve interromper o caminho correspondente. Se a contagem e a cópia usam percursos diferentes, compare suas regras de rejeição. Validar uma representação e copiar outra deixa uma fronteira sem demonstração de segurança.

Ilustração de controlador industrial aberto, placa embarcada e cabo Ethernet

Ilustração gerada de hardware embarcado genérico. O caminho de rede alcança componentes do firmware; confirmar Treck e a versão integrada exige documentação, análise de dependências ou evidência do fabricante.

O inventário do firmware é uma investigação de dependências

Não atribua a CVE a uma linha inteira de dispositivos apenas porque um produto da marca incorporou a biblioteca. Reúna modelo, revisão de hardware, firmware em execução, configuração DNS e aviso do fabricante. Peça a versão da pilha e a identificação da correção incorporada ao build. Quando disponível, uma SBOM ajuda a localizar a dependência, mas não substitui a correspondência com a imagem instalada.

A nota do CERT/CC recomenda atualização da pilha e contato com o fornecedor do dispositivo. A referência 6.0.1.67 aparece no contexto histórico de correção de Ripple20; não é uma recomendação de versão mais recente para todo firmware em 2026. Bibliotecas modificadas, builds e configurações tornam a confirmação específica do produto necessária.

Em uma análise de imagem autorizada, preserve o original, calcule seu hash e trabalhe em uma cópia. Strings de bibliotecas são pistas para investigação, não uma prova de versão vulnerável. Remoção de símbolos, compilação estática e alterações do integrador podem esconder ou modificar essas informações.

Laboratório diferencial: a saída precisa respeitar os invariantes

Uma estratégia de teste combina um harness local do parser, quando disponível, com duas imagens identificadas por hash. Use sanitizadores na compilação de teste e limites de tempo e memória. O oráculo deve verificar mais que “não caiu”: aceite de nomes válidos, rejeição controlada de referências inválidas, terminação e nenhuma leitura ou escrita fora dos buffers.

Organize o corpus em famílias: nomes sem compressão, ponteiros válidos, offsets nas fronteiras, referências fora da mensagem e caminhos que excedem limites. Registre qual propriedade cada caso exercita. Variações devem mudar um aspecto por vez, com entradas preservadas para reprodução. Não é necessário usar o parser de um dispositivo operacional como primeiro alvo de experimentação.

Este é um desenho de laboratório, sem alegação de exploração realizada nesta matéria. Se o firmware não oferecer instrumentação suficiente, classifique a conclusão como limitada. Um watchdog que reinicia o equipamento pode ocultar a causa; a ausência de log de memória não comprova que o caminho esteja seguro.

Detecção precisa expandir significado, não apenas medir pacotes

Uma regra que observa somente o comprimento do datagrama não explica o tamanho que um parser produzirá após a expansão. Para detecção, relacione requisição, resposta, transporte e anomalias de estrutura, mantendo limites de processamento no próprio sensor. Um IDS que resolve referências sem controlar o percurso pode ganhar seu próprio problema de disponibilidade.

O alerta deve preservar identificadores da sessão e o mínimo de conteúdo necessário para revisão. Muitos ponteiros ou uma resposta incomum são sinais, não confirmação de CVE-2020-11901. Calibre contra tráfego legítimo e documente falsos positivos antes de bloquear um fluxo de produção.

Mitigação e encerramento com evidência

Priorize firmware corrigido, resolvers controlados e segmentação coerente com as dependências do equipamento. O bloqueio de consultas diretas para destinos desnecessários reduz caminhos de entrada, mas não substitui a correção: respostas permitidas ainda chegam ao cliente DNS. Não assuma que DNSSEC, por si só, corrige um parser de memória.

Ao encerrar a avaliação, entregue o vínculo entre dispositivo, imagem, biblioteca, correção e reteste. A contribuição técnica de Ripple20 é mostrar que a resposta de uma dependência de rede também é entrada de segurança. Comprimento comprimido, comprimento expandido e capacidade de memória precisam permanecer ligados por validações explícitas.

Escrito por

Daniel Felipe é criador do NetCatTest e produz conteúdos sobre cibersegurança, privacidade digital, OSINT, laboratórios autorizados e ferramentas para estudo técnico responsável.

Compartilhar

Enviar este artigo