
Un parco giochi flessibile per le sfide CTF su Android.
<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">Sito web</a> |
<a href="https://droidground.com/demo" target="_blank">Demo</a>
</p>
Nelle tradizionali **sfide CTF**, è comune nascondere le flag in file sul sistema, richiedendo agli attaccanti di sfruttare vulnerabilità per recuperarle. Tuttavia, nel mondo Android, questo approccio non funziona bene. I file APK sono facilmente scaricabili e reversibili, quindi **inserire una flag sul dispositivo la rende solitamente banale** da estrarre tramite analisi statica o trucchi con l'emulatore. Questo limita severamente la capacità di creare sfide realistiche e focalizzate sul runtime.
_DroidGround_ è progettato per risolvere questo problema.
È una piattaforma realizzata su misura per ospitare sfide di hacking mobile Android in un ambiente **controllato** e **realistico**, in cui **gli attaccanti sono vincolati quanto basta** per richiedere la risoluzione delle sfide nel modo previsto.
È importante notare che i partecipanti possono essere **isolati all'interno dell'ambiente dell'app**. La modularità dello strumento consente di stabilire se l'utente può o non può avviare una shell, leggere file arbitrari o caricare strumenti tramite sideload. Tutto può essere configurato in modo che l'unico modo per recuperare la flag sia comprendere e sfruttare l'app stessa.
## 📋 Indice
- [🧭 Panoramica](#-overview)
- [✨ Funzionalità](#-features)
- [📸 Screenshot](#-screenshots)
- [⚙️ Configurazione](#️-configuration)
- [🧩 Casi d'uso](#-use-cases)
- [⚙️ Utilizzo](#️-usage)
- [💡 Suggerimenti](#-tips)
- [🛠 Sviluppo](#-development)
- [🤝 Contribuire](#-contributing)
- [📚 Crediti](#-credits)
- [🪪 Licenza](#-license)
## 🧭 Panoramica
_DroidGround_ abilita un'ampia varietà di sfide _Android_ che altrimenti sarebbero difficili da implementare nelle configurazioni CTF tradizionali. Ad esempio, in una sfida di esecuzione di codice remoto (RCE), i giocatori potrebbero ricevere un APK per l'analisi locale. Dopo aver scoperto una vulnerabilità, possono sviluppare uno script Frida ed eseguirlo tramite DroidGround sul dispositivo di destinazione reale per estrarre la flag dall'archivio interno. Altri tipi di sfida possono coinvolgere activity nascoste, intent broadcast personalizzati, sfruttamento di servizi o analisi dinamica utilizzando strumenti precaricati.
Con lo streaming del dispositivo in tempo reale, il controllo granulare delle funzionalità, l'integrazione con Frida e script di configurazione e reset personalizzabili, DroidGround consente agli organizzatori di CTF di creare sfide Android sicure, flessibili e realistiche che vanno ben oltre ciò che è tipicamente possibile.
## ✨ Funzionalità
DroidGround offre un ricco set di funzionalità controllate dal server.
- **Schermo del dispositivo in tempo reale** (tramite `scrcpy`), con controllo opzionale di mouse, touch e tastiera
- **Ripristino dello stato della sfida**
- **Riavvio dell'app / Avvio activity / Avvio servizio**
- **Invio di intent broadcast**
- **Spegnimento / Riavvio del dispositivo**
- **Download del bugreport (bugreportz)**
- **Scripting Frida**
- Esecuzione da libreria precaricata (modalità isolata)
- Esecuzione di script arbitrari (modalità completa)
- **Browser dei file**
- **Accesso al terminale**
- **Gestione APK**
- **Visualizzatore Logcat**
- **Server di exploit** (se la modalità team è abilitata)
Quasi tutte le funzionalità sono **modulari** e definite tramite variabili d'ambiente, garantendo un controllo preciso sull'ambito della sfida.
## 📸 Screenshot
|  |  |
| ------------------------------------------------------ | ----------------------------------------------------- |
| Panoramica | Avvia Activity |
|  |  |
| Modalità Frida Jailed | Modalità Frida Full |
|  |  |
| Browser File | Gestione App |
|  |  |
| Terminale | Log |
## ⚙️ Configurazione
Il file `.env.sample` nella directory principale è un buon punto di partenza. Di seguito è riportato l'elenco completo di tutte le variabili d'ambiente attualmente supportate:
| Variabile | Descrizione | Predefinito |
| ------------------------------------- | --------------------------------------------------------------------------------- | ----------- |
| `DROIDGROUND_BASE_PATH` | Percorso della webapp (utile per l'hosting su sottopercorsi) | - |
| `DROIDGROUND_APP_PACKAGE_NAME` | Nome del pacchetto dell'app di destinazione | - |
| `DROIDGROUND_ADB_HOST` | Host ADB | `localhost` |
| `DROIDGROUND_ADB_PORT` | Porta ADB | `5037` |
| `DROIDGROUND_ADB_SERIAL` | Seriale del dispositivo ADB opzionale a cui connettersi | - |
| `DROIDGROUND_DEVICE_TYPE` | `usb` o `network` | `usb` |
| `DROIDGROUND_DEVICE_HOST` | IP del dispositivo Android (`adb`) (solo modalità network) | - |
| `DROIDGROUND_DEVICE_PORT` | porta del dispositivo Android (`adb`) (solo modalità network) | - |
| `DROIDGROUND_INIT_SCRIPTS_FOLDER` | Cartella contenente `setup.sh` e `reset.sh` | `/init.d` |
| `DROIDGROUND_HOST` | Indirizzo di bind | `0.0.0.0` |
| `DROIDGROUND_PORT` | Porta di bind | `4242` |
| `DROIDGROUND_RESTART_APP_DISABLED` | Disabilita il riavvio dell'app | `false` |
| `DROIDGROUND_APP_MANAGER_DISABLED` | Disabilita l'app manager | `false` |
| `DROIDGROUND_BUG_REPORT_DISABLED` | Disabilita il bugreport | `false` |
| `DROIDGROUND_FILE_BROWSER_DISABLED` | Disabilita il file browser | `false` |
| `DROIDGROUND_FRIDA_DISABLED` | Disabilita il supporto Frida | `false` |
| `DROIDGROUND_FRIDA_TYPE` | `jail` o `full` | `jail` |
| `DROIDGROUND_FRIDA_INJECTION` | `server` o `gadget` | `server` |
| `DROIDGROUND_LOGCAT_DISABLED` | Disabilita logcat | `false` |
| `DROIDGROUND_REBOOT_ENABLED` | Abilita il riavvio | `false` |
| `DROIDGROUND_SHUTDOWN_ENABLED` | Abilita lo spegnimento | `false` |
| `DROIDGROUND_START_ACTIVITY_DISABLED` | Disabilita startActivity | `false` |
| `DROIDGROUND_START_RECEIVER_DISABLED` | Disabilita broadcast | `false` |
| `DROIDGROUND_START_SERVICE_DISABLED` | Disabilita startService | `false` |
| `DROIDGROUND_TERMINAL_DISABLED` | Disabilita il terminale | `false` |
| `DROIDGROUND_RESET_DISABLED` | Disabilita il reset | `false` |
| `DROIDGROUND_SCRCPY_CONTROL_ENABLED` | Abilita l'input da mouse, touch e tastiera tramite lo schermo del dispositivo | `false` |
| `DROIDGROUND_SCRCPY_MAX_SIZE` | Dimensione massima del video in pixel; `0` mantiene la risoluzione completa del dispositivo | `1280` |
| `DROIDGROUND_SCRCPY_MAX_FPS` | Frame rate massimo del video; `0` lo lascia senza limiti | `60` |
| `DROIDGROUND_SCRCPY_VIDEO_BIT_RATE` | Bitrate video in bit al secondo | `4000000` |
| `DROIDGROUND_EXPLOIT_APP_DURATION` | Il tempo (in secondi) durante il quale l'app exploit sarà attiva | `10` |
| `DROIDGROUND_EXPLOIT_APP_MAX_SIZE` | La dimensione massima (in MB) dell'app exploit | `50` |
| `DROIDGROUND_NUM_TEAMS` | Il numero di team che giocano contemporaneamente | - |
| `DROIDGROUND_TEAM_TOKEN_<N>` | Il token per l'n-esimo team. Generato automaticamente se mancante | - |
| `DROIDGROUND_IP_STATIC` | L'indirizzo IP statico da visualizzare. Ha la precedenza su `DROIDGROUND_IP_IFACE` | - |
| `DROIDGROUND_IP_IFACE` | L'interfaccia di rete per l'indirizzo IP visualizzato | - |
| `DROIDGROUND_LOGO_LINK` | Imposta facoltativamente il link cliccabile del logo (ad es., la pagina principale della tua CTF) | - |
Imposta `DROIDGROUND_SCRCPY_CONTROL_ENABLED=true` e riavvia DroidGround per rendere interattivo lo schermo del dispositivo. Fai clic o tocca lo schermo per metterlo a fuoco, quindi fai clic, trascina, scorri, usa più punti di contatto, scorri con la rotellina del mouse o digita. Fai clic con il tasto destro o premi Escape per il tasto Indietro di Android. Tab e Shift+Tab spostano il focus fuori dallo schermo. L'input è condiviso da tutti coloro che visualizzano il dispositivo; durante un'esecuzione di exploit di una squadra, solo i visualizzatori autenticati come quella squadra possono visualizzarlo o controllarlo. L'impostazione predefinita rimane uno schermo in sola visualizzazione. L'input di testo utilizza l'iniezione dei tasti di Android di scrcpy, quindi il supporto dei caratteri dipende dalla mappatura della tastiera del dispositivo.
`DROIDGROUND_IP_IFACE` cerca prima una corrispondenza esatta e, in caso contrario, ripiega sulla prima interfaccia che _inizia con_ il valore fornito, poiché Docker consente di specificare solo il **prefisso** dell'interfaccia di rete all'interno del container.
Lo streaming dello schermo utilizza per impostazione predefinita una dimensione massima di 1280 pixel, fino a 60 fps e 4 Mbps per ridurre il carico di codifica, rete e browser. Questo sacrifica un po' di dettaglio fine in favore della reattività nella vista incorporata del dispositivo. Imposta `DROIDGROUND_SCRCPY_MAX_SIZE=0` e `DROIDGROUND_SCRCPY_VIDEO_BIT_RATE=10000000` per ripristinare le precedenti impostazioni di qualità a risoluzione completa. Per connessioni o browser più lenti, prova una dimensione massima di `1024`, `30` fps e `2000000` bit al secondo. Riavvia DroidGround dopo aver modificato queste impostazioni.
Il browser utilizza WebCodecs quando disponibile e, in caso contrario, ripiega sul decoder H.264 software. WebCodecs richiede un contesto sicuro: usa HTTPS per i deployment remoti (anche localhost funziona). HTTP semplice su un IP o hostname remoto utilizza la decodifica software. I visualizzatori lenti saltano a un nuovo keyframe invece di accumulare un arretrato video. Se non arriva alcun keyframe entro 1,5 secondi, DroidGround richiede un aggiornamento video; questo supporta encoder come `OMX.google.h264.encoder` di ReDroid, i cui I-frame periodici non sono necessariamente frame IDR decodificabili in modo indipendente. Le richieste di aggiornamento sono condivise tra i visualizzatori e possono aggiornare brevemente lo schermo per tutti. Il server mantiene un canale di controllo scrcpy interno per gli aggiornamenti video; input di mouse, touch e tastiera e il risveglio automatico dello schermo restano vincolati a `DROIDGROUND_SCRCPY_CONTROL_ENABLED`. Consulta la [specifica WebCodecs](https://www.w3.org/TR/webcodecs/#videodecoder-interface) e la [documentazione video di scrcpy](https://github.com/Genymobile/scrcpy/blob/master/doc/video.md) per le impostazioni sottostanti del browser e del video.
L'utilizzo della variabile `DROIDGROUND_NUM_TEAMS` modifica leggermente il comportamento dell'applicazione sotto il cofano. Se questa opzione è impostata:
1. La funzionalità del server di exploit è abilitata, consentendo a ciascuna squadra di utilizzare il proprio (molto semplice) server di exploit tramite il proprio **_team token_**.
2. Il team token sarà **necessario** per installare ed eseguire le app di exploit. Ogni app installata sarà associata a una squadra e le altre squadre non potranno eseguirla.
3. Mentre l'app di exploit di una squadra è in esecuzione, le altre squadre e i visualizzatori senza token vedono un display nero che spiega che è in esecuzione l'exploit di un'altra squadra. Il server trattiene il video e rifiuta il loro input sul dispositivo. Il display condiviso riprende dopo il riavvio dell'app di destinazione. Inserisci il tuo token in **Team token for display** sotto il dispositivo per guardare le esecuzioni della tua squadra; avviare un exploit dall'interfaccia autentica automaticamente anche il display di quel browser. I token vengono inviati tramite WebSocket anziché nel suo URL e sono mantenuti in memoria per la pagina corrente. Questo vale anche in modalità Unlimited Teams. Senza la modalità team, il display rimane condiviso.
Ciò consente di condividere la stessa istanza di DroidGround con più squadre in challenge in cui la flag può essere esfiltrata tramite una richiesta di rete. Questo **riduce enormemente i costi di deployment di DroidGround** per le competizioni CTF.
Inoltre, se il valore è impostato a `-1` verrà abilitata la cosiddetta modalità **Unlimited Teams**. In questa modalità sarà disponibile un pulsante per generare un nuovo **_team token_** nella pagina _Overview_. Tutte le variabili `DROIDGROUND_TEAM_TOKEN_<N>` vengono ignorate se questa modalità è abilitata.
## 🧩 Casi d'uso
Ecco alcuni modi in cui DroidGround può essere utilizzato:
1. **Attività nascosta**: trova e avvia un'attività non esposta per vedere il flag (l'app del giocatore contiene un flag fittizio).
2. **RCE**: l'app è vulnerabile a RCE e il flag è memorizzato sul dispositivo.
3. **Strumentazione Frida**: sovraccarica un metodo ed estrai il flag dalla memoria privata usando uno script.
## ⚙️ Utilizzo
Nella cartella [examples](https://github.com/secforce/droidground/blob/main/examples/apps) sono forniti un paio di file _Docker Compose_ di esempio. Utilizzano app provenienti dal [repository dei campioni DroidGround](https://github.com/SECFORCE/droidground-samples), che verrà progressivamente arricchito per mostrare tutte le funzionalità principali. Sono anche un buon punto di partenza per capire come configurare il proprio CTF.
All'avvio _DroidGround_ esegue le seguenti operazioni:
1. Stabilisce la connessione con `adb`
2. Esegue lo script `setup.sh` nella cartella specificata da `DROIDGROUND_INIT_SCRIPTS_FOLDER`, se presente. Questo script può essere utilizzato per installare l'app di destinazione e fare tutto il resto necessario per inizializzare il CTF (ad es. posizionare il flag in una posizione nota)
3. (se _Frida_ è abilitato) Scarica il `frida-server` corretto in base alla versione installata e all'architettura del dispositivo e lo avvia
4. Avvia l'app di destinazione (quella specificata tramite `DROIDGROUND_APP_PACKAGE_NAME`). Se l'app non è installata, _DroidGround_ terminerà.
5. Configura le _REST API_, i server _WebSocket_ e lo streaming del display
Ecco un esempio di script `setup.sh`:
```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"
```
Per un deploy in produzione (in un CTF reale) potresti voler predisporre in anticipo un numero predefinito di istanze DroidGround oppure potresti voler consentire agli utenti di avviare istanze (con una limitazione o magari associando ogni team/utente a un'istanza specifica). Per questo motivo abbiamo anche aggiunto un semplice [esempio di spawner](https://github.com/secforce/droidground/blob/main/examples/spawner).
In alternativa, come menzionato in precedenza, puoi creare una challenge in cui la flag può essere esfiltrata tramite una richiesta di rete e sfruttare la variabile d'ambiente `DROIDGROUND_NUM_TEAMS` per evitare di avviare più istanze (il che potrebbe essere costoso). La cartella [net-multi-step](https://github.com/secforce/droidground/blob/main/examples/apps/net-multi-step) fornisce un buon esempio su come realizzare questo tipo di challenge.
## 💡 Suggerimenti
Ecco alcuni suggerimenti per configurare il tuo CTF Android:
- Fai attenzione quando abiliti la **Frida Full Mode**, il giocatore avrà il controllo completo del dispositivo (ecco perché abbiamo creato la **Frida Jail Mode** come descritto in [Frida Library](https://github.com/secforce/droidground/blob/main/library)).
- Fai attenzione quando abiliti il **Terminal**, il giocatore avrà il controllo completo del dispositivo.
- Fai attenzione quando abiliti la funzionalità **Shutdown**.
- Se prevedi di rendere la flag direttamente visibile nell'interfaccia utente, potresti voler trovare un modo per avviare istanze diverse (una per ogni team/giocatore)
Durante il test della configurazione prima di andare in produzione potrebbe essere utile ottenere la **superficie d'attacco** dell'app target. Questo è qualcosa che i giocatori non dovrebbero vedere perché fa parte del loro lavoro scoprire e analizzare la superficie d'attacco!
Pertanto, viene fornito un endpoint `GET` raggiungibile su `/attackSurface` e protetto con un token (che deve essere usato come valore dell'header `Authorization`) generato casualmente durante l'avvio e stampato nei log (quindi accessibile solo dai sysadmin).
Se vuoi usare i tuoi script Frida in modalità jailed, devi semplicemente fare un bind-mount della cartella che li contiene nel container Docker:
```yaml
volumes:
- <Frida library folder>:/droidground/library
```
Per istruire l'applicazione sull'elenco degli script disponibili è necessario un file `library.json` (come quello presente in [library](https://github.com/secforce/droidground/blob/main/library/library.json)).
## 🛠 Sviluppo
Metterlo in funzione non dovrebbe essere troppo difficile, ma prima di iniziare dovresti avere installati i seguenti strumenti:
- `frida` (solo se abiliti _Frida_)
- `node` (è un'app Node, devi averlo!)
- `adb` (beh, ci affidiamo a lui per comunicare con il dispositivo)
- _JDK_ (ti serve per compilare l'app companion)
Dopodiché puoi semplicemente eseguire quanto segue:
```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
```
Dopodiché devi solo impostare le variabili **env** e poi eseguire `npm run dev` e sarai pronto a partire. Buon dev mode!
## 🤝 Contribuire
Le pull request sono benvenute! Apri prima una issue per discutere le modifiche principali. Le idee per nuovi workflow CTF o tipi di challenge sono particolarmente apprezzate.
## 📚 Crediti
Sviluppato da [Angelo Delicato](https://github.com/thelicato) [@SECFORCE](https://www.secforce.com).
La sezione _server_ si basa fortemente sullo straordinario lavoro svolto da [@yume-chan](https://github.com/yume-chan/ya-webadb); probabilmente questa app non esisterebbe senza il suo straordinario lavoro.
L'app _companion_ si basa fortemente sul [aya server](https://github.com/liriliri/aya/tree/master/server), che funziona allo stesso modo dello [scrcpy server](https://github.com/Genymobile/scrcpy). Maggiori dettagli sono disponibili nel [README](https://github.com/secforce/droidground/blob/main/companion/README.md) specifico.
## 🪪 Licenza
_DroidGround_ è rilasciato sotto la [GPL-3.0 LICENSE](https://github.com/SECFORCE/droidground/blob/main/LICENSE)