Concourse Enumeration & Attacks
Concourse Enumeration & Attacks
Benutzerrollen & Berechtigungen
Concourse kommt mit fünf Rollen:
Concourse Admin: Diese Rolle wird nur den Eigentümern des Hauptteams (Standard-Initial-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 lesen und schreiben innerhalb der Team-Assets, aber nicht die Team-Einstellungen ändern.
pipeline-operator: Pipeline-Operatoren können Pipeline-Operationen wie das Auslösen von Builds und das Fixieren von Ressourcen durchführen, jedoch können sie die Pipeline-Konfigurationen nicht aktualisieren.
viewer: Team-Zuschauer haben "nur-Lese-Zugriff auf ein Team und seine Pipelines.
Darüber hinaus können die Berechtigungen der Rollen owner, member, pipeline-operator und viewer durch Konfiguration von RBAC geändert werden (indem spezifischere Aktionen konfiguriert werden). Mehr dazu 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 es können mehrere Teams existieren. Ein Benutzer kann mehreren Teams angehören und in jedem von ihnen unterschiedliche Berechtigungen haben.
Vars & Credential Manager
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 das secret-field von doppelten Anführungszeichen "..."
umgeben sein, wenn sie Sonderzeichen 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
Statische Vars können in Task-Schritten angegeben werden:
Oder mit den folgenden fly
Argumenten:
-v
oder--var
NAME=VALUE
setzt den StringVALUE
als Wert für die VariableNAME
.-y
oder--yaml-var
NAME=VALUE
parstVALUE
als YAML und setzt es als Wert für die VariableNAME
.-i
oder--instance-var
NAME=VALUE
parstVALUE
als YAML und setzt es als Wert für die InstanzvariableNAME
. Siehe Grouping Pipelines, um mehr über Instanzvariablen zu erfahren.-l
oder--load-vars-from
FILE
lädtFILE
, ein YAML-Dokument, das Variablennamen zu Werten zuordnet, und setzt sie alle.
Credential Management
Es gibt verschiedene Möglichkeiten, wie ein Credential Manager in einer Pipeline angegeben werden kann, lesen Sie wie unter https://concourse-ci.org/creds.html. Darüber hinaus unterstützt Concourse verschiedene Credential Manager:
Beachten Sie, dass wenn Sie irgendeine Art von Schreibzugriff auf Concourse haben, Sie Jobs erstellen können, um diese Geheimnisse zu exfiltrieren, da Concourse in der Lage sein muss, auf sie zuzugreifen.
Concourse Enumeration
Um eine Concourse-Umgebung zu enumerieren, müssen Sie zuerst gültige Anmeldeinformationen sammeln oder ein authentifiziertes Token finden, wahrscheinlich in einer .flyrc
Konfigurationsdatei.
Login und Aktueller Benutzer enum
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 Maschinen durchsuchen, könnten Sie dort die Anmeldeinformationen finden.
Teams & Benutzer
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
Pipelines
Pipelines auflisten:
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 in der Pipeline deklarierten Variablen 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 verwendeten Pipeline-Geheimnisnamen abrufen (wenn Sie einen Job erstellen/ändern oder einen Container kapern können, könnten Sie sie exfiltrieren):
Container & Worker
Worker auflisten:
fly -t <target> workers
Container auflisten:
fly -t <target> containers
Builds auflisten (um zu sehen, was läuft):
fly -t <target> builds
Concourse-Angriffe
Anmeldeinformationen Brute-Force
admin:admin
test:test
Aufzählung von Secrets und Parametern
Im vorherigen Abschnitt haben wir gesehen, wie man alle Secret-Namen und Variablen erhält, die von der Pipeline verwendet werden. Die Variablen könnten sensible Informationen enthalten und die Namen der Secrets werden später nützlich sein, um zu versuchen, sie zu stehlen.
Sitzung innerhalb eines laufenden oder kürzlich ausgeführten Containers
Wenn Sie genügend Privilegien haben (Mitgliedsrolle oder höher), können Sie Pipelines und Rollen auflisten und einfach eine Sitzung innerhalb des <pipeline>/<job>
Containers erhalten, indem Sie:
Mit diesen Berechtigungen könnten Sie möglicherweise:
Geheimnisse stehlen innerhalb des Containers
Versuchen, auf den Knoten zu entkommen
Cloud-Metadaten-Endpunkt auflisten/missbrauchen (vom Pod und vom Knoten, falls möglich)
Pipeline-Erstellung/Änderung
Wenn Sie über ausreichende Privilegien (Mitgliedsrolle oder höher) verfügen, können Sie neue Pipelines erstellen/ändern. Sehen Sie sich dieses Beispiel an:
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)Zum Node entkommen (indem Sie sich genügend Privilegien verschaffen -
privileged: true
)Cloud-Metadaten-Endpunkt auflisten/missbrauchen (vom Pod und vom Node aus)
Erstellte Pipeline löschen
Benutzerdefinierte Aufgabe ausführen
Dies ist ähnlich der vorherigen Methode, aber anstatt eine ganze neue Pipeline zu ändern/erstellen, können Sie einfach eine benutzerdefinierte Aufgabe ausführen (was wahrscheinlich viel unauffälliger sein wird):
Ausbruch zum Node von einer privilegierten Aufgabe
In den vorherigen Abschnitten haben wir gesehen, wie man eine privilegierte Aufgabe mit concourse ausführt. Dies gibt dem Container nicht genau denselben Zugriff wie das privilegierte Flag in einem Docker-Container. Zum Beispiel wird man das Node-Dateisystemgerät in /dev nicht sehen, daher könnte der Ausbruch "komplexer" sein.
Im folgenden PoC werden wir den release_agent mit einigen kleinen Modifikationen verwenden, um auszubrechen:
Wie Sie vielleicht bemerkt haben, ist dies nur ein regular release_agent escape, bei dem lediglich der Pfad des cmd im Node geändert wird.
Flucht zum Node aus einem Worker-Container
Ein regular release_agent escape mit einer kleinen Modifikation ist dafür ausreichend:
Entkommen zum Node vom Web-Container
Auch wenn der Web-Container einige Verteidigungen deaktiviert hat, läuft er nicht als ein gewöhnlicher privilegierter Container (zum Beispiel, Sie können nicht mounten und die Fähigkeiten sind sehr eingeschränkt, daher sind alle einfachen Wege, um aus dem Container zu entkommen, nutzlos).
Jedoch speichert er lokale Anmeldedaten im Klartext:
Du könntest diese Anmeldedaten verwenden, um dich gegen den Webserver anzumelden und einen privilegierten Container zu erstellen und auf den 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):
Missbrauch des Garden-Dienstes - Kein echter Angriff
Dies sind nur einige interessante Notizen über den Dienst, aber da er nur auf localhost hört, werden diese Notizen keine Auswirkungen haben, die 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 Image herunterladen und jede Aufgabe ausführen). Das klingt ziemlich gut für einen Angreifer, aber es gibt einige gute Schutzmaßnahmen:
Es ist nur lokal exponiert (127.0.0.1) und ich denke, wenn sich der Worker mit dem speziellen SSH-Dienst gegen das Web authentifiziert, wird ein Tunnel erstellt, sodass der Webserver mit jedem Garden-Dienst innerhalb jedes Workers sprechen 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 Container-Berechtigungen:
Allerdings funktionieren Techniken wie das Mounten des /dev-Geräts des Nodes oder release_agent nicht (da das echte Gerät mit dem Dateisystem des Nodes nicht zugänglich ist, nur ein virtuelles). Wir können nicht auf die Prozesse des Nodes zugreifen, daher wird das Entkommen aus dem Node 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 Node entkommen.
Beachten Sie, dass ich beim Spielen mit Concourse festgestellt habe, dass, wenn ein neuer Container gestartet wird, um etwas auszuführen, die Containerprozesse vom Worker-Container aus zugänglich sind, sodass es wie ein Container ist, der einen neuen Container in sich erstellt.
In einen laufenden privilegierten Container gelangen
Erstellen eines neuen privilegierten Containers
Sie können sehr einfach einen neuen Container erstellen (einfach eine zufällige UID ausführen) 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:
Referenzen
https://concourse-ci.org/vars.html
Last updated