
droidground v1.0.11
Un campo de juegos flexible para desafíos CTF en Android.
DroidGround
En los retos CTF tradicionales, es común ocultar flags en archivos dentro de un sistema, lo que obliga a los atacantes a explotar vulnerabilidades para recuperarlas. Sin embargo, en el mundo de Android, este enfoque no funciona bien. Los archivos APK son fácilmente descargables y reversibles, por lo que colocar una flag en el dispositivo normalmente hace que sea trivial extraerla mediante análisis estático o trucos de emulador. Esto limita severamente la capacidad de crear retos realistas centrados en el tiempo de ejecución.
DroidGround está diseñado para resolver este problema.
Es una plataforma construida a medida para alojar retos de hacking móvil en Android en un entorno controlado y realista, donde los atacantes están limitados lo justo para requerir resolver los retos de la forma prevista.
Es importante destacar que los participantes pueden estar encerrados dentro del entorno de la aplicación. La modularidad de la herramienta permite establecer si el usuario puede o no abrir una shell, leer archivos arbitrarios o instalar herramientas. Todo puede configurarse para que la única forma de recuperar la flag sea comprendiendo y explotando la propia aplicación.
📋 Tabla de Contenidos
- 🧭 Descripción general
- ✨ Características
- 📸 Capturas de pantalla
- ⚙️ Configuración
- 🧩 Casos de uso
- ⚙️ Uso
- 💡 Consejos
- 🛠 Desarrollo
- 🤝 Contribuir
- 📚 Créditos
- 🪪 Licencia
🧭 Descripción general
DroidGround permite una amplia variedad de retos de Android que de otro modo son difíciles de implementar en configuraciones CTF tradicionales. Por ejemplo, en un reto de ejecución remota de código (RCE), los jugadores podrían recibir un APK para su análisis local. Tras descubrir una vulnerabilidad, pueden desarrollar un script de Frida y ejecutarlo a través de DroidGround en el dispositivo objetivo real para extraer la flag del almacenamiento interno. Otros tipos de retos pueden implicar actividades ocultas, intents de broadcast personalizados, explotación de servicios o análisis dinámico usando herramientas precargadas.
Con streaming del dispositivo en tiempo real, control detallado sobre las características, integración con Frida y scripts de configuración y reinicio personalizables, DroidGround permite a los organizadores de CTF construir retos de Android seguros, flexibles y realistas que van mucho más allá de lo que normalmente es posible.
✨ Características
DroidGround proporciona un amplio conjunto de características controladas por el servidor.
- Pantalla del dispositivo en tiempo real (mediante
scrcpy), con control opcional de ratón, táctil y teclado - Restablecer el estado del reto
- Reiniciar app / Iniciar actividad / Iniciar servicio
- Enviar intent de broadcast
- Apagar / Reiniciar dispositivo
- Descargar bugreport (bugreportz)
- Scripting con Frida
- Ejecutar desde biblioteca precargada (modo restringido)
- Ejecutar scripts arbitrarios (modo completo)
- Explorador de archivos
- Acceso a terminal
- Gestión de APK
- Visor de Logcat
- Servidor de exploits (si el modo equipo está habilitado)
Casi todas las características son modulares y se definen mediante variables de entorno, lo que garantiza un control preciso sobre el alcance del reto.
📸 Capturas de pantalla
![]() | ![]() |
|---|---|
| Descripción general | Iniciar actividad |
![]() | ![]() |
| Modo restringido de Frida | Modo completo de Frida |
![]() | ![]() |
| Explorador de archivos | Gestor de apps |
![]() | ![]() |
| Terminal | Logs |
⚙️ Configuración
El archivo .env.sample en el directorio raíz es un buen punto de partida. Esta es la lista completa de todas las variables de entorno soportadas actualmente:
| Variable | Descripción | Por defecto |
|---|---|---|
DROIDGROUND_BASE_PATH | Ruta de la aplicación web (útil para alojar en subrutas) | - |
DROIDGROUND_APP_PACKAGE_NAME | Nombre del paquete de la app objetivo | - |
DROIDGROUND_ADB_HOST | Host de ADB | localhost |
DROIDGROUND_ADB_PORT | Puerto de ADB | 5037 |
DROIDGROUND_ADB_SERIAL | Número de serie opcional del dispositivo ADB al que conectarse | - |
DROIDGROUND_DEVICE_TYPE | usb o network | usb |
DROIDGROUND_DEVICE_HOST | IP del dispositivo Android (adb) (solo modo red) | - |
DROIDGROUND_DEVICE_PORT | Puerto del dispositivo Android (adb) (solo modo red) | - |
DROIDGROUND_INIT_SCRIPTS_FOLDER | Carpeta que contiene setup.sh y reset.sh | /init.d |
DROIDGROUND_HOST | Dirección de enlace | 0.0.0.0 |
DROIDGROUND_PORT | Puerto de enlace | 4242 |
DROIDGROUND_RESTART_APP_DISABLED | Deshabilitar reinicio de la app | false |
DROIDGROUND_APP_MANAGER_DISABLED | Deshabilitar gestor de apps | false |
DROIDGROUND_BUG_REPORT_DISABLED | Deshabilitar bugreport | false |
DROIDGROUND_FILE_BROWSER_DISABLED | Deshabilitar explorador de archivos | false |
DROIDGROUND_FRIDA_DISABLED | Deshabilitar soporte de Frida | false |
DROIDGROUND_FRIDA_TYPE | jail o full | jail |
DROIDGROUND_FRIDA_INJECTION | server o gadget | server |
DROIDGROUND_LOGCAT_DISABLED | Deshabilitar logcat | false |
DROIDGROUND_REBOOT_ENABLED | Habilitar reinicio | false |
DROIDGROUND_SHUTDOWN_ENABLED | Habilitar apagado | false |
DROIDGROUND_START_ACTIVITY_DISABLED | Deshabilitar startActivity | false |
DROIDGROUND_START_RECEIVER_DISABLED | Deshabilitar broadcast | false |
DROIDGROUND_START_SERVICE_DISABLED | Deshabilitar startService | false |
DROIDGROUND_TERMINAL_DISABLED | Deshabilitar terminal | false |
DROIDGROUND_RESET_DISABLED | Deshabilitar reinicio | false |
DROIDGROUND_SCRCPY_CONTROL_ENABLED | Habilitar entrada de ratón, táctil y teclado a través de la pantalla del dispositivo | false |
DROIDGROUND_SCRCPY_MAX_SIZE | Dimensión máxima de vídeo en píxeles; 0 mantiene la resolución completa del dispositivo | 1280 |
DROIDGROUND_SCRCPY_MAX_FPS | Tasa de fotogramas máxima de vídeo; 0 la deja sin límite | 60 |
DROIDGROUND_SCRCPY_VIDEO_BIT_RATE | Bitrate de vídeo en bits por segundo | 4000000 |
DROIDGROUND_EXPLOIT_APP_DURATION | El tiempo (en segundos) que la app de exploit estará activa | 10 |
DROIDGROUND_EXPLOIT_APP_MAX_SIZE | El tamaño máximo (en MB) de la app de exploit | 50 |
DROIDGROUND_NUM_TEAMS | El número de equipos jugando simultáneamente | - |
DROIDGROUND_TEAM_TOKEN_<N> | El token para el enésimo equipo. Se genera automáticamente si falta | - |
DROIDGROUND_IP_STATIC | La dirección IP estática a mostrar. Tiene prioridad sobre DROIDGROUND_IP_IFACE | - |
DROIDGROUND_IP_IFACE | La interfaz de red para la dirección IP mostrada | - |
DROIDGROUND_LOGO_LINK | Establece opcionalmente el enlace al hacer clic en el logo (p. ej., tu página principal del CTF) | - |
Establece DROIDGROUND_SCRCPY_CONTROL_ENABLED=true y reinicia DroidGround para hacer interactiva la pantalla del dispositivo. Haz clic o toca la pantalla para enfocarla, luego haz clic, arrastra, desliza, usa múltiples puntos táctiles, desplázate con la rueda del ratón o escribe. Haz clic derecho o pulsa Escape para el botón Atrás de Android. Tab y Shift+Tab mueven el foco fuera de la pantalla. La entrada es compartida por todos los que visualizan el dispositivo, incluso en modo equipo. El valor por defecto sigue siendo una pantalla de solo visualización. La entrada de texto utiliza la inyección de teclas de Android de scrcpy, por lo que la compatibilidad de caracteres depende del mapeo de teclado del dispositivo.
La variable DROIDGROUND_IP_IFACE busca primero una coincidencia exacta y recurre a la primera interfaz que empiece por el valor proporcionado, ya que Docker solo permite especificar el prefijo de la interfaz de red dentro del contenedor.
El streaming de pantalla usa por defecto una dimensión máxima de 1280 píxeles, hasta 60 fps y 4 Mbps para reducir la carga de codificación, red y navegador. Esto sacrifica algo de detalle fino a cambio de capacidad de respuesta en la vista embebida del dispositivo. Establece DROIDGROUND_SCRCPY_MAX_SIZE=0 y DROIDGROUND_SCRCPY_VIDEO_BIT_RATE=10000000 para restaurar la configuración de calidad a resolución completa anterior. Para conexiones o navegadores más lentos, prueba un tamaño máximo de 1024, 30 fps y 2000000 bits por segundo. Reinicia DroidGround después de cambiar estas configuraciones.
El navegador usa WebCodecs cuando está disponible y recurre al decodificador H.264 por software en caso contrario. WebCodecs requiere un contexto seguro: usa HTTPS para despliegues remotos (localhost también funciona). HTTP simple en una IP o nombre de host remoto usa decodificación por software. Los visores lentos saltan a un fotograma clave nuevo en lugar de acumular un retraso de vídeo; unirse o recuperarse puede tardar aproximadamente un intervalo de fotograma clave (un segundo). Consulta la especificación de WebCodecs y la documentación de vídeo de scrcpy para conocer la configuración subyacente del navegador y del vídeo.
El uso de la variable DROIDGROUND_NUM_TEAMS cambia ligeramente el comportamiento de la aplicación internamente. Si esta opción está establecida:
- La característica del servidor de exploits se habilita, permitiendo a cada equipo usar su propio servidor de exploits (muy simple) mediante su token de equipo.
- El token de equipo será requerido para instalar y ejecutar apps de exploit. Cada app instalada estará vinculada a un equipo y otros equipos no podrán ejecutarla.
Esto permite compartir la misma instancia de DroidGround con múltiples equipos en retos donde la flag puede ser exfiltrada mediante una petición de red. Esto reduce masivamente los costes de despliegue de DroidGround para competiciones CTF.
Además, si el valor se establece en -1, habilitará el llamado modo Equipos Ilimitados. En este modo, un botón para generar un nuevo token de equipo estará disponible en la página Descripción general. Todas las variables DROIDGROUND_TEAM_TOKEN_<N> se ignoran si este modo está habilitado.
🧩 Casos de uso
Aquí hay algunas formas en que se puede usar DroidGround:
- Actividad oculta: Encontrar y lanzar una actividad no expuesta para ver la flag (la app del jugador contiene una flag ficticia).
- RCE: La app es vulnerable a RCE y la flag está almacenada en el dispositivo.
- Instrumentación con Frida: Sobrecargar un método y extraer la flag de la memoria privada usando un script.
⚙️ Uso
Se proporcionan un par de archivos Docker Compose de ejemplo en la carpeta examples. Usan apps del repositorio de ejemplos de DroidGround, que se mejorará progresivamente para mostrar todas las características clave. También son un buen punto de partida para entender cómo configurar tu propio CTF.
Al arrancar, DroidGround hace lo siguiente:
- Establece la conexión con
adb - Ejecuta el
setup.shen la carpeta especificada porDROIDGROUND_INIT_SCRIPTS_FOLDERsi está presente. Este script puede usarse para instalar la app objetivo y hacer todo lo demás que sea necesario para inicializar el CTF (p. ej., colocar la flag en una ubicación conocida) - (si Frida está habilitado) Descarga el
frida-servercorrecto según la versión instalada y la arquitectura del dispositivo y lo inicia - Ejecuta la app objetivo (la especificada mediante
DROIDGROUND_APP_PACKAGE_NAME). Si la app no está instalada, DroidGround saldrá. - Configura las REST APIs, los servidores WebSocket y el streaming de pantalla
Aquí hay un script setup.sh de ejemplo:
#!/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"
Para un despliegue en producción (en un CTF real) quizás quieras aprovisionar un número predefinido de instancias de DroidGround de antemano o quizás quieras permitir a los usuarios crear instancias (con una limitación o tal vez asociar cada equipo/usuario con una instancia específica). Por esta razón también añadimos un sencillo ejemplo de spawner.
Alternativamente, como se mencionó anteriormente, puedes crear un reto donde la flag pueda ser exfiltrada mediante una petición de red y aprovechar la variable de entorno DROIDGROUND_NUM_TEAMS para evitar crear múltiples instancias (lo que podría ser costoso). La carpeta net-multi-step proporciona un buen ejemplo de cómo entregar este tipo de retos.
💡 Consejos
Aquí hay algunas sugerencias para configurar tu CTF de Android:
- Ten cuidado al habilitar el Modo completo de Frida, el jugador tendrá control total sobre el dispositivo (por eso creamos el Modo restringido de Frida como se detalla en Biblioteca de Frida).
- Ten cuidado al habilitar el Terminal, el jugador tendrá control total sobre el dispositivo.
- Ten cuidado al habilitar la característica de Apagado.
- Si planeas hacer la flag directamente visible en la interfaz de usuario, quizás quieras encontrar una forma de crear diferentes instancias (una para cada equipo/jugador)
Mientras pruebas la configuración antes de pasar a producción, podría ser útil obtener la superficie de ataque de la app objetivo. ¡Esto es algo que los jugadores no deberían ver porque forma parte de su trabajo descubrir y analizar la superficie de ataque!
Por lo tanto, se proporciona un endpoint GET accesible en /attackSurface y protegido con un token (que debe usarse como valor de la cabecera Authorization) que se genera aleatoriamente durante el arranque y se imprime en los logs (por lo tanto, accesible solo por administradores de sistemas).
Si quieres usar tus propios scripts de Frida en modo restringido, solo necesitas montar la carpeta que los contiene en el contenedor Docker:
volumes:
- <Frida library folder>:/droidground/library
Se requiere un archivo library.json (como el de library) para indicar a la aplicación la lista de scripts disponibles.
🛠 Desarrollo
Ponerlo en marcha no debería ser demasiado difícil, pero antes de empezar deberías tener instaladas las siguientes herramientas:
frida(solo si habilitas Frida)node(¡es una app Node, necesitas tenerlo!)adb(bueno, dependemos de él para comunicarnos con el dispositivo)- JDK (lo necesitas para compilar la app complementaria)
Después de eso, puedes simplemente ejecutar lo siguiente:
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
Después de eso, solo necesitas establecer las variables de entorno y luego ejecutar npm run dev y estarás listo para empezar. ¡Feliz modo desarrollo!
🤝 Contribuir
¡Las pull requests son bienvenidas! Por favor, abre primero un issue para discutir cambios importantes. Las ideas para nuevos flujos de trabajo de CTF o tipos de retos son especialmente apreciadas.
📚 Créditos
Desarrollado por Angelo Delicato @SECFORCE.
La sección del servidor depende en gran medida del increíble trabajo realizado por @yume-chan, probablemente esta app no existiría si no fuera por su increíble trabajo.
La app complementaria está basada en gran medida en el servidor aya, que funciona de la misma manera que el servidor scrcpy. Se pueden encontrar más detalles en el README específico.
🪪 Licencia
DroidGround se publica bajo la LICENCIA GPL-3.0







