Concourse Enumeration & Attacks
Last updated
Last updated
Lerne & übe AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Lerne & übe GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Concourse kommt mit fünf Rollen:
Concourse Admin: Diese Rolle wird nur den Eigentümern des Hauptteams (standardmäßiges anfängliches Concourse-Team) zugewiesen. Admins können andere Teams konfigurieren (z.B.: fly set-team
, fly destroy-team
...). Die Berechtigungen dieser Rolle können nicht durch RBAC beeinflusst werden.
Owner: Team-Eigentümer können alles innerhalb des Teams ändern.
Member: Team-Mitglieder können innerhalb der Team-Ressourcen lesen und schreiben, können jedoch die Teameinstellungen nicht ändern.
Pipeline-Operator: Pipeline-Operatoren können Pipeline-Operationen wie das Auslösen von Builds und das Festlegen von Ressourcen durchführen, können jedoch die Pipeline-Konfigurationen nicht aktualisieren.
Viewer: Team-Viewer haben "nur-Lese"-Zugriff auf ein Team und dessen Pipelines.
Darüber hinaus können die Berechtigungen der Rollen Owner, Member, Pipeline-Operator und Viewer durch die Konfiguration von RBAC (insbesondere durch die Konfiguration ihrer Aktionen) geändert werden. Lies mehr darüber unter: https://concourse-ci.org/user-roles.html
Beachte, dass Concourse Pipelines innerhalb von Teams gruppiert. Daher können Benutzer, die zu einem Team gehören, diese Pipelines verwalten und mehrere Teams können existieren. Ein Benutzer kann mehreren Teams angehören und unterschiedliche Berechtigungen in jedem von ihnen haben.
In den YAML-Konfigurationen kannst du Werte mit der Syntax ((_source-name_:_secret-path_._secret-field_))
konfigurieren.
Aus den Dokumenten: Der source-name ist optional, und wenn er weggelassen wird, wird der clusterweite Credential Manager verwendet, oder der Wert kann statisch bereitgestellt werden.
Das optionale _secret-field_ gibt ein Feld im abgerufenen Geheimnis an, das gelesen werden soll. Wenn es weggelassen wird, kann der Credential Manager wählen, ein 'Standardfeld' aus dem abgerufenen Credential zu lesen, wenn das Feld existiert.
Darüber hinaus können der secret-path und secret-field von doppelten Anführungszeichen "..."
umgeben sein, wenn sie spezielle Zeichen wie .
und :
enthalten. Zum Beispiel wird ((source:"my.secret"."field:1"))
den secret-path auf my.secret
und das secret-field auf field:1
setzen.
Statische Vars können in Aufgaben-Schritten angegeben werden:
Or using the following fly
Argumenten:
-v
oder --var
NAME=VALUE
setzt den String VALUE
als Wert für die Var NAME
.
-y
oder --yaml-var
NAME=VALUE
analysiert VALUE
als YAML und setzt es als Wert für die Var NAME
.
-i
oder --instance-var
NAME=VALUE
analysiert VALUE
als YAML und setzt es als Wert für die Instanzvar NAME
. Siehe Grouping Pipelines, um mehr über Instanzvars zu erfahren.
-l
oder --load-vars-from
FILE
lädt FILE
, ein YAML-Dokument, das die Zuordnung von Var-Namen zu Werten enthält, und setzt sie alle.
Es gibt verschiedene Möglichkeiten, wie ein Credential Manager in einer Pipeline angegeben werden kann, lesen Sie mehr dazu in https://concourse-ci.org/creds.html. Darüber hinaus unterstützt Concourse verschiedene Credential Manager:
Beachten Sie, dass Sie, wenn Sie eine Art von Schreibzugriff auf Concourse haben, Jobs erstellen können, um diese Geheimnisse zu exfiltrieren, da Concourse in der Lage sein muss, auf sie zuzugreifen.
Um eine Concourse-Umgebung zu enumerieren, müssen Sie zuerst gültige Anmeldeinformationen sammeln oder ein authentifiziertes Token finden, wahrscheinlich in einer .flyrc
-Konfigurationsdatei.
Um sich anzumelden, müssen Sie den Endpunkt, den Teamnamen (Standard ist main
) und ein Team, dem der Benutzer angehört, kennen:
fly --target example login --team-name my-team --concourse-url https://ci.example.com [--insecure] [--client-cert=./path --client-key=./path]
Konfigurierte Ziele abrufen:
fly targets
Überprüfen, ob die konfigurierte Zielverbindung noch gültig ist:
fly -t <target> status
Rolle des Benutzers gegen das angegebene Ziel abrufen:
fly -t <target> userinfo
Beachten Sie, dass das API-Token standardmäßig in $HOME/.flyrc
gespeichert wird. Wenn Sie eine Maschine durchsuchen, könnten Sie dort die Anmeldeinformationen finden.
Eine Liste der Teams abrufen
fly -t <target> teams
Rollen innerhalb des Teams abrufen
fly -t <target> get-team -n <team-name>
Eine Liste der Benutzer abrufen
fly -t <target> active-users
Liste der Pipelines:
fly -t <target> pipelines -a
Pipeline YAML abrufen (sensible Informationen könnten in der Definition gefunden werden):
fly -t <target> get-pipeline -p <pipeline-name>
Alle konfigurierten Vars der Pipeline abrufen
for pipename in $(fly -t <target> pipelines | grep -Ev "^id" | awk '{print $2}'); do echo $pipename; fly -t <target> get-pipeline -p $pipename -j | grep -Eo '"vars":[^}]+'; done
Alle Namen der verwendeten Pipelines-Geheimnisse abrufen (wenn Sie einen Job erstellen/modifizieren oder einen Container hijacken können, könnten Sie sie exfiltrieren):
Liste Worker:
fly -t <target> workers
Liste Container:
fly -t <target> containers
Liste Builds (um zu sehen, was läuft):
fly -t <target> builds
admin:admin
test:test
Im vorherigen Abschnitt haben wir gesehen, wie Sie alle Geheimnisnamen und Variablen abrufen können, die von der Pipeline verwendet werden. Die Variablen können sensible Informationen enthalten und der Name der Geheimnisse wird später nützlich sein, um zu versuchen, sie zu stehlen.
Wenn Sie über ausreichende Berechtigungen (Mitgliedsrolle oder mehr) verfügen, können Sie Pipelines und Rollen auflisten und einfach eine Sitzung innerhalb des <pipeline>/<job>
Containers mit folgendem Befehl erhalten:
Mit diesen Berechtigungen könnten Sie in der Lage sein:
Die Geheimnisse im Container zu stehlen
Zu versuchen, zum Knoten zu entkommen
Den Cloud-Metadaten-Endpunkt zu enumerieren/missbrauchen (vom Pod und vom Knoten, wenn möglich)
Wenn Sie über ausreichende Berechtigungen (Mitgliedsrolle oder mehr) verfügen, können Sie neue Pipelines erstellen/ändern. Überprüfen Sie dieses Beispiel:
Mit der Änderung/Erstellung einer neuen Pipeline können Sie:
Geheimnisse stehlen (indem Sie sie ausgeben oder in den Container gelangen und env
ausführen)
Entkommen zum Knoten (indem Sie Ihnen genügend Berechtigungen geben - privileged: true
)
Cloud-Metadaten-Endpunkt auflisten/missbrauchen (vom Pod und vom Knoten)
Gelöschte Pipeline erstellen
Dies ist ähnlich wie die vorherige Methode, aber anstatt eine ganze neue Pipeline zu ändern/zu erstellen, können Sie einfach eine benutzerdefinierte Aufgabe ausführen (die wahrscheinlich viel heimlicher sein wird):
In den vorherigen Abschnitten haben wir gesehen, wie man eine privilegierte Aufgabe mit Concourse ausführt. Dies gibt dem Container nicht genau den gleichen Zugriff wie das privilegierte Flag in einem Docker-Container. Zum Beispiel werden Sie das Knoten-Dateisystemgerät in /dev nicht sehen, sodass das Entkommen "komplexer" sein könnte.
In der folgenden PoC werden wir den release_agent verwenden, um mit einigen kleinen Modifikationen zu entkommen:
Wie Sie vielleicht bemerkt haben, handelt es sich hierbei nur um eine reguläre release_agent-Escape, bei der der Pfad des cmd im Knoten geändert wird.
Eine reguläre release_agent-Escape mit einer kleinen Modifikation reicht dafür aus:
Auch wenn der Web-Container einige Verteidigungen deaktiviert hat, läuft er nicht als ein gewöhnlicher privilegierter Container (zum Beispiel kannst du nicht mounten und die Fähigkeiten sind sehr begrenzt, sodass alle einfachen Möglichkeiten, aus dem Container zu entkommen, nutzlos sind).
Allerdings speichert er lokale Anmeldeinformationen im Klartext:
Du könntest diese Anmeldeinformationen verwenden, um dich am Webserver anzumelden und einen privilegierten Container zu erstellen und zum Knoten zu entkommen.
In der Umgebung kannst du auch Informationen finden, um auf die postgresql-Instanz zuzugreifen, die concourse verwendet (Adresse, Benutzername, Passwort und Datenbank unter anderem Informationen):
Dies sind nur einige interessante Hinweise zum Dienst, aber da er nur auf localhost hört, werden diese Hinweise keinen Einfluss haben, den wir nicht bereits zuvor ausgenutzt haben.
Standardmäßig wird jeder Concourse-Worker einen Garden Dienst auf Port 7777 ausführen. Dieser Dienst wird vom Web-Master verwendet, um dem Worker anzuzeigen, was er ausführen muss (das Bild herunterzuladen und jede Aufgabe auszuführen). Das klingt für einen Angreifer ziemlich gut, aber es gibt einige gute Schutzmaßnahmen:
Er ist nur lokal exponiert (127.0.0.1) und ich denke, wenn der Worker sich mit dem Web über den speziellen SSH-Dienst authentifiziert, wird ein Tunnel erstellt, damit der Webserver mit jedem Garden-Dienst innerhalb jedes Workers kommunizieren kann.
Der Webserver überwacht die laufenden Container alle paar Sekunden, und unerwartete Container werden gelöscht. Wenn Sie also einen benutzerdefinierten Container ausführen möchten, müssen Sie die Kommunikation zwischen dem Webserver und dem Garden-Dienst manipulieren.
Concourse-Worker laufen mit hohen Containerprivilegien:
Allerdings funktionieren Techniken wie das Mounten des /dev-Geräts des Knotens oder des release_agent nicht (da das echte Gerät mit dem Dateisystem des Knotens nicht zugänglich ist, sondern nur ein virtuelles). Wir können nicht auf Prozesse des Knotens zugreifen, daher wird das Entkommen aus dem Knoten ohne Kernel-Exploits kompliziert.
Im vorherigen Abschnitt haben wir gesehen, wie man aus einem privilegierten Container entkommt. Wenn wir also Befehle in einem privilegierten Container ausführen können, der vom aktuellen Worker erstellt wurde, könnten wir zum Knoten entkommen.
Beachten Sie, dass ich beim Spielen mit Concourse festgestellt habe, dass die Prozesse des Containers zugänglich sind, wenn ein neuer Container zum Ausführen von etwas erstellt wird, sodass es ist, als würde ein Container einen neuen Container in sich erstellen.
In einen laufenden privilegierten Container gelangen
Erstellen eines neuen privilegierten Containers
Sie können sehr einfach einen neuen Container erstellen (führen Sie einfach eine zufällige UID aus) und etwas darauf ausführen:
Allerdings überprüft der Webserver alle paar Sekunden die laufenden Container, und wenn ein unerwarteter entdeckt wird, wird er gelöscht. Da die Kommunikation über HTTP erfolgt, könnten Sie die Kommunikation manipulieren, um die Löschung unerwarteter Container zu vermeiden:
https://concourse-ci.org/vars.html
Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)