Concourse Enumeration & Attacks
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
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 na pipeline, takie jak uruchamianie budów i przypinanie zasobów, jednak 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 ich działania). Przeczytaj więcej na ten temat w: https://concourse-ci.org/user-roles.html
Zauważ, że Concourse grupuje pipeline w zespołach. Dlatego użytkownicy należący do zespołu będą mogli zarządzać tymi pipeline i może istnieć kilka zespołów. Użytkownik może należeć do kilku zespołów i mieć różne uprawnienia w każdym z nich.
W konfiguracjach YAML możesz konfigurować wartości używając składni ((_source-name_:_secret-path_._secret-field_))
.
Z dokumentacji: source-name jest opcjonalny, a jeśli zostanie pominięty, zostanie użyty menedżer poświadczeń w klastrze, lub wartość może być podana statycznie.
Opcjonalne _secret-field_ określa pole w pobranym sekrecie do odczytu. Jeśli zostanie pominięte, menedżer poświadczeń może zdecydować się na odczytanie 'domyślnego pola' z pobranych poświadczeń, 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
.
Statyczne zmienne mogą być określone w krokach zadań:
Or using the following fly
arguments:
-v
or --var
NAME=VALUE
ustawia ciąg VALUE
jako wartość dla zmiennej NAME
.
-y
or --yaml-var
NAME=VALUE
analizuje VALUE
jako YAML i ustawia go jako wartość dla zmiennej NAME
.
-i
or --instance-var
NAME=VALUE
analizuje VALUE
jako YAML i ustawia go jako wartość dla zmiennej instancji NAME
. Zobacz Grouping Pipelines, aby dowiedzieć się więcej o zmiennych instancji.
-l
or --load-vars-from
FILE
ładuje FILE
, dokument YAML zawierający mapowanie nazw zmiennych na wartości, i ustawia je wszystkie.
Istnieją różne sposoby, w jakie Menadżer Poświadczeń może być określony w potoku, przeczytaj jak w https://concourse-ci.org/creds.html. Ponadto, Concourse obsługuje różne menedżery poświadczeń:
Zauważ, że jeśli masz jakiś rodzaj dostępu do zapisu do Concourse, możesz tworzyć zadania, aby wyekstrahować te sekrety, ponieważ Concourse musi mieć możliwość ich dostępu.
Aby enumerować środowisko Concourse, najpierw musisz zgromadzić ważne poświadczenia lub znaleźć uwierzytelniony token, prawdopodobnie w pliku konfiguracyjnym .flyrc
.
Aby się zalogować, musisz znać punkt końcowy, nazwę zespołu (domyślnie main
) oraz 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 zapisywany w $HOME/.flyrc
domyślnie, przeszukując maszyny, możesz tam znaleźć poświadczenia.
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
Lista potoków:
fly -t <target> pipelines -a
Uzyskaj yaml potoku (wrażliwe informacje mogą być zawarte w definicji):
fly -t <target> get-pipeline -p <pipeline-name>
Uzyskaj wszystkie zmienne konfiguracyjne zadeklarowane w potoku
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 sekretów potoków używanych (jeśli możesz tworzyć/modyfikować zadanie lub przejąć kontener, możesz je wyekstrahować):
Lista pracowników:
fly -t <target> workers
Lista kontenerów:
fly -t <target> containers
Lista budów (aby zobaczyć, co jest uruchomione):
fly -t <target> builds
admin:admin
test:test
W poprzedniej sekcji zobaczyliśmy, jak można uzyskać wszystkie nazwy i zmienne sekretów używanych przez pipeline. Zmienne mogą zawierać wrażliwe informacje, a nazwa sekretów będzie przydatna później do próby ich kradzieży.
Jeśli masz wystarczające uprawnienia (rola członka lub wyższa), będziesz mógł wymienić pipeline'y i role i po prostu uzyskać sesję wewnątrz kontenera <pipeline>/<job>
używając:
Z tymi uprawnieniami możesz być w stanie:
Kraść sekrety wewnątrz kontenera
Spróbować uciec do węzła
Enumerować/Abuse endpoint metadanych chmury (z podu i z węzła, jeśli to możliwe)
Jeśli masz wystarczające uprawnienia (rola członka lub wyższa) będziesz mógł tworzyć/modyfikować nowe pipeline. Sprawdź ten przykład:
With the modification/creation of a new pipeline you will be able to:
Kraść sekrety (poprzez ich wyświetlanie lub wchodzenie do kontenera i uruchamianie env
)
Uciec do węzła (dając ci wystarczające uprawnienia - privileged: true
)
Enumerate/Abuse cloud metadata endpoint (z poda i z węzła)
Usunąć utworzoną pipeline
To jest podobne do poprzedniej metody, ale zamiast modyfikować/tworzyć całą nową pipeline, możesz po prostu wykonać niestandardowe zadanie (co prawdopodobnie będzie znacznie bardziej ukryte):
W poprzednich sekcjach zobaczyliśmy, jak wykonać zadanie uprzywilejowane z concourse. To nie da kontenerowi dokładnie takiego samego dostępu jak flaga uprzywilejowana 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 "skomplikowana".
W poniższym PoC zamierzamy użyć release_agent do ucieczki z pewnymi drobnymi modyfikacjami:
Jak mogłeś zauważyć, to jest po prostu zwykłe wydanie_agenta ucieczki, po prostu modyfikując ścieżkę cmd w węźle
Zwykła ucieczka_agenta z drobną modyfikacją wystarczy do tego:
Nawet jeśli kontener web ma wyłączone niektóre zabezpieczenia, nie działa jako zwykły kontener z uprawnieniami (na przykład, nie możesz zamontować i możliwości są bardzo ograniczone, więc wszystkie łatwe sposoby na ucieczkę z kontenera są bezużyteczne).
Jednak przechowuje lokalne poświadczenia w postaci niezaszyfrowanej:
Możesz użyć tych poświadczeń do logowania się do serwera webowego i utworzenia uprzywilejowanego kontenera oraz ucieczki do węzła.
W środowisku możesz również znaleźć informacje do dostępu do instancji postgresql, z której korzysta concourse (adres, nazwa użytkownika, hasło i baza danych oraz inne informacje):
To tylko kilka interesujących uwag na temat usługi, ale ponieważ nasłuchuje ona tylko na localhost, te uwagi nie będą miały żadnego wpływu, którego wcześniej nie wykorzystaliśmy.
Domyślnie każdy pracownik concourse będzie uruchamiał usługę Garden na porcie 7777. Usługa ta jest używana przez mistrza sieci do wskazania pracownikowi co musi wykonać (pobranie obrazu i uruchomienie każdego zadania). To brzmi całkiem dobrze dla atakującego, ale istnieje kilka dobrych zabezpieczeń:
Jest ekspozycja lokalna (127.0.0.1) i myślę, że gdy pracownik uwierzytelni się w sieci 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 pracownika.
Serwer webowy monitoruje działające 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.
Pracownicy concourse działają z wysokimi uprawnieniami kontenera:
Jednak techniki takie jak montowanie urządzenia /dev w węźle lub release_agent nie zadział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 zobaczyliśmy, jak uciec z uprzywilejowanego kontenera, więc jeśli możemy wykonywać polecenia w uprzywilejowanym kontenerze utworzonym przez aktualnego pracownika, moglibyśmy uciec do węzła.
Zauważ, że bawiąc się z concourse, zauważyłem, że gdy nowy kontener jest uruchamiany, aby coś wykonać, procesy kontenera są dostępne z kontenera pracownika, 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 stworzyć nowy kontener (po prostu uruchom losowy UID) i wykonać coś na nim:
Jednak serwer WWW sprawdza co kilka sekund działające kontenery, a jeśli zostanie odkryty niespodziewany, zostanie on usunięty. Ponieważ komunikacja odbywa się w HTTP, możesz manipulować komunikacją, aby uniknąć usunięcia niespodziewanych kontenerów:
https://concourse-ci.org/vars.html
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)