Żądny wiedzy? Wbijaj na Mega Sekurak Hacking Party w maju! -30% z kodem: majearly

Leaky Vessels – nowa seria podatności w konteneryzacji

08 lutego 2024, 12:49 | W biegu | 0 komentarzy

Słowo kontener w IT jednoznacznie kojarzy się z dockerem chociaż nie jest to jedyna technologia pozwalająca na opakowanie oprogramowania w paczkę, która zawiera niezbędne do uruchomienia środowisko (czyli zależności, biblioteki). Kontenery mogą korzystać np. z namespaces i cgroups, aby odizolować uruchamiane programy od siebie nawzajem. Współdzielenie kernela systemu bazowego powoduje, że jest to rozwiązanie lekkie i szybkie, konfigurowane na dostępnych obrazach systemowych przy pomocy plików tekstowych, co ułatwia ich wersjonowanie. Kontenery przyjęły się szczególnie w środowiskach chmurowych, gdzie zarządzanie i instrumentacja klastrów kontenerów odbywa się przy pomocy np. Kubernetesa. 

Rysunek 1. Jak działa docker (źródło: https://www.docker.com/resources/what-container/)

Opublikowane zostały w dniu 31.01.2024 na blogu Snyka cztery podatności:

  • CVE-2024-21626
  • CVE-2024-23651
  • CVE-2024-23653
  • CVE-2024-23652

Dotyczą kluczowych elementów do budowy i zarządzania infrastrukturą skonteneryzowanych aplikacji, a nie samych obrazów i skutkują możliwością wyjścia (wyskoczenia) ze środowiska kontenera do systemu operacyjnego hosta. 

CVE-2024-21626

Podatność CVE-2024-21626 dotyczy bezpośrednio runc, czyli narzędzia CLI służącego do uruchamiania kontenerów (tzw. container runtime). Ucieczka do hosta możliwa jest przez wykorzystanie złośliwego pliku Dockerfile albo spreparowanego obrazu systemu (upstream image), który zostanie wybrany za pomocą słowa kluczowego FROM

Powodem wystąpienia tego problemu jest kolejność operacji przy zastosowaniu dyrektywy WORKDIR, która definiuje początkowy katalog roboczy wszystkich procesów utworzonych w Dockerfile’u, takich jak te powstałe na skutek użycia innych dyrektyw – na etapie budowania kontenera (słowo kluczowe RUN) oraz na etapie działania kontenera (dyrektywy CMD oraz ENTRYPOINT). Okazuje się, że zdefiniowany katalog jest odwiedzany przy użyciu syscalla chdir jeszcze zanim specyficzne, uprzywilejowane deskryptory plików hosta zostaną zamknięte. To powoduje, że możliwe jest wykorzystanie tych uprzywilejowanych deskryptorów przez odwołanie się do katalogu /proc/self/fd/ jako argumentu wywołania chdir. Dzięki temu deskryptory te pozostają dostępne nawet po wykonaniu operacji zamknięcia, jeszcze przed przekazaniem sterowania do komend zawartych w Dockerfile. 

Atak ma kilka wersji, możliwe jest wykorzystanie wywołań runc init czy też runc exec

Jak to działa w praktyce? Złośliwie skonfigurowany kontener spowoduje, że startujący wewnątrz proces będzie miał dostęp do systemu plików hosta. Domyślnie uprawnienia procesu będą identyczne z tymi, jakich używa silnik np. Docker Engine albo K8s (Kubernetes) – gdzie zwykle operują one jako root, stąd też możliwe jest wykorzystanie dostępu do dysku w celu osiągnięcia RCE w kontekście roota na hoście.

Problem został rozwiązany przez deweloperów runc poprzez sprawdzenie, czy ścieżka zdefiniowana przez WORKDIR znajduje się wewnątrz filesystemu kontenera. Dodatkowo zaimplementowano mechanizmy, mające na celu poprawne obsłużenie zamknięcia deskryptorów plików hosta po ich użyciu. 

W notce informującej o podatności, autorzy wskazują, że wydanie oznaczone numerem 1.1.12 zawiera wymagane łatki i zarówno samo runc, jak i rozwiązania korzystające z tego narzędzia powinny zostać zaktualizowane, tak aby używać poprawionej wersji. 

Snyk udostępnił też, zbudowane na filtrach eBPF, narzędzie o nazwie leaky-vessels-runtime-detector, pozwalające zidentyfikować uruchomione kontenery, które próbują wykorzystać tę podatność. Możliwe jest też wykorzystanie statycznego analizatora, który sprawdzi bazowe obrazy użyte z instrukcją FROM pod kątem wykorzystania słów kluczowych WORKDIR i ONBUILD, które będą nosiły znamiona złośliwych. Ta druga metoda została określona jako mniej precyzyjna i powodująca dużo fałszywych alarmów. 

Przed opublikowaniem znaleziska, badacze przeszukali popularne rejestry obrazów i nie znaleźli dowodów na to, że te podatności były wykorzystywane. Sami jednak podkreślają, że ich research nie był wyczerpujący i sytuacja ta może się zmienić, zwłaszcza po upublicznieniu znaleziska. 

Wskazano również potencjalne problemy z innymi środowiskami wykonania jak crun czy youki, gdzie zauważono podobne błędy chociaż jak na razie nie udało się ich wyeksploitować. 

CVE-2024-23651

Podatność oznaczona numerem katalogowym CVE-2024-23651, wykorzystuje z kolei mechanizm podmontowywania wolumenów typu cache podczas budowania kontenera. Funkcjonalność definiowana przez dyrektywę RUN --mount=type=cache pozwala na montowanie katalogu ze stałą zawartością podczas procesu budowania obrazu, ma to na celu poprawienie wydajności poprzez zachowywanie cache pomiędzy kolejnymi procesami budowania. 

Luka to błąd klasy race-condition. Wyścig występuje między walidacją a użyciem (tzw. TOCTOU – time-of-check/time-of-use) ścieżki wewnątrz podmontowanego cache. Możliwa jest podmiana tej ścieżki pomiędzy sprawdzeniem a wywołaniem systemowym mount, co powoduje że możliwe jest podmontowanie dowolnego katalogu wewnątrz filesystemu kontenera. Analogicznie do poprzedniej podatności, w momencie wykonania ataku, podmontowywany jest filesystem hosta. Uprawnienia będą identyczne jak samego procesu silnika Dockera, czyli użytkownika root. To oczywiście pozwala na eskalację dostępu do dysku do wykonania poleceń z uprawnieniami roota. 

CVE-2024-23653

Nieco inne podejście wykorzystano przy eksploitacji CVE-2024-23653. Problem wynika z brakującego sprawdzenia uprawnień przez endpoint GRPC (framework do zdalnych wywołań procedur) wykorzystywany przez BuildKit (backend, który m.in. przyspiesza budowanie kontenerów). Jedna z funkcji Dockera pozwala na definicję własnego parsera formatów przy pomocy dyrektywy # syntax= umieszczonej na samej górze Dockerfile. Można tam wskazać inny obraz dockerowy, który będzie wykorzystany do przetransformowania wejścia do pośredniej reprezentacji. Zdefiniowany parser ma możliwość wywołania wielu metod na serwerze GRPC. Jednym z dostępnych endpointów jest Container.Start, który pozwala na uruchamianie kontenerów. Przy wywołaniu nie jest sprawdzany parametr StartRequest.SecurityMode, co pozwala na uruchomienie przez parser kolejnego kontenera z podniesionymi uprawnieniami, a to w efekcie prowadzi do ucieczki z ograniczonego środowiska i oczywiście wykonanie poleceń jako root na bazowym systemie.

CVE-2024-23652

Ostatnią luką z opublikowanego zestawu jest CVE-2024-23652, która również dotyka Buildkita, a konkretnie etapu usuwania tymczasowych katalogów po ich użyciu. W przypadku podania w dyrektywie RUN --mount nieistniejącego katalogu, zostanie on stworzony na potrzeby operacji budowania, a następnie usunięty, gdy przestanie być potrzebny. Okazuje się, że jeśli katalog nadrzędny zostanie podmieniony na dowiązanie symboliczne w czasie gdy dany kontener będzie działał, to operacja czyszczenia przed jego zamknięciem spowoduje wykorzystanie dowiązania symbolicznego. Pozwala to na usunięcie wskazanego pliku z systemu hosta. Ponieważ Buildkit, tak samo jak engine działa z uprawnieniami roota, to możliwe jest usunięcie dowolnego pliku. Poprawiona wersja 0.12.5 jest już jednak dostępna. 

Autorzy badania zalecają aktualizację komponentów środowiska uruchomieniowego kontenerów, ponieważ zawierają one wszystkie potrzebne na ten moment łatki. Należy podkreślić, że aby doszło do skutecznej eksploitacji, to uprzywilejowany użytkownik musi zostać skłoniony do wykonania określonej operacji (np. skorzystania ze złośliwego pliku Dockerfile), czyli wymagany jest element socjotechniki/ataku na łańcuch dostaw, aby taki Dockerfile/obraz został uruchomiony. 

~fc

Spodobał Ci się wpis? Podziel się nim ze znajomymi:



Komentarze

Odpowiedz