GCP - Storage Privesc
Storage
Podstawowe informacje:
storage.objects.get
storage.objects.get
To uprawnienie pozwala na pobieranie plików przechowywanych w Cloud Storage. Może to potencjalnie umożliwić eskalację uprawnień, ponieważ w niektórych przypadkach przechowywane są tam wrażliwe informacje. Ponadto, niektóre usługi GCP przechowują swoje informacje w bucketach:
GCP Composer: Gdy tworzysz środowisko Composer, kod wszystkich DAG-ów będzie zapisany w buckecie. Te zadania mogą zawierać interesujące informacje w swoim kodzie.
GCR (Container Registry): Obraz kontenerów jest przechowywany w bucketach, co oznacza, że jeśli możesz czytać buckety, będziesz mógł pobrać obrazy i szukać wycieków i/lub kodu źródłowego.
storage.objects.setIamPolicy
storage.objects.setIamPolicy
Możesz przyznać sobie uprawnienia do wykorzystania dowolnego z wcześniejszych scenariuszy tej sekcji.
storage.buckets.setIamPolicy
storage.buckets.setIamPolicy
Aby zobaczyć przykład, jak zmodyfikować uprawnienia za pomocą tego uprawnienia, sprawdź tę stronę:
storage.hmacKeys.create
storage.hmacKeys.create
Funkcja "interoperacyjności" Cloud Storage, zaprojektowana do interakcji między chmurami jak z AWS S3, obejmuje tworzenie kluczy HMAC dla kont serwisowych i użytkowników. Atakujący może to wykorzystać, generując klucz HMAC dla konta serwisowego z podwyższonymi uprawnieniami, co pozwala na eskalację uprawnień w Cloud Storage. Podczas gdy klucze HMAC powiązane z użytkownikami są dostępne tylko za pośrednictwem konsoli internetowej, zarówno klucze dostępu, jak i tajne pozostają wiecznie dostępne, co umożliwia potencjalny dostęp do przechowywania kopii zapasowych. Z drugiej strony, klucze HMAC powiązane z kontem serwisowym są dostępne przez API, ale ich klucze dostępu i tajne nie są dostępne po utworzeniu, co dodaje warstwę złożoności dla ciągłego dostępu.
Inny skrypt exploitacyjny dla tej metody można znaleźć tutaj.
storage.objects.create
, storage.objects.delete
= Uprawnienia do zapisu w Storage
storage.objects.create
, storage.objects.delete
= Uprawnienia do zapisu w StorageAby utworzyć nowy obiekt w obrębie bucketu, potrzebujesz storage.objects.create
, a zgodnie z dokumentacją, potrzebujesz również storage.objects.delete
, aby zmodyfikować istniejący obiekt.
Bardzo częstym wykorzystaniem bucketów, w których można pisać w chmurze, jest sytuacja, gdy bucket przechowuje pliki serwera WWW, możesz być w stanie przechować nowy kod, który będzie używany przez aplikację internetową.
Composer
Composer to Apache Airflow zarządzany w GCP. Ma kilka interesujących funkcji:
Działa w obrębie klastra GKE, więc SA, którego używa klaster, jest dostępny przez kod działający w Composer
Wszystkie komponenty środowisk composera (kod DAGów, wtyczki i dane) są przechowywane w obrębie bucketu GCP. Jeśli atakujący ma uprawnienia do odczytu i zapisu, może monitorować bucket i za każdym razem, gdy DAG jest tworzony lub aktualizowany, przesłać wersję z backdoorem, aby środowisko composera pobrało z storage wersję z backdoorem.
Możesz znaleźć PoC tego ataku w repozytorium: https://github.com/carlospolop/Monitor-Backdoor-Composer-DAGs
Cloud Functions
Kod Cloud Functions jest przechowywany w Storage, a za każdym razem, gdy tworzona jest nowa wersja, kod jest przesyłany do bucketu, a następnie nowy kontener jest budowany z tego kodu. Dlatego nadpisanie kodu przed zbudowaniem nowej wersji umożliwia wykonanie dowolnego kodu przez funkcję chmurową.
Możesz znaleźć PoC tego ataku w repozytorium: https://github.com/carlospolop/Monitor-Backdoor-Cloud-Functions
App Engine
Wersje AppEngine generują pewne dane w obrębie bucketu w formacie nazwy: staging.<project-id>.appspot.com
. W tym bucketcie można znaleźć folder o nazwie ae
, który będzie zawierał folder dla każdej wersji aplikacji AppEngine, a w tych folderach będzie można znaleźć plik manifest.json
. Plik ten zawiera json z wszystkimi plikami, które muszą być użyte do stworzenia konkretnej wersji. Co więcej, można znaleźć prawdziwe nazwy plików, URL do nich w obrębie bucketu GCP (pliki w bucketcie zmieniły swoją nazwę na ich sha1 hash) oraz sha1 hash każdego pliku.
Należy zauważyć, że nie jest możliwe wcześniejsze przejęcie tego bucketu, ponieważ użytkownicy GCP nie są uprawnieni do generowania bucketów przy użyciu nazwy domeny appspot.com.
Jednakże, mając dostęp do odczytu i zapisu w tym bucketcie, można eskalować uprawnienia do SA przypisanego do wersji App Engine, monitorując bucket i za każdym razem, gdy dokonana zostanie zmiana (nowa wersja), modyfikując nową wersję tak szybko, jak to możliwe. W ten sposób kontener, który zostanie stworzony z tego kodu, wykona kod z backdoorem.
Wspomniany atak można przeprowadzić na wiele różnych sposobów, wszystkie zaczynają się od monitorowania bucketu staging.<project-id>.appspot.com
:
Prześlij kompletny nowy kod wersji AppEngine do innego dostępnego bucketu i przygotuj plik
manifest.json
z nową nazwą bucketu i sha1 hashami. Następnie, gdy nowa wersja zostanie utworzona w obrębie bucketu, wystarczy zmodyfikować plikmanifest.json
i przesłać złośliwy.Prześlij zmodyfikowaną wersję
requirements.txt
, która będzie używać złośliwego kodu zależności i zaktualizuj plikmanifest.json
z nową nazwą pliku, URL i jego hashem.Prześlij zmodyfikowany plik
main.py
lubapp.yaml
, który wykona złośliwy kod i zaktualizuj plikmanifest.json
z nową nazwą pliku, URL i jego hashem.
Możesz znaleźć PoC tego ataku w repozytorium: https://github.com/carlospolop/Monitor-Backdoor-AppEngine
GCR
Google Container Registry przechowuje obrazy w obrębie bucketów, jeśli możesz zapisać te buckety, możesz być w stanie przesunąć się lateralnie do miejsca, w którym te buckety są uruchamiane.
Bucket używany przez GCR będzie miał URL podobny do
gs://<eu/usa/asia/nothing>.artifacts.<project>.appspot.com
(Najwyższe subdomeny są określone tutaj).
Ta usługa jest przestarzała, więc ten atak nie jest już użyteczny. Co więcej, Artifact Registry, usługa, która zastępuje tę, nie przechowuje obrazów w bucketach.
Referencje
Last updated