CTF-Infrastruktur als Proof-of-Concept in der Microsoft Azure Cloud

jk233

Einführung

Eine eigene Capture-The-Flag (CTF) Plattform zu betreiben bringt besondere Herausforderungen mit sich. Neben umfangreichem Benutzermanagement, dem Bereitstellen und sicherem Hosten von absichtlich verwundbaren Systemen, sowie einer möglichst einfachen Methode, spielbare Systeme von externen Quellen einzubinden.

So möchte man vielleicht der eigenen Community die Möglichkeit bieten, eigene Szenarien zu entwickeln, welche im Anschluss in die Plattform integriert werden können. Sollte die Plattform dann über einen gewissen Zeitraum durch Mitgliederzuwachs weitere Ressourcen benötigen, bietet sich eine schnelle und flexible Anpassung der Umgebung an. Auch andersherum bietet sich Skalierung in diesem Fall deutlich an, denn sollte man eine Plattform nur in kleinerem, womöglich privatem Kreis betreiben, so würde ein permanentes Bereitstellen aller verwundbaren Szenarien auch ungenutzt Ressourcen verbrauchen. 

CTF Infrastruktur in der Wolke

Um diese Möglichkeit der Bereitstellung einer CTF-Plattform einmal zu beleuchten, hab ich  mich an die Arbeit gemacht und einmal versucht, eine solche Plattform in einem Proof-of-Concept zu erstellen. Das entstandene Projekt trägt keinen Namen und dient eher der Evaluation, als einer tatsächlichen Umsetzung. Ein wichtiger Hinweis: Dieser Blogpost sollte nicht als eine 1:1 Anleitung für das Hosting einer eigenen Plattform herangezogen werden. Durch das Experimentieren mit verschiedenen Programmiersprachen, der Azure-Cloud und des signifikanten Umfangs eines solchen Vorhabens, ist das hier gezeigte lediglich als eine Art Beispiel zu sehen. Stellen, in welchen man weitere Features implementieren könnte, oder in welchen ich bewusst “Abkürzungen” gegangen bin, werden hervorgehoben. 

Die ursprüngliche Idee hatte sich bereits zu Beginn der Vorlesung entwickelt, da diese Thematik durch unser Institut für Cybersicherheit bereits auf die eine oder andere Weise im Fokus stand. Nie jedoch mit dieser Überlegung einer Azure basierten Plattform.

Durch den großen Umfang eines solchen Projekts musste zuerst eine Roadmap her, welche sich im Laufe des Projekts immer wieder angepasst und verändert hat. Final wurden folgende Ziele definiert:

Benutzerverwaltung

  • Registration
  • Login/Logout

Privates Netzwerk für bereits erstellte VMs

Die Möglichkeit für Benutzer, Maschinen zu “spawnen”

Auf Hinblick möglicher Skalierungswünsche habe ich mich für eine “Serverless” Umsetzung entschieden, wodurch ich mir für die geplante Webanwendung, sowie deren Datenbank keinerlei Hardware basierten Überlegungen stellen muss (beinahe, den Preis sollte man zumindest immer im Auge behalten).

Architektur & Tech-Stack

Die erstellte Plattform ist vollständig in Microsoft Azure gehostet. Hierfür werden verschiedene Dienste genutzt. Zunächst kann der Spieler über einen Browser seiner Wahl auf die Webanwendung, welche serverless als Azure Web App gehostet wird. Diese Webapp, geschrieben in Go, stellt eine Verbindung mit einer Datenbank her, in welcher alle notwendigen Informationen über die Benutzer und die spielbaren Maschinen gespeichert werden. Als Datenbank-Backend kommt eine Microsoft SQL Database zum Einsatz, welche ebenfalls serverless in Azure verfügbar ist. Darüber hinaus wird ein kleines privates Netzwerk benötigt, welches keinen Internetzugriff haben darf (hier sind absichtlich verwundbare Systeme im Einsatz). Hierfür wurde ein kleines virtuelles Netzwerk (Azure virtual network service – 10.0.0.0/28) erstellt. Da sich dieses ebenfalls in der Azure Cloud befindet, kann die Größe beliebig angepasst werden. Innerhalb dieses Netzwerks sollen alle gewünschten VMs liegen, welche von den Spielern angegriffen werden können. Unter Anbetracht der Tatsache, dass man auch von Community-Mitgliedern erstellte Szenarien einbinden können möchte, habe ich mich gegen die Nutzung von Ansible entschieden. Ansible, welches zum automatischen Deployen von VMs wunderbar genutzt werden kann, kommt in diesem Fall mit einem großen Problem: Jede Maschine, die von Dritten bereitgestellt würde, müsste erst auf ein Ansible-Playbook “übersetzt” werden. Das Ziel soll es sein, dass jede Person sich ein Szenario überlegen und einfach auf ihrem eigenen Computer erstellen kann. Beispielsweise mittels VMware oder VirtualBox eine kleine Linux-VM installieren, Schwachstellen-Pfade erstellen und teilen. Das Übersetzen in Ansible-Playbooks wird besonders dann problematisch, wenn bestimmte Software-Installationen/Versionen benötigt werden. Da die VMs innerhalb des privaten Netzwerkes keinerlei Internetzugriff haben dürfen, wird eine Installation oder das Patchen zum Problem.

Stattdessen kommt ein Powershell-Script zum Einsatz, welches bestehende Images auf den Azure-Account hochlädt und dort dann bei VMs eingebunden werden kann.

Schlussendlich muss es dem Spieler über die Webapp möglich sein VMs zu starten, bzw. zu stoppen, welche keinen direkten Zugriff auf das private Netzwerk haben. Hierfür kommen Azure-Runbooks mit öffentlichen Webhooks zum Einsatz.

Im Ablauf sieht es dann also wie folgt aus: Der Benutzer registriert sich/loggt sich über die Webapp ein. Die Webapp verifiziert die Daten mit dem MSSQL Server und steuert den Zugriff. Sobald der Benutzer eingeloggt ist, kann er den Status der verfügbaren VMs im Webpanel einsehen und durch das Drücken eines Knopfs, via Webhook auf die Runbooks, steuern.

Frontend

Für die Webapp kommt Go zum Einsatz. Da ich kein begabter Webentwickler bin, habe ich den visuellen Teil sehr schlicht mit Bootstrap umgesetzt. 

Aufgeteilt wurde das Projekt in verschiedene Unterordner.

Innerhalb von “Controllers” findet sich die eigentliche Logik der Anwendung. Hierbei gibt es, ähnlich einer REST-API, für jedes “Feature” eine eigene Funktion, mit einem eigenen ansteuerbaren Endpoint.

Für das Routing und diverse andere Features kommt das Gin Framework zum Einsatz.

Der visuelle Teil befindet sich aufgeteilt im Templates-Ordner, wobei die oben genannten Controller auf bestimmte Views verweisen, welche dann wiederum definieren, welche Layouts geladen werden. Auch die Informationsweitergabe an das Frontend erfolgt über die Controller, indem Gin bei der Weiterleitung alle in der View verwendbaren Variablen mitsendet:

Backend

Go erleichtert die Arbeit mit Datenbanken ungemein. Dank gorm (Go object-relation mapping) ist es kinderleicht möglich eigene Tabellen zu definieren und einheitlich im Code zu verwenden. Die gewünschte Tabelle wird mit allen Feldern in einem struct definiert und beim Start der Anwendung durch einen Aufruf von AutoMigrate auf dem MSSQL Server erstellt. Gewünschte Spalteneigenschaften, wie beispielsweise das Festlegen eines Primary Keys werden einfach hinzugeschrieben:

Das Session-Management wird hierbei von Gin zur Verfügung gestellt (weitere Informationen hier: https://github.com/gin-contrib/sessions)

Damit der Benutzer allerdings noch die Maschinen starten und stoppen kann, bedarf es noch der Azure Runbooks. Runbooks sind Funktionen oder Skripte, welche nur ausgeführt werden, wenn sie auch angesteuert werden. In diesem Fall wurden einfach Powershell-Scripte erstellt, welche sich in Azure einloggen, durch die Liste der vorhandenen Virtuellen Maschinen, in der eigenen Ressourcen-Gruppe läuft und nach bestimmten Tags sucht. Durch das Festlegen von Tags können Maschinen beispielsweise individuell angesteuert werden.

Nachdem die Playbooks hochgeladen wurden, müssen diese noch veröffentlicht werden. Die hier einmalig angezeigte URL wurde dann schlicht auf einen Button im Frontend gelegt, welcher einen Post-Request an einen internen Endpoint geschickt, welcher dann wiederum einen Post-Request an Azure versendet (wie oben bei den Controllern gezeigt).

CI/CD

Selbstverständlich wäre es viel zu mühsam, jedes Mal die Webanwendung manuell auf die Azure-Ressource zu verschieben. Allerdings gibt es unter Azure das Hindernis, dass im Gegensatz zu Python oder .NET die Sprache Go nicht offiziell “unterstützt” wird. Nachdem die Web App mit “.NET” erstellt wurde, ist es möglich, über Github Actions einen automatischen Bau-, Test- und Veröffentlichungsprozess zu starten. Damit die Anwendung dann jedoch auf dem Azure-System laufen kann, benötigt es eine für Windows kompilierte Binary. Zusätzlich muss die Azure Web App auch wissen, was es überhaupt auszuführen hat. Dies wird durch das Bereitstellen einer web.config Datei erreicht (diese wird von Microsoft IIS geladen):

Diese Datei muss im Build Ordner liegen. Zusätzlich müssen zum Kompilieren alle statischen Dateien wie Templates in den Build Ordner verschoben werden, ansonsten werden diese beim Ausführen Go-Datei auf dem Zielserver nicht gefunden.

Das gesamte Playbook definiert also zunächst das Zielsystem (Windows), legt dann die Ziel-Go Version fest, kopiert alle statischen Daten, baut die Anwendung, testet die Anwendung (ob eine Verbindung zur serverless Datenbank möglich ist) und rollt diese auf Azure aus.

Wichtig anzumerken an dieser Stelle ist, dass Azure Web-App nach dem Start einen zufälligen Port auswählt, um die Go-Website zu starten. Dieser Port befindet sich in einer Umgebungsvariable und kann beim Start einfach geladen werden. Um weiterhin in lokales Entwickeln zu ermöglichen, prüft man einfach ob eine Umgebungsvariable gesetzt ist oder nicht:

Schlussendlich gibt es noch ein PowerShell-Skript, welches es ermöglicht, vom eigenen Computer ein VM Image hochzuladen. Azure verlangt hierfür jedoch ein .vhd-Image, mit einer äußerst bestimmten Größe. Das Umwandeln mit Beispielsweise Qemu-img ist also vorher notwendig. Außerdem verwendet das Skript Az Funktionen, entsprechend muss die Az Gallery für Powershell installiert werden, bevor das Skript ausführbar wird.

Vor- und Nachteile

Als klaren Vorteil ist die Skalierbarkeit zu nennen. Kosten können hier – wenn richtig beachtet – signifikant gesenkt werden. Werden Ressourcen nicht benötigt, kann man diese ausschalten. Da das Bereitstellen von verwundbaren VMs mit sehr hohen Ressourcen verbunden ist (i. d. R. 1-4 vCores und 1-8GB RAM) bietet sich eine Cloud-Lösung definitiv an. Die Kosten können sich jedoch auch schnell zu einem Nachteil entwickeln. Fehlerhafte Konfigurationen im äußerst unübersichtlichen Azure Panel und die Monatsabrechnung auf der Kreditkarte könnte interessant werden.

Der größte Nachteil an diesem Proof-of-Concept ist das verwendete Powershell-Script zum Hochladen bestehender Images. Das Umwandeln benötigt bestimmte Formate und Größen und der Prozess dauert. Auch war es mir nicht möglich, die Images direkt als VMs zu deployen, oder VM-Templates daraus zu erstellen. Selbst wenn ein vollautomatisiertes Ausrollen gelingen sollte, hat man noch immer den stark limitierenden Faktor der eigenen Upload-Geschwindigkeit. VMs sind oftmals mehrere GB groß, insbesondere Windows-VMs können schnell auf 40 GB oder größer wachsen.

Technisch löst die Cloud einige Herausforderungen, die auch ich bei der Umsetzung hatte. Beispielsweise war das Ansteuern privater VMs durch die Runbooks äußerst einfach, sofern man einmal herausgefunden hat, dass es Runbooks gibt und wofür sie genutzt werden können. Wie sich im Post zeigt, sind viele Herausforderungen im Laufe des Projekts aufgetaucht, welche dank der Azure-Cloud fast alle gelöst werden konnten. Die einzigen beiden nicht gelösten Probleme sind einerseits die Problematik mit dem Hochladen bestehender Images und das Einbinden von einer eigenen .env Datei für Umgebungsvariablen. Scheinbar gibt es die Möglichkeit .env Dateien direkt auf die Azure Web App hochzuladen, diese muss jedoch jedes Mal manuell über das Azure Panel ausgetauscht werden. Ich habe sie leider nicht einmal zum Laufen bekommen, wodurch Credentials nun in bester Cybersicherheitsmannier im Code stehen.

Fazit

Diese Möglichkeit der Cloud-Nutzung ist definitiv etwas, das jedem CTF-Enthusiasten Freude und Kostenreduzierung bringen kann. Allerdings sind der Aufbau und die Unterteilung in hunderte “Unterprodukte”, gemeinsam mit der fehlenden Kostentransparenz, etwas, das man definitiv im Hinterkopf behalten sollte. Auch wenn beim Erstellen einzelner Ressourcen Schätzwerte für Monatspreise geliefert werden, verliert man jedoch schon nach den ersten Services schnell den Überblick.


Posted

in

by

jk233

Comments

Leave a Reply