Concourse Enumeration & Attacks
Wyliczanie i Ataki na Concourse
Role Użytkownika i Uprawnienia
Concourse posiada 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ć zmienione przez RBAC.właściciel: Właściciele zespołu mogą modyfikować wszystko w zespole.
członek: Członkowie zespołu mogą czytać i pisać w zasobach zespołu, ale nie mogą modyfikować ustawień zespołu.
operator-pipeline: Operatorzy potoku mogą wykonywać operacje potoku, takie jak uruchamianie budowy i przypinanie zasobów, jednak nie mogą aktualizować konfiguracji potoku.
widz: Widzowie zespołu mają dostęp "tylko do odczytu" do zespołu i jego potoków.
Ponadto uprawnienia ról właściciela, członka, operatora potoku i widza mogą być zmienione poprzez konfigurację RBAC (konfigurując bardziej szczegółowo jego działania). Dowiedz się więcej na: https://concourse-ci.org/user-roles.html
Zauważ, że Concourse grupuje potoki wewnątrz Zespołów. Dlatego użytkownicy należący do Zespołu będą mogli zarządzać tymi potokami 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.
Vars & Menedżer Poświadczeń
W konfiguracjach YAML można konfigurować wartości za pomocą składni ((_source-name_:_secret-path_._secret-field_))
.
Z dokumentacji: Nazwa-źródła jest opcjonalna, a jeśli jest pominięta, zostanie użyty menedżer poświadczeń na poziomie klastra, lub wartość może być podana statycznie.
Opcjonalne _secret-field_ określa pole w pobranym tajnym kluczu do odczytu. Jeśli jest pominięte, 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 jak .
i :
. Na przykład, ((source:"my.secret"."field:1"))
ustawia secret-path na my.secret
i secret-field na field:1
.
Static Vars
Statyczne zmienne można określić w krokach zadań:
Zarządzanie poświadczeniami
Istnieją różne sposoby określenia Menedżera Poświadczeń w potoku, przeczytaj więcej na stronie https://concourse-ci.org/creds.html. Co więcej, Concourse obsługuje różne menedżery poświadczeń:
Zauważ, że jeśli masz jakikolwiek rodzaj dostępu do zapisu w Concourse, możesz tworzyć zadania do wycieku tych sekretów, ponieważ Concourse musi mieć do nich dostęp.
Wyliczanie Concourse
Aby wyliczyć środowisko Concourse, najpierw musisz zbierać ważne poświadczenia lub znaleźć uwierzytelniony token, prawdopodobnie w pliku konfiguracyjnym .flyrc
.
Logowanie i wyliczanie bieżącego użytkownika
Aby zalogować się, musisz znać punkt końcowy, nazwę zespołu (domyślnie to
main
) i zespoł, 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]
Pobierz skonfigurowane cele:
fly targets
Sprawdź, czy skonfigurowane połączenie celu jest wciąż ważne:
fly -t <target> status
Pobierz rolę użytkownika w stosunku do wskazanego celu:
fly -t <target> userinfo
Zauważ, że token API jest zapisywany domyślnie w $HOME/.flyrc
, podczas plądrowania maszyn możesz tam znaleźć poświadczenia.
Zespoły i Użytkownicy
Pobierz listę Zespołów
fly -t <target> teams
Pobierz role wewnątrz zespołu
fly -t <target> get-team -n <team-name>
Pobierz listę użytkowników
fly -t <target> active-users
Potoki
Wyświetl potoki:
fly -t <target> pipelines -a
Pobierz yaml potoku (w definicji mogą znajdować się informacje poufne):
fly -t <target> get-pipeline -p <pipeline-name>
Pobierz wszystkie zadeklarowane zmienne konfiguracyjne 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
Pobierz wszystkie nazwy sekretów używane w potokach (jeśli możesz tworzyć/modyfikować zadanie lub przejąć kontener, możesz je wycieknąć):
Kontenery i Pracownicy
Lista pracowników:
fly -t <cel> workers
Lista kontenerów:
fly -t <cel> containers
Lista budów (aby zobaczyć co jest uruchomione):
fly -t <cel> builds
Ataki na Concourse
Brutalna siła poświadczeń
admin:admin
test:test
Wyliczanie sekretów i parametrów
W poprzedniej sekcji zobaczyliśmy, jak można uzyskać wszystkie nazwy sekretów i zmienne używane przez potok. Zmienne mogą zawierać poufne informacje i nazwa sekretów będzie przydatna później do próby ich kradzieży.
Sesja wewnątrz uruchomionego lub niedawno uruchomionego kontenera
Jeśli masz wystarczające uprawnienia (rola członka lub wyższa), będziesz mógł wyświetlić potoki i role i po prostu uzyskać sesję wewnątrz kontenera <potok>/<zadanie>
używając:
Dzięki tym uprawnieniom możesz:
Ukradnij sekrety znajdujące się w kontenerze
Spróbuj uciec do węzła
Wylicz/Wykorzystaj punkt końcowy metadanych chmury (z pojemnika i z węzła, jeśli to możliwe)
Tworzenie/Modyfikacja potoku
Jeśli masz wystarczające uprawnienia (rola członka lub wyższa), będziesz mógł tworzyć/modyfikować nowe potoki. Sprawdź ten przykład:
Przy modyfikacji/utworzeniu nowego potoku będziesz mógł:
Ukradnij sekrety (poprzez wyświetlenie ich lub uzyskanie dostępu do kontenera i uruchomienie
env
)Ucieczka do węzła (nadając wystarczające uprawnienia -
privileged: true
)Wyliczanie/Missbruk metadanych chmury (z pojemnika i z węzła)
Usuń utworzony potok
Wykonaj niestandardowe zadanie
To jest podobne do poprzedniej metody, ale zamiast modyfikować/tworzyć cały nowy potok, możesz po prostu wykonać niestandardowe zadanie (co prawdopodobnie będzie o wiele bardziej skryte):
Ucieczka do węzła z zadania uprzywilejowanego
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 dockerowym. 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 użyjemy release_agent do ucieczki z pewnymi drobnymi modyfikacjami:
Jak mogłeś zauważyć, to po prostu zwykłe ucieczka z release_agent po prostu modyfikując ścieżkę cmd w węźle
Ucieczka do węzła z kontenera pracownika
Zwykła ucieczka z release_agent z niewielką modyfikacją jest wystarczająca:
Ucieczka do węzła z kontenera sieciowego
Nawet jeśli kontener sieciowy ma wyłączone niektóre zabezpieczenia, nie działa jako zwykły kontener uprzywilejowany (na przykład nie można zamontować i uprawnienia są bardzo ograniczone, więc wszystkie łatwe sposoby ucieczki z kontenera są bezużyteczne).
Jednak przechowuje lokalne dane uwierzytelniające w postaci zwykłego tekstu:
Możesz użyć tych poświadczeń do zalogowania się na serwerze sieciowym i utworzenia uprzywilejowanego kontenera oraz ucieczki do węzła.
W środowisku można również znaleźć informacje o dostępie do instancji postgresql, którą używa concourse (adres, nazwa użytkownika, hasło i baza danych między innymi informacje):
Nadużywanie usługi Garden - Nie jest to rzeczywisty atak
To tylko kilka interesujących uwag na temat usługi, ale ponieważ słucha ona tylko na localhost, te uwagi nie będą miały żadnego wpływu, którego już 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 Web mastera do wskazania pracownikowi co ma wykonać (pobranie obrazu i uruchomienie każdego zadania). Brzmi to całkiem dobrze dla atakującego, ale istnieją pewne fajne zabezpieczenia:
Jest eksponowana tylko lokalnie (127.0.0.1) i wydaje mi się, że gdy pracownik uwierzytelnia się ponownie w sieci Web za pomocą specjalnej usługi SSH, tworzony jest tunel, dzięki czemu serwer sieciowy może komunikować się z każdą usługą Garden wewnątrz każdego pracownika.
Serwer sieciowy monitoruje uruchomione kontenery co kilka sekund, a niespodziewane kontenery są usuwane. Dlatego jeśli chcesz uruchomić niestandardowy kontener, musisz mieszać w komunikacji między serwerem sieciowym a usługą garden.
Pracownicy Concourse działają z wysokimi uprawnieniami kontenera:
Jednak techniki takie jak montowanie urządzenia /dev węzła lub release_agent nie zadziałają (ponieważ rzeczywiste 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 wykorzystania luk w jądrze staje się skomplikowana.
W poprzednim rozdziale zobaczyliśmy, jak uciec z uprzywilejowanego kontenera, więc jeśli możemy wykonać polecenia w uprzywilejowanym kontenerze utworzonym przez bieżącego pracownika, moglibyśmy uciec do węzła.
Zauważ, że bawiąc się z Concourse zauważyłem, że gdy nowy kontener jest uruchamiany do wykonania czegoś, procesy kontenera są dostępne z kontenera pracownika, więc to jakby kontener tworzył nowy kontener wewnątrz siebie.
Wejście do działającego uprzywilejowanego kontenera
Tworzenie nowego kontenera uprzywilejowanego
Możesz bardzo łatwo utworzyć nowy kontener (uruchom losowy UID) i wykonać na nim jakieś polecenie:
Jednak serwer sieciowy co kilka sekund sprawdza kontenery, które są uruchomione, i jeśli zostanie odkryty niespodziewany, zostanie usunięty. Ponieważ komunikacja odbywa się za pomocą protokołu HTTP, można przerobić komunikację, aby uniknąć usunięcia niespodziewanych kontenerów:
Odnośniki
https://concourse-ci.org/vars.html
Last updated