
Este projeto gera zonefiles DNS com parâmetros NSEC3 personalizados para reproduzir e avaliar os ataques de CVE-2023-50868.
Este projeto gera zonefiles DNS com parâmetros NSEC3 personalizados para reproduzir e avaliar os ataques em CVE-2023-50868.
Python3 (testado no Python3.10)
Dependências Python instaladas:
lib: Utilitários Python, incluindo:
keys.py: Funções wrapper para carregar/armazenar chaves em arquivosnsec.py: Implementação de Hashes NSEC do DNSSECdnssec.py: Funções dnspython modificadas/patcheadas com suporte a NSEC3config.py: Utilitários de carregamento de configuraçãokeys: Arquivos PEM com chaves pré-geradas (geradas com )gen_keys.pyzones: Zonefiles (gerados com gen_zones.py)config.json: Exemplo de configuraçãoConfigure quais zonas NSEC3 devem ser criadas modificando o config.json (veja Config)
Gerar chaves:
$ ./gen_keys.py
Para cada zona, uma KSK e uma ZSK são geradas. As chaves são reutilizadas ao alterar a configuração, desde que os nomes das zonas permaneçam inalterados na configuração.
Gerar zonefiles:
$ ./gen_zones.py -c
A opção -c permite a exportação de arquivos de configuração (atualmente apenas para BIND9)
Use --help para mais opções.
A estrutura de configuração contém dois elementos:
default: Parâmetros padrão para as zonas (nem todos são suportados até agora)zones: Lista de todas as zonas a serem exportadasUma zona contém:
name (obrigatório): O nome usado ao referenciar a zona e como nome de arquivo durante a exportaçãoorigin (obrigatório): O nome de domínio canônico da origem da zonaparent: O nome da zona pai (não a origem), à qual os registros NS, A, DS e NSEC3PARAM desta zona são adicionadoskeysize (obrigatório): O tamanho da chave RSA (apenas RSA até agora)nsec3: Os parâmetros NSEC3:
iterations: padrão 0salt: padrão ''algorithm: Valor inteiro, atualmente, apenas SHA-1 (1) é suportadotight: Um booleano especial que controla se os registros NSEC3 imediatamente após a origem e antes e depois de *.origin devem ser adicionados. Por exemplo, se *.origin tiver um registro NSEC3 1d..ua.origin., então os registros para 1d..u0.origin. e 1d..ub.origin. também são adicionados ao zonefile. Isso garante que cada prova NXDOMAIN em um subdomínio da origem (ex.: a.origin.) exija três registros NSEC3, pois os registros NSEC3 que cobrem a origem e o curinga têm um intervalo muito pequeno para next_hashns: O(s) servidor(es) de nomes desta zona. Um único valor ou lista de:
ns: O nome de domínio de um servidor de nomes, padrão ns1.originip: O domínio IPv4 (IPv6 atualmente não suportado), padrão 172.0.0.1soa: O RDATA do SOArrsets: Uma lista de RRsets adicionais, dada como a lista de 5 tuplas [nome de domínio, ttl, classe, tipo, rdata] onde todos os valores (exceto, opcionalmente, ttl) são fornecidos como stringsPara reproduzir o ataque NSEC3, esta seção ilustra uma possível configuração personalizada consistindo em um servidor de nomes DNS e um resolver (resolvedor) vítima. Antes de continuar, certifique-se de que o ambiente do sistema tenha um firewall configurado de forma suficiente para não expor servidores públicos aos zonefiles de ataque.
Instale o servidor de nomes NSD (versão atual)
Navegue até o site da NLNetlabs (https://nsd.docs.nlnetlabs.nl/en/latest/installation.html) para instruções de instalação.
É recomendado implantar o servidor de nomes em uma VM ou container. Como ponto de partida, há um pequeno Dockerfile em docker/nsd.
Construa o container com docker build -t <tag> <path_to_dockerfile>, por exemplo:
cd docker/nsd && docker build -t nsd .
Execute o container com docker run -it --name <name> nsd bash para abrir um console no container.
Em seguida, o servidor de nomes precisa ser configurado para hospedar os zonefiles de ataque.
Isso exige uma configuração correta dos zonefiles a serem gerados (principalmente, o endereço IP informado nos registros NS precisa corresponder ao endereço IP do container).
Se nenhuma rede foi configurada, o endereço IP do container pode ser visualizado com:
docker container inspect <name> | grep IPAddress
Gere as zonas com a saída de configuração (./gen_zones.py -c, veja acima) e copie a pasta de saída das zonas do diretório do repositório para o container docker:
docker cp ./zones <name>:/etc/nsd
No console do container, o config do NSD /etc/nsd/nsd.conf no container precisa ser alterado com as seguintes linhas:
verify:
enable: no
remote-control:
control-enable: no
include: "/etc/nsd/zones/nsd.conf"
Por fim, execute o NSD a partir do shell do container com o comando
/usr/sbin/nsd -d -c /etc/nsd/nsd.conf
Ative a saída de logs com a opção -V 4.
Agora, se nenhum problema ocorreu, o servidor de nomes autoritativo deve estar em execução. Você pode verificar isso executando uma consulta a um dos domínios das zonas a partir do sistema hospedeiro usando dig:
dig @<ip-addr-of-nsd-container> <domain>
Instale um resolver. Nesta demonstração, mostramos uma abordagem possível para o Unbound 1.17.1.
Um dockerfile oficial pode ser encontrado aqui: https://github.com/NLnetLabs/pythonunbound
Incluímos uma versão modificada deste Dockerfile em docker/unbound com uma versão atualizada do Ubuntu e pré-configurada para o Unbound 1.17.1.
Clone o repositório, mude para o diretório dele e construa o container do Unbound:
docker build -t <tag> .
Execute o container com:
docker run --name <name> -it <tag> bash
Em seguida, o Unbound precisa ser configurado de forma que consiga localizar o servidor de nomes autoritativo NSD.
Isso é feito modificando o arquivo unbound.conf no diretório de trabalho do container.
Para isso, certifique-se de que a entrada server.module-config seja removida da configuração.
Para habilitar a validação DNSSEC, os registros DNSKEY da zona pai do atacante precisam ser configurados manualmente. Essa precisa ser a mesma chave usada para gerar as assinaturas, por exemplo:
server:
chroot: ""
do-ip6: no
trust-anchor: "attack.er. DNSKEY 257 3 7 AwEAAdqDN3rJYlmGP3jJs5lCZq5NYrCn pCVlV0ko17JnbfYfLCroEF4reO/Xy0MK C9AVvSRTk83MHDuzMYXogm7m/gcn3Mh0 MwB2InP8jkPw5not+TMH/Wrbs31xkT2n RIBJJ+1lPF+e2AvwWvgREcEVTRbdhIqQ iM1StWXoTVudry4V"
Além disso, uma stub-zone precisa ser configurada para permitir que o resolver Unbound encontre o servidor de nomes autoritativo NSD.
Isso é alcançado adicionando o seguinte ao arquivo unbound.conf:
Se você tiver qualquer problema com este guia, sinta-se à vontade para nos contatar para obter mais orientações.
stub-zone:
name: "attack.er."
stub-prime: yes
stub-addr: <ip-addr-of-nsd-container>
Inicie o unbound no container com:
unbound -vvv (use -dd para impedir a daemonização)
Agora você deve conseguir consultar o unbound com dig e observar o tempo de resposta:
dig @127.0.0.1 attack.er