Concourse Enumeration & Attacks
Concourse Enumeration & Attacks
Role użytkowników i uprawnienia
Concourse ma pięć ról:
Concourse Admin: Ta rola jest przyznawana tylko właścicielom głównego zespołu (domyślny początkowy zespół concourse). Administratorzy mogą konfigurować inne zespoły (np.:
fly set-team
,fly destroy-team
...). Uprawnienia tej roli nie mogą być zmieniane przez RBAC.owner: Właściciele zespołów mogą modyfikować wszystko w zespole.
member: Członkowie zespołu mogą czytać i pisać w zasobach zespołu, ale nie mogą modyfikować ustawień zespołu.
pipeline-operator: Operatorzy pipeline mogą wykonywać operacje pipeline takie jak uruchamianie buildów i przypinanie zasobów, ale nie mogą aktualizować konfiguracji pipeline.
viewer: Widzowie zespołu mają dostęp tylko do odczytu do zespołu i jego pipeline.
Ponadto, uprawnienia ról owner, member, pipeline-operator i viewer mogą być modyfikowane poprzez konfigurację RBAC (konfigurując bardziej szczegółowo jego działania). Przeczytaj więcej na ten temat: https://concourse-ci.org/user-roles.html
Należy zauważyć, że Concourse grupuje pipeline w zespołach. Dlatego użytkownicy należący do zespołu będą mogli zarządzać tymi pipeline, a kilka zespołów może istnieć. Użytkownik może należeć do kilku zespołów i mieć różne uprawnienia w każdym z nich.
Vars & Credential Manager
W konfiguracjach YAML można konfigurować wartości za pomocą składni ((_source-name_:_secret-path_._secret-field_))
.
Z dokumentacji: source-name jest opcjonalny, a jeśli go nie podano, zostanie użyty menedżer poświadczeń na poziomie klastra, lub wartość może być podana statycznie.
Opcjonalny _secret-field_ określa pole w pobranym sekrecie do odczytu. Jeśli go nie podano, menedżer poświadczeń może wybrać odczytanie 'domyślnego pola' z pobranego poświadczenia, jeśli pole istnieje.
Ponadto, secret-path i secret-field mogą być otoczone podwójnymi cudzysłowami "..."
jeśli zawierają znaki specjalne takie jak .
i :
. Na przykład, ((source:"my.secret"."field:1"))
ustawi secret-path na my.secret
i secret-field na field:1
.
Static Vars
Statyczne zmienne mogą być określone w krokach zadań:
Albo używając następujących argumentów fly
:
-v
lub--var
NAME=VALUE
ustawia ciągVALUE
jako wartość dla zmiennejNAME
.-y
lub--yaml-var
NAME=VALUE
parsujeVALUE
jako YAML i ustawia to jako wartość dla zmiennejNAME
.-i
lub--instance-var
NAME=VALUE
parsujeVALUE
jako YAML i ustawia to jako wartość dla zmiennej instancjiNAME
. Zobacz Grouping Pipelines, aby dowiedzieć się więcej o zmiennych instancji.-l
lub--load-vars-from
FILE
ładujeFILE
, dokument YAML zawierający mapowanie nazw zmiennych na wartości, i ustawia je wszystkie.
Zarządzanie poświadczeniami
Istnieją różne sposoby, w jakie Credential Manager może być określony w pipeline, przeczytaj jak na https://concourse-ci.org/creds.html. Ponadto, Concourse obsługuje różnych menedżerów poświadczeń:
Zauważ, że jeśli masz jakiś rodzaj dostępu do zapisu do Concourse, możesz tworzyć zadania, aby wykraść te sekrety, ponieważ Concourse musi mieć do nich dostęp.
Enumeracja Concourse
Aby przeprowadzić enumerację środowiska Concourse, najpierw musisz zdobyć ważne poświadczenia lub znaleźć uwierzytelniony token, prawdopodobnie w pliku konfiguracyjnym .flyrc
.
Logowanie i enumeracja bieżącego użytkownika
Aby się zalogować, musisz znać endpoint, nazwę zespołu (domyślnie
main
) i zespół, do którego należy użytkownik:fly --target example login --team-name my-team --concourse-url https://ci.example.com [--insecure] [--client-cert=./path --client-key=./path]
Uzyskaj skonfigurowane cele:
fly targets
Sprawdź, czy skonfigurowane połączenie celu jest nadal ważne:
fly -t <target> status
Uzyskaj rolę użytkownika w odniesieniu do wskazanego celu:
fly -t <target> userinfo
Zauważ, że token API jest zapisany domyślnie w $HOME/.flyrc
, przeszukując maszyny, możesz tam znaleźć poświadczenia.
Zespoły i użytkownicy
Uzyskaj listę zespołów
fly -t <target> teams
Uzyskaj role w zespole
fly -t <target> get-team -n <team-name>
Uzyskaj listę użytkowników
fly -t <target> active-users
Pipelines
Lista pipelines:
fly -t <target> pipelines -a
Uzyskaj yaml pipeline (wrażliwe informacje mogą być zawarte w definicji):
fly -t <target> get-pipeline -p <pipeline-name>
Uzyskaj wszystkie zadeklarowane zmienne konfiguracyjne pipeline
for pipename in $(fly -t <target> pipelines | grep -Ev "^id" | awk '{print $2}'); do echo $pipename; fly -t <target> get-pipeline -p $pipename -j | grep -Eo '"vars":[^}]+'; done
Uzyskaj wszystkie nazwy sekretnych zmiennych używanych w pipelines (jeśli możesz utworzyć/zmodyfikować zadanie lub przejąć kontener, możesz je wykraść):
Containers & Workers
Lista workers:
fly -t <target> workers
Lista containers:
fly -t <target> containers
Lista builds (aby zobaczyć, co jest uruchomione):
fly -t <target> builds
Concourse Attacks
Brute-Force poświadczeń
admin:admin
test:test
Enumeracja secrets i parametrów
W poprzedniej sekcji widzieliśmy, jak można uzyskać wszystkie nazwy secrets i zmienne używane przez pipeline. Zmienne mogą zawierać wrażliwe informacje, a nazwy secrets będą przydatne później, aby spróbować je ukraść.
Sesja wewnątrz działającego lub niedawno uruchomionego container
Jeśli masz wystarczające uprawnienia (rola member lub wyższa), będziesz mógł wylistować pipelines i role oraz po prostu uzyskać sesję wewnątrz <pipeline>/<job>
container używając:
Z tymi uprawnieniami możesz być w stanie:
Ukraść sekrety wewnątrz kontenera
Spróbować uciec do węzła
Przeprowadzić enumerację/nadużycie endpointu metadanych chmury (z poziomu poda i węzła, jeśli to możliwe)
Tworzenie/Modyfikacja Pipeline
Jeśli masz wystarczające uprawnienia (rola członka lub wyższa), będziesz w stanie tworzyć/modyfikować nowe pipeline. Sprawdź ten przykład:
Z modyfikacją/tworzeniem nowego pipeline będziesz w stanie:
Ukraść sekrety (poprzez ich wyświetlenie lub wejście do kontenera i uruchomienie
env
)Uciec na node (dając sobie wystarczające uprawnienia -
privileged: true
)Przeprowadzić enumerację/nadużycie cloud metadata endpoint (z poziomu poda i z poziomu node)
Usunąć utworzony pipeline
Wykonanie niestandardowego zadania
Jest to podobne do poprzedniej metody, ale zamiast modyfikować/tworzyć cały nowy pipeline, możesz po prostu wykonać niestandardowe zadanie (co prawdopodobnie będzie znacznie bardziej ukryte):
Ucieczka do węzła z uprzywilejowanego zadania
W poprzednich sekcjach widzieliśmy, jak wykonać uprzywilejowane zadanie z concourse. To nie da kontenerowi dokładnie takiego samego dostępu jak flaga uprzywilejowania w kontenerze docker. Na przykład, nie zobaczysz urządzenia systemu plików węzła w /dev, więc ucieczka może być bardziej "złożona".
W poniższym PoC użyjemy release_agent do ucieczki z kilkoma małymi modyfikacjami:
Jak mogłeś zauważyć, jest to tylko regular release_agent escape z modyfikacją ścieżki cmd w nodzie
Ucieczka do noda z kontenera Worker
Regular release_agent escape z drobną modyfikacją jest wystarczający do tego:
Ucieczka do węzła z kontenera Web
Nawet jeśli kontener web ma wyłączone niektóre zabezpieczenia, nie działa jako zwykły uprzywilejowany kontener (na przykład, nie można montować i możliwości są bardzo ograniczone, więc wszystkie łatwe sposoby ucieczki z kontenera są bezużyteczne).
Jednak przechowuje lokalne poświadczenia w postaci jawnej:
Możesz użyć tych poświadczeń, aby zalogować się do serwera webowego i utworzyć uprzywilejowany kontener i uciec do węzła.
W środowisku możesz również znaleźć informacje do dostępu do instancji postgresql używanej przez concourse (adres, username, password i baza danych oraz inne informacje):
Wykorzystywanie usługi Garden - Nie jest to prawdziwy atak
To są tylko interesujące uwagi na temat usługi, ale ponieważ nasłuchuje ona tylko na localhost, te uwagi nie będą miały wpływu, którego nie wykorzystaliśmy już wcześniej
Domyślnie każdy worker concourse będzie uruchamiał usługę Garden na porcie 7777. Usługa ta jest używana przez Web mastera do wskazania workerowi co ma wykonać (pobranie obrazu i uruchomienie każdego zadania). Brzmi to całkiem dobrze dla atakującego, ale istnieją pewne zabezpieczenia:
Jest ona wystawiona tylko lokalnie (127.0.0.1) i myślę, że gdy worker uwierzytelnia się wobec Web za pomocą specjalnej usługi SSH, tworzony jest tunel, aby serwer webowy mógł rozmawiać z każdą usługą Garden wewnątrz każdego workera.
Serwer webowy monitoruje uruchomione kontenery co kilka sekund, a nieoczekiwane kontenery są usuwane. Więc jeśli chcesz uruchomić niestandardowy kontener, musisz manipulować komunikacją między serwerem webowym a usługą Garden.
Workery concourse działają z wysokimi uprawnieniami kontenerów:
Jednak techniki takie jak montowanie urządzenia /dev węzła lub release_agent nie działają (ponieważ prawdziwe urządzenie z systemem plików węzła nie jest dostępne, tylko wirtualne). Nie możemy uzyskać dostępu do procesów węzła, więc ucieczka z węzła bez exploitów jądra staje się skomplikowana.
W poprzedniej sekcji widzieliśmy, jak uciec z uprzywilejowanego kontenera, więc jeśli możemy wykonać polecenia w uprzywilejowanym kontenerze utworzonym przez obecnego workera, moglibyśmy uciec do węzła.
Zauważ, że podczas zabawy z concourse zauważyłem, że gdy nowy kontener jest uruchamiany, aby coś wykonać, procesy kontenera są dostępne z kontenera workera, więc to tak, jakby kontener tworzył nowy kontener wewnątrz siebie.
Dostanie się do działającego uprzywilejowanego kontenera
Tworzenie nowego uprzywilejowanego kontenera
Możesz bardzo łatwo utworzyć nowy kontener (po prostu uruchom losowy UID) i wykonać na nim coś:
Jednakże serwer webowy sprawdza co kilka sekund kontenery, które są uruchomione, i jeśli zostanie wykryty nieoczekiwany, zostanie usunięty. Ponieważ komunikacja odbywa się w HTTP, można manipulować komunikacją, aby uniknąć usunięcia nieoczekiwanych kontenerów:
Referencje
https://concourse-ci.org/vars.html
Last updated