
Eine flexible Spielwiese für Android-CTF-Challenges.
<h1 align="center">
<br>
<img src="https://assets.kitploit.com/production/public/readmes/7301/75c22abcf52c94c756ce37d77db74df73c48b6846c3aede4c8971c38e2180f65.png" alt= "droidground" width="200px">
</h1>
<p align="center">
<b>DroidGround</b>
<p>
<p align="center">
<a href="https://github.com/SECFORCE/droidground/blob/main/README.md"><img src="https://img.shields.io/badge/Documentation-complete-green.svg?style=flat"></a>
<a href="https://github.com/SECFORCE/droidground/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-GPL3-blue.svg"></a>
<a href="https://blackhat.com/eu-25/arsenal/schedule/index.html#droidground-a-flexible-playground-for-android-ctf-challenges-47803"><img src="https://raw.githubusercontent.com/secforce/droidground/HEAD/docs/blackhat-2025.svg"></a>
<br />
<a href="https://droidground.com" target="_blank">Website</a> |
<a href="https://droidground.com/demo" target="_blank">Demo</a>
</p>
In traditionellen **CTF-Challenges** ist es üblich, Flags in Dateien auf einem System zu verstecken, sodass Angreifer Schwachstellen ausnutzen müssen, um sie abzurufen. In der Android-Welt funktioniert dieser Ansatz jedoch nicht gut. APK-Dateien sind leicht herunterladbar und reversibel, sodass **das Platzieren einer Flag auf dem Gerät sie normalerweise trivial extrahierbar macht** – mittels statischer Analyse oder Emulator-Tricks. Dies schränkt die Möglichkeit, realistische, laufzeitfokussierte Challenges zu erstellen, stark ein.
_DroidGround_ wurde entwickelt, um dieses Problem zu lösen.
Es ist eine maßgeschneiderte Plattform zum Hosten von Android-Mobile-Hacking-Challenges in einer **kontrollierten** und **realistischen** Umgebung, in der **Angreifer gerade genug eingeschränkt werden**, um die Challenges auf die vorgesehene Weise lösen zu müssen.
Wichtig ist, dass Teilnehmer **in der App-Umgebung eingesperrt** sein können. Die Modularität des Tools ermöglicht es festzulegen, ob der Benutzer eine Shell starten, beliebige Dateien lesen oder Tools sideloaden kann oder nicht. Alles kann so eingerichtet werden, dass der einzige Weg, die Flag abzurufen, darin besteht, die App selbst zu verstehen und auszunutzen.
## 📋 Inhaltsverzeichnis
- [🧭 Überblick](#-überblick)
- [✨ Funktionen](#-funktionen)
- [📸 Screenshots](#-screenshots)
- [⚙️ Konfiguration](#️-konfiguration)
- [🧩 Anwendungsfälle](#-anwendungsfälle)
- [⚙️ Verwendung](#️-verwendung)
- [💡 Tipps](#-tipps)
- [🛠 Entwicklung](#-entwicklung)
- [🤝 Mitwirken](#-mitwirken)
- [📚 Danksagungen](#-danksagungen)
- [🪪 Lizenz](#-lizenz)
## 🧭 Überblick
_DroidGround_ ermöglicht eine Vielzahl von _Android_-Challenges, die in traditionellen CTF-Setups sonst schwer umzusetzen sind. In einer Remote-Code-Execution-(RCE-)Challenge erhalten Spieler beispielsweise möglicherweise eine APK zur lokalen Analyse. Nachdem sie eine Schwachstelle entdeckt haben, können sie ein Frida-Skript entwickeln und es über DroidGround auf dem echten Zielgerät ausführen, um die Flag aus dem internen Speicher zu extrahieren. Andere Challenge-Typen können versteckte Activities, benutzerdefinierte Broadcast-Intents, Service-Ausnutzung oder dynamische Analyse mit vorinstallierten Tools umfassen.
Mit Echtzeit-Gerätestreaming, feingranularer Kontrolle über Funktionen, Frida-Integration sowie anpassbaren Setup- und Reset-Skripten ermöglicht DroidGround CTF-Organisatoren, sichere, flexible und realistische Android-Challenges zu erstellen, die weit über das hinausgehen, was typischerweise möglich ist.
## ✨ Funktionen
DroidGround bietet eine umfangreiche Sammlung servergesteuerter Funktionen.
- **Echtzeit-Gerätebildschirm** (über `scrcpy`), mit optionaler Maus-, Touch- und Tastatursteuerung
- **Challenge-Status zurücksetzen**
- **App neu starten / Activity starten / Service starten**
- **Broadcast-Intent senden**
- **Gerät herunterfahren / neu starten**
- **Bugreport herunterladen (bugreportz)**
- **Frida-Scripting**
- Aus vorgeladener Bibliothek ausführen (Jailed-Modus)
- Beliebige Skripte ausführen (Full-Modus)
- **Dateibrowser**
- **Terminalzugriff**
- **APK-Verwaltung**
- **Logcat-Viewer**
- **Exploit-Server** (falls Team-Modus aktiviert ist)
Nahezu alle Funktionen sind **modular** und werden über Umgebungsvariablen definiert, was eine präzise Kontrolle über den Challenge-Umfang gewährleistet.
## 📸 Screenshots
|  |  |
| ------------------------------------------------------ | ----------------------------------------------------- |
| Überblick | Activity starten |
|  |  |
| Frida Jailed-Modus | Frida Full-Modus |
|  |  |
| Dateibrowser | App-Manager |
|  |  |
| Terminal | Logs |
## ⚙️ Konfiguration
Die Datei `.env.sample` im Stammverzeichnis ist ein guter Ausgangspunkt. Dies ist die vollständige Liste aller derzeit unterstützten Umgebungsvariablen:
| Variable | Beschreibung | Standard |
| ------------------------------------- | --------------------------------------------------------------------------------- | ----------- |
| `DROIDGROUND_BASE_PATH` | Pfad der Webapp (nützlich für Hosting auf Unterpfaden) | - |
| `DROIDGROUND_APP_PACKAGE_NAME` | Paketname der Ziel-App | - |
| `DROIDGROUND_ADB_HOST` | ADB-Host | `localhost` |
| `DROIDGROUND_ADB_PORT` | ADB-Port | `5037` |
| `DROIDGROUND_ADB_SERIAL` | Optionale ADB-Geräteseriennummer zum Verbinden | - |
| `DROIDGROUND_DEVICE_TYPE` | `usb` oder `network` | `usb` |
| `DROIDGROUND_DEVICE_HOST` | IP des Android-Geräts (`adb`) (nur Netzwerkmodus) | - |
| `DROIDGROUND_DEVICE_PORT` | Port des Android-Geräts (`adb`) (nur Netzwerkmodus) | - |
| `DROIDGROUND_INIT_SCRIPTS_FOLDER` | Ordner mit `setup.sh` und `reset.sh` | `/init.d` |
| `DROIDGROUND_HOST` | Bind-Adresse | `0.0.0.0` |
| `DROIDGROUND_PORT` | Bind-Port | `4242` |
| `DROIDGROUND_RESTART_APP_DISABLED` | App-Neustart deaktivieren | `false` |
| `DROIDGROUND_APP_MANAGER_DISABLED` | App-Manager deaktivieren | `false` |
| `DROIDGROUND_BUG_REPORT_DISABLED` | Bugreport deaktivieren | `false` |
| `DROIDGROUND_FILE_BROWSER_DISABLED` | Dateibrowser deaktivieren | `false` |
| `DROIDGROUND_FRIDA_DISABLED` | Frida-Unterstützung deaktivieren | `false` |
| `DROIDGROUND_FRIDA_TYPE` | `jail` oder `full` | `jail` |
| `DROIDGROUND_FRIDA_INJECTION` | `server` oder `gadget` | `server` |
| `DROIDGROUND_LOGCAT_DISABLED` | Logcat deaktivieren | `false` |
| `DROIDGROUND_REBOOT_ENABLED` | Neustart aktivieren | `false` |
| `DROIDGROUND_SHUTDOWN_ENABLED` | Herunterfahren aktivieren | `false` |
| `DROIDGROUND_START_ACTIVITY_DISABLED` | startActivity deaktivieren | `false` |
| `DROIDGROUND_START_RECEIVER_DISABLED` | Broadcast deaktivieren | `false` |
| `DROIDGROUND_START_SERVICE_DISABLED` | startService deaktivieren | `false` |
| `DROIDGROUND_TERMINAL_DISABLED` | Terminal deaktivieren | `false` |
| `DROIDGROUND_RESET_DISABLED` | Zurücksetzen deaktivieren | `false` |
| `DROIDGROUND_SCRCPY_CONTROL_ENABLED` | Maus-, Touch- und Tastatureingabe über den Gerätebildschirm aktivieren | `false` |
| `DROIDGROUND_SCRCPY_MAX_SIZE` | Maximale Videoabmessung in Pixeln; `0` behält die volle Geräteauflösung bei | `1280` |
| `DROIDGROUND_SCRCPY_MAX_FPS` | Maximale Video-Bildrate; `0` lässt sie unbegrenzt | `60` |
| `DROIDGROUND_SCRCPY_VIDEO_BIT_RATE` | Video-Bitrate in Bits pro Sekunde | `4000000` |
| `DROIDGROUND_EXPLOIT_APP_DURATION` | Die Zeit (in Sekunden), die die Exploit-App aktiv sein wird | `10` |
| `DROIDGROUND_EXPLOIT_APP_MAX_SIZE` | Die maximale Größe (in MB) der Exploit-App | `50` |
| `DROIDGROUND_NUM_TEAMS` | Die Anzahl der gleichzeitig spielenden Teams | - |
| `DROIDGROUND_TEAM_TOKEN_<N>` | Das Token für das n-te Team. Wird automatisch generiert, falls nicht vorhanden | - |
| `DROIDGROUND_IP_STATIC` | Die anzuzeigende statische IP-Adresse. Hat Vorrang vor `DROIDGROUND_IP_IFACE` | - |
| `DROIDGROUND_IP_IFACE` | Die Netzwerkschnittstelle für die angezeigte IP-Adresse | - |
| `DROIDGROUND_LOGO_LINK` | Optionaler Klick-Link für das Logo (z. B. Ihre CTF-Hauptseite) | - |
Setzen Sie `DROIDGROUND_SCRCPY_CONTROL_ENABLED=true` und starten Sie DroidGround neu, um den Gerätebildschirm interaktiv zu machen. Klicken oder tippen Sie auf den Bildschirm, um ihn zu fokussieren, und klicken, ziehen, wischen Sie dann, verwenden Sie mehrere Berührungspunkte, scrollen Sie mit dem Mausrad oder geben Sie Text ein. Rechtsklick oder Escape löst Android Zurück aus. Tab und Shift+Tab bewegen den Fokus aus dem Bildschirm heraus. Die Eingabe wird von allen, die das Gerät ansehen, geteilt, auch im Team-Modus. Der Standard bleibt ein schreibgeschützter Bildschirm. Die Texteingabe verwendet scrcpys Android-Tastatureingabe, sodass die Zeichenunterstützung von der Tastaturzuordnung des Geräts abhängt.
Die Variable `DROIDGROUND_IP_IFACE` sucht zuerst nach einer exakten Übereinstimmung und greift andernfalls auf die erste Schnittstelle zurück, die _mit_ dem angegebenen Wert _beginnt_, da Docker innerhalb des Containers nur die Angabe des Netzwerkschnittstellen-**Präfixes** erlaubt.
Das Screen-Streaming verwendet standardmäßig eine maximale Abmessung von 1280 Pixeln, bis zu 60 fps und 4 Mbps, um Encoding-, Netzwerk- und Browser-Aufwand zu reduzieren. Dies tauscht etwas Feindetail gegen Reaktionsfähigkeit in der eingebetteten Geräteansicht ein. Setzen Sie `DROIDGROUND_SCRCPY_MAX_SIZE=0` und `DROIDGROUND_SCRCPY_VIDEO_BIT_RATE=10000000`, um die vorherigen Qualitätseinstellungen mit voller Auflösung wiederherzustellen. Für langsamere Verbindungen oder Browser versuchen Sie eine maximale Größe von `1024`, `30` fps und `2000000` Bits pro Sekunde. Starten Sie DroidGround nach dem Ändern dieser Einstellungen neu.
Der Browser verwendet WebCodecs, wenn verfügbar, und greift andernfalls auf den Software-H.264-Decoder zurück. WebCodecs erfordert einen sicheren Kontext: Verwenden Sie HTTPS für Remote-Bereitstellungen (localhost funktioniert ebenfalls). Reines HTTP auf einer Remote-IP oder einem Hostnamen verwendet Software-Decodierung. Langsame Betrachter springen zu einem frischen Keyframe, anstatt einen Video-Rückstand anzusammeln. Wenn innerhalb von 1,5 Sekunden kein Keyframe eintrifft, fordert DroidGround eine Videoaktualisierung an; dies unterstützt Encoder wie ReDroids `OMX.google.h264.encoder`, dessen periodische I-Frames nicht unbedingt unabhängig dekodierbare IDR-Frames sind. Aktualisierungsanfragen werden von allen Betrachtern geteilt und können den Bildschirm für alle kurz aktualisieren. Der Server unterhält einen internen scrcpy-Steuerkanal für Videoaktualisierungen; Maus-, Touch- und Tastatureingabe sowie automatisches Aufwecken des Bildschirms bleiben durch `DROIDGROUND_SCRCPY_CONTROL_ENABLED` gesteuert. Siehe die [WebCodecs-Spezifikation](https://www.w3.org/TR/webcodecs/#videodecoder-interface) und die [scrcpy-Videodokumentation](https://github.com/Genymobile/scrcpy/blob/master/doc/video.md) für die zugrunde liegenden Browser- und Videoeinstellungen.
Die Verwendung der Variable `DROIDGROUND_NUM_TEAMS` ändert das Verhalten der Anwendung unter der Haube geringfügig. Wenn diese Option gesetzt ist:
1. Wird die Exploit-Server-Funktion aktiviert, sodass jedes Team über sein **_Team-Token_** seinen eigenen (sehr einfachen) Exploit-Server verwenden kann.
2. Wird das Team-Token **erforderlich**, um Exploit-Apps zu installieren und auszuführen. Jede installierte App wird an ein Team gebunden, und andere Teams können sie nicht ausführen.
Dies ermöglicht es, dieselbe DroidGround-Instanz mit mehreren Teams in Challenges zu teilen, bei denen die Flag über eine Netzwerkanfrage exfiltriert werden kann. Dies **reduziert die Bereitstellungskosten von DroidGround für CTF-Wettbewerbe massiv**.
Wenn der Wert auf `-1` gesetzt wird, aktiviert dies außerdem den sogenannten **Unlimited Teams**-Modus. In diesem Modus ist auf der Seite _Überblick_ eine Schaltfläche zum Generieren eines neuen **_Team-Tokens_** verfügbar. Alle `DROIDGROUND_TEAM_TOKEN_<N>`-Variablen werden ignoriert, wenn dieser Modus aktiviert ist.
## 🧩 Anwendungsfälle
Hier sind einige Möglichkeiten, wie DroidGround verwendet werden kann:
1. **Versteckte Activity**: Finden und starten Sie eine nicht exponierte Activity, um die Flag zu sehen (die App des Spielers enthält eine Dummy-Flag).
2. **RCE**: Die App ist anfällig für RCE und die Flag ist auf dem Gerät gespeichert.
3. **Frida-Instrumentierung**: Überladen Sie eine Methode und extrahieren Sie die Flag mit einem Skript aus dem privaten Speicher.
## ⚙️ Verwendung
Ein paar Beispiel-_Docker-Compose_-Dateien sind im Ordner [examples](https://github.com/secforce/droidground/blob/main/examples/apps) enthalten. Sie verwenden Apps aus dem [DroidGround-Samples-Repo](https://github.com/SECFORCE/droidground-samples), das schrittweise erweitert wird, um alle wichtigen Funktionen zu präsentieren. Sie sind auch ein guter Ausgangspunkt, um zu verstehen, wie Sie Ihr eigenes CTF einrichten.
Beim Start führt _DroidGround_ Folgendes aus:
1. Die Verbindung mit `adb` einrichten
2. Das `setup.sh` im durch `DROIDGROUND_INIT_SCRIPTS_FOLDER` angegebenen Ordner ausführen, falls vorhanden. Dieses Skript kann verwendet werden, um die Ziel-App zu installieren und alles andere zu tun, was zum Initialisieren des CTF erforderlich ist (z. B. Platzieren der Flag an einem bekannten Ort)
3. (falls _Frida_ aktiviert ist) Den korrekten `frida-server` basierend auf der installierten Version und der Architektur des Geräts herunterladen und starten
4. Die Ziel-App ausführen (die durch `DROIDGROUND_APP_PACKAGE_NAME` angegebene). Wenn die App nicht installiert ist, wird _DroidGround_ beendet.
5. Die _REST-APIs_, die _WebSocket_-Server und das Display-Streaming einrichten
Hier ist ein Beispiel-`setup.sh`-Skript:
```sh
#!/usr/bin/env bash
adb shell pm uninstall com.example.app # To do some cleanup
echo "Sleep for 2 seconds before installing app"
sleep 2
echo "Installing app..."
adb install ./flag.apk # The cwd is set to the "init.d" folder, so the apk file can be accessed with the relative path
echo "Install command executed"
```
Für eine Produktionsbereitstellung (in einem echten CTF) möchten Sie möglicherweise vorab eine vordefinierte Anzahl von DroidGround-Instanzen bereitstellen oder den Benutzern erlauben, Instanzen zu starten (mit einer Begrenzung oder vielleicht jedes Team/jeden Benutzer einer bestimmten Instanz zuordnen). Aus diesem Grund haben wir auch ein einfaches [Spawner-Beispiel](https://github.com/secforce/droidground/blob/main/examples/spawner) hinzugefügt.
Alternativ können Sie, wie bereits erwähnt, eine Challenge erstellen, bei der die Flag über eine Netzwerkanfrage exfiltriert werden kann, und die Umgebungsvariable `DROIDGROUND_NUM_TEAMS` nutzen, um das Starten mehrerer Instanzen (was teuer sein könnte) zu vermeiden. Der Ordner [net-multi-step](https://github.com/secforce/droidground/blob/main/examples/apps/net-multi-step) bietet ein gutes Beispiel dafür, wie solche Challenges bereitgestellt werden können.
## 💡 Tipps
Hier sind einige Vorschläge für die Einrichtung Ihres Android-CTF:
- Seien Sie vorsichtig beim Aktivieren des **Frida Full-Modus**; der Spieler hat dann die vollständige Kontrolle über das Gerät (deshalb haben wir den **Frida Jail-Modus** entwickelt, wie in [Frida Library](https://github.com/secforce/droidground/blob/main/library) beschrieben).
- Seien Sie vorsichtig beim Aktivieren des **Terminals**; der Spieler hat dann die vollständige Kontrolle über das Gerät.
- Seien Sie vorsichtig beim Aktivieren der **Shutdown**-Funktion.
- Wenn Sie planen, die Flag direkt in der UI sichtbar zu machen, möchten Sie möglicherweise einen Weg finden, verschiedene Instanzen zu starten (eine für jedes Team/jeden Spieler)
Beim Testen des Setups vor dem Produktivbetrieb könnte es nützlich sein, die **Angriffsfläche** der Ziel-App zu ermitteln. Dies ist etwas, das Spieler nicht sehen sollten, da es ihre Aufgabe ist, die Angriffsfläche zu entdecken und zu analysieren!
Daher wird ein `GET`-Endpunkt unter `/attackSurface` bereitgestellt, der mit einem Token geschützt ist (das als Wert des `Authorization`-Headers verwendet werden muss), das beim Start zufällig generiert und in den Logs ausgegeben wird (daher nur für Systemadministratoren zugänglich).
Wenn Sie Ihre eigenen Frida-Skripte im Jailed-Modus verwenden möchten, müssen Sie lediglich den Ordner, der sie enthält, in den Docker-Container bind-mounten:
```yaml
volumes:
- <Frida library folder>:/droidground/library
```
Eine `library.json`-Datei (wie die in [library](https://github.com/secforce/droidground/blob/main/library/library.json)) ist erforderlich, um die Anwendung über die Liste der verfügbaren Skripte zu informieren.
## 🛠 Entwicklung
Es sollte nicht allzu schwierig sein, es zum Laufen zu bringen, aber bevor Sie beginnen, sollten Sie die folgenden Tools installiert haben:
- `frida` (nur wenn Sie _Frida_ aktivieren)
- `node` (es ist eine Node-App, Sie müssen es haben!)
- `adb` (nun ja, wir verlassen uns darauf, um mit dem Gerät zu kommunizieren)
- _JDK_ (Sie benötigen es, um die Companion-App zu bauen)
Danach können Sie einfach Folgendes ausführen:
```sh
git clone https://github.com/SECFORCE/droidground.git
cd droidground
# Install without running scripts
npm install --ignore-scripts
# Rebuild frida to get the bindings
npm rebuild frida
# Build companion app
npm run companion
# Get scrcpy
npm run scrcpy
```
Danach müssen Sie nur noch die **env**-Variablen setzen und dann `npm run dev` ausführen, und schon kann es losgehen. Viel Spaß im Dev-Modus!
## 🤝 Mitwirken
Pull Requests sind willkommen! Bitte eröffnen Sie zuerst ein Issue, um größere Änderungen zu besprechen. Ideen für neue CTF-Workflows oder Challenge-Typen sind besonders willkommen.
## 📚 Danksagungen
Entwickelt von [Angelo Delicato](https://github.com/thelicato) [@SECFORCE](https://www.secforce.com).
Der _Server_-Abschnitt stützt sich stark auf die großartige Arbeit von [@yume-chan](https://github.com/yume-chan/ya-webadb); ohne seine großartige Arbeit würde diese App wahrscheinlich nicht existieren.
Die _Companion_-App basiert stark auf dem [aya server](https://github.com/liriliri/aya/tree/master/server), der auf die gleiche Weise funktioniert wie der [scrcpy server](https://github.com/Genymobile/scrcpy). Weitere Details finden Sie im spezifischen [README](https://github.com/secforce/droidground/blob/main/companion/README.md).
## 🪪 Lizenz
_DroidGround_ wird unter der [GPL-3.0 LICENSE](https://github.com/SECFORCE/droidground/blob/main/LICENSE) veröffentlicht.