
Гибкая площадка для Android CTF-задач.
<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>
В традиционных **CTF-задачах** флаги часто прячут в файлах на системе, и атакующим приходится эксплуатировать уязвимости, чтобы их извлечь. Однако в мире Android такой подход плохо работает. APK-файлы легко скачать и декомпилировать, поэтому **размещение флага на устройстве обычно делает его извлечение тривиальным** с помощью статического анализа или трюков с эмулятором. Это серьёзно ограничивает возможность создавать реалистичные задачи, ориентированные на время выполнения.
_DroidGround_ создан для решения этой проблемы.
Это специально разработанная платформа для проведения задач по взлому Android-приложений в **контролируемой** и **реалистичной** среде, где **атакующие ограничены ровно настолько**, чтобы решать задачи предполагаемым способом.
Что важно, участники могут быть **заперты внутри среды приложения**. Модульность инструмента позволяет настроить, может ли пользователь запустить шелл, читать произвольные файлы или устанавливать сторонние инструменты. Всё можно настроить так, чтобы единственным способом получить флаг было понимание и эксплуатация самого приложения.
## 📋 Содержание
- [🧭 Обзор](#-обзор)
- [✨ Возможности](#-возможности)
- [📸 Скриншоты](#-скриншоты)
- [⚙️ Конфигурация](#️-конфигурация)
- [🧩 Сценарии использования](#-сценарии-использования)
- [⚙️ Использование](#️-использование)
- [💡 Советы](#-советы)
- [🛠 Разработка](#-разработка)
- [🤝 Участие в разработке](#-участие-в-разработке)
- [📚 Благодарности](#-благодарности)
- [🪪 Лицензия](#-лицензия)
## 🧭 Обзор
_DroidGround_ позволяет создавать широкий спектр _Android_-задач, которые иначе сложно реализовать в традиционных CTF-условиях. Например, в задаче на удалённое выполнение кода (RCE) игроки могут получить APK для локального анализа. Обнаружив уязвимость, они могут разработать Frida-скрипт и запустить его через DroidGround на реальном целевом устройстве, чтобы извлечь флаг из внутреннего хранилища. Другие типы задач могут включать скрытые активности, пользовательские broadcast-интенты, эксплуатацию сервисов или динамический анализ с помощью предзагруженных инструментов.
Благодаря потоковой передаче экрана устройства в реальном времени, тонкой настройке функций, интеграции с Frida и настраиваемым скриптам установки и сброса, DroidGround даёт организаторам CTF возможность создавать безопасные, гибкие и реалистичные Android-задачи, выходящие далеко за рамки типичных возможностей.
## ✨ Возможности
DroidGround предоставляет богатый набор функций, управляемых с сервера.
- **Экран устройства в реальном времени** (через `scrcpy`), с опциональным управлением мышью, касаниями и клавиатурой
- **Сброс состояния задачи**
- **Перезапуск приложения / Запуск активности / Запуск сервиса**
- **Отправка broadcast-интента**
- **Выключение / Перезагрузка устройства**
- **Скачивание bugreport (bugreportz)**
- **Frida-скриптинг**
- Запуск из предзагруженной библиотеки (режим jail)
- Запуск произвольных скриптов (полный режим)
- **Файловый браузер**
- **Доступ к терминалу**
- **Управление APK**
- **Просмотр Logcat**
- **Сервер эксплойтов** (если включён командный режим)
Почти все функции **модульные** и определяются через переменные окружения, что обеспечивает точный контроль над рамками задачи.
## 📸 Скриншоты
|  |  |
| ------------------------------------------------------ | ----------------------------------------------------- |
| Обзор | Запуск активности |
|  |  |
| Frida в режиме Jail | Frida в полном режиме |
|  |  |
| Файловый браузер | Менеджер приложений |
|  |  |
| Терминал | Логи |
## ⚙️ Конфигурация
Файл `.env.sample` в корневой директории — хорошая отправная точка. Ниже приведён полный список всех поддерживаемых на данный момент переменных окружения:
| Переменная | Описание | По умолчанию |
| ------------------------------------- | --------------------------------------------------------------------------------- | ------------ |
| `DROIDGROUND_BASE_PATH` | Путь веб-приложения (полезно для размещения на подпутях) | - |
| `DROIDGROUND_APP_PACKAGE_NAME` | Имя пакета целевого приложения | - |
| `DROIDGROUND_ADB_HOST` | Хост ADB | `localhost` |
| `DROIDGROUND_ADB_PORT` | Порт ADB | `5037` |
| `DROIDGROUND_ADB_SERIAL` | Опциональный серийный номер ADB-устройства для подключения | - |
| `DROIDGROUND_DEVICE_TYPE` | `usb` или `network` | `usb` |
| `DROIDGROUND_DEVICE_HOST` | IP Android-устройства (`adb`) (только в режиме network) | - |
| `DROIDGROUND_DEVICE_PORT` | Порт Android-устройства (`adb`) (только в режиме network) | - |
| `DROIDGROUND_INIT_SCRIPTS_FOLDER` | Папка, содержащая `setup.sh` и `reset.sh` | `/init.d` |
| `DROIDGROUND_HOST` | Адрес привязки | `0.0.0.0` |
| `DROIDGROUND_PORT` | Порт привязки | `4242` |
| `DROIDGROUND_RESTART_APP_DISABLED` | Отключить перезапуск приложения | `false` |
| `DROIDGROUND_APP_MANAGER_DISABLED` | Отключить менеджер приложений | `false` |
| `DROIDGROUND_BUG_REPORT_DISABLED` | Отключить bugreport | `false` |
| `DROIDGROUND_FILE_BROWSER_DISABLED` | Отключить файловый браузер | `false` |
| `DROIDGROUND_FRIDA_DISABLED` | Отключить поддержку Frida | `false` |
| `DROIDGROUND_FRIDA_TYPE` | `jail` или `full` | `jail` |
| `DROIDGROUND_FRIDA_INJECTION` | `server` или `gadget` | `server` |
| `DROIDGROUND_LOGCAT_DISABLED` | Отключить logcat | `false` |
| `DROIDGROUND_REBOOT_ENABLED` | Включить перезагрузку | `false` |
| `DROIDGROUND_SHUTDOWN_ENABLED` | Включить выключение | `false` |
| `DROIDGROUND_START_ACTIVITY_DISABLED` | Отключить startActivity | `false` |
| `DROIDGROUND_START_RECEIVER_DISABLED` | Отключить broadcast | `false` |
| `DROIDGROUND_START_SERVICE_DISABLED` | Отключить startService | `false` |
| `DROIDGROUND_TERMINAL_DISABLED` | Отключить терминал | `false` |
| `DROIDGROUND_RESET_DISABLED` | Отключить сброс | `false` |
| `DROIDGROUND_SCRCPY_CONTROL_ENABLED` | Включить ввод мышью, касаниями и клавиатурой через экран устройства | `false` |
| `DROIDGROUND_SCRCPY_MAX_SIZE` | Максимальный размер видео в пикселях; `0` сохраняет полное разрешение устройства | `1280` |
| `DROIDGROUND_SCRCPY_MAX_FPS` | Максимальная частота кадров видео; `0` оставляет её неограниченной | `60` |
| `DROIDGROUND_SCRCPY_VIDEO_BIT_RATE` | Битрейт видео в битах в секунду | `4000000` |
| `DROIDGROUND_EXPLOIT_APP_DURATION` | Время (в секундах), в течение которого эксплойт-приложение будет активно | `10` |
| `DROIDGROUND_EXPLOIT_APP_MAX_SIZE` | Максимальный размер (в МБ) эксплойт-приложения | `50` |
| `DROIDGROUND_NUM_TEAMS` | Количество команд, играющих одновременно | - |
| `DROIDGROUND_TEAM_TOKEN_<N>` | Токен для n-й команды. Генерируется автоматически при отсутствии | - |
| `DROIDGROUND_IP_STATIC` | Статический IP-адрес для отображения. Имеет приоритет над `DROIDGROUND_IP_IFACE` | - |
| `DROIDGROUND_IP_IFACE` | Сетевой интерфейс для отображаемого IP-адреса | - |
| `DROIDGROUND_LOGO_LINK` | Опционально задаёт ссылку при клике на логотип (например, главную страницу вашего CTF) | - |
Установите `DROIDGROUND_SCRCPY_CONTROL_ENABLED=true` и перезапустите DroidGround, чтобы сделать экран устройства интерактивным. Кликните или коснитесь экрана, чтобы сфокусировать его, затем кликайте, перетаскивайте, свайпайте, используйте несколько точек касания, прокручивайте колесом мыши или вводите текст. Правый клик или Escape — кнопка «Назад» в Android. Tab и Shift+Tab перемещают фокус за пределы экрана. Ввод разделяется всеми, кто просматривает устройство, в том числе в командном режиме. По умолчанию экран остаётся доступным только для просмотра. Ввод текста использует инъекцию клавиш Android от scrcpy, поэтому поддержка символов зависит от раскладки клавиатуры устройства.
`DROIDGROUND_IP_IFACE` сначала ищет точное совпадение и при неудаче переходит к первому интерфейсу, который _начинается с_ указанного значения, поскольку Docker позволяет указать только **префикс** сетевого интерфейса внутри контейнера.
Потоковая передача экрана по умолчанию использует максимальный размер 1280 пикселей, до 60 fps и 4 Мбит/с, чтобы снизить нагрузку на кодирование, сеть и браузер. Это идёт на компромисс с детализацией ради отзывчивости во встроенном представлении устройства. Установите `DROIDGROUND_SCRCPY_MAX_SIZE=0` и `DROIDGROUND_SCRCPY_VIDEO_BIT_RATE=10000000`, чтобы вернуть прежние настройки качества с полным разрешением. Для медленных соединений или браузеров попробуйте максимальный размер `1024`, `30` fps и `2000000` бит в секунду. Перезапустите DroidGround после изменения этих настроек.
Браузер использует WebCodecs, когда он доступен, и в противном случае переключается на программный декодер H.264. WebCodecs требует защищённого контекста: используйте HTTPS для удалённых развёртываний (localhost также подходит). Обычный HTTP на удалённом IP или имени хоста использует программное декодирование. Медленные зрители перескакивают к свежему ключевому кадру вместо накопления видеобэклога. Если ключевой кадр не приходит в течение 1,5 секунд, DroidGround запрашивает обновление видео; это поддерживает такие кодировщики, как `OMX.google.h264.encoder` в ReDroid, чьи периодические I-кадры не обязательно являются независимо декодируемыми IDR-кадрами. Запросы на обновление разделяются между зрителями и могут ненадолго обновить экран для всех. Сервер поддерживает внутренний канал управления scrcpy для обновления видео; ввод мышью, касаниями, клавиатурой и автоматическое пробуждение экрана по-прежнему зависят от `DROIDGROUND_SCRCPY_CONTROL_ENABLED`. См. [спецификацию WebCodecs](https://www.w3.org/TR/webcodecs/#videodecoder-interface) и [документацию по видео scrcpy](https://github.com/Genymobile/scrcpy/blob/master/doc/video.md) для получения информации о базовых настройках браузера и видео.
Использование переменной `DROIDGROUND_NUM_TEAMS` немного меняет поведение приложения под капотом. Если эта опция задана:
1. Включается функция сервера эксплойтов, позволяя каждой команде использовать собственный (очень простой) сервер эксплойтов через свой **_токен команды_**.
2. **_Токен команды_** будет **обязателен** для установки и запуска эксплойт-приложений. Каждое установленное приложение будет привязано к команде, и другие команды не смогут его запустить.
Это позволяет использовать один и тот же экземпляр DroidGround несколькими командами в задачах, где флаг можно эксфильтровать через сетевой запрос. Это **значительно снижает затраты на развёртывание DroidGround** для CTF-соревнований.
Кроме того, если значение установлено в `-1`, включается так называемый режим **Unlimited Teams**. В этом режиме на странице _Обзор_ появится кнопка для генерации нового **_токена команды_**. Все переменные `DROIDGROUND_TEAM_TOKEN_<N>` игнорируются, если этот режим включён.
## 🧩 Сценарии использования
Вот несколько способов использования DroidGround:
1. **Скрытая активность**: найти и запустить неэкспортированную активность, чтобы увидеть флаг (в приложении игрока содержится фиктивный флаг).
2. **RCE**: приложение уязвимо к RCE, а флаг хранится на устройстве.
3. **Инструментирование Frida**: перегрузить метод и извлечь флаг из приватной памяти с помощью скрипта.
## ⚙️ Использование
Несколько примеров файлов _Docker Compose_ приведены в папке [examples](https://github.com/secforce/droidground/blob/main/examples/apps). Они используют приложения из [репозитория примеров DroidGround](https://github.com/SECFORCE/droidground-samples), который будет постепенно дополняться, чтобы продемонстрировать все ключевые функции. Они также являются хорошей отправной точкой для понимания того, как настроить собственный CTF.
При загрузке _DroidGround_ выполняет следующее:
1. Устанавливает соединение с `adb`
2. Запускает `setup.sh` в папке, указанной в `DROIDGROUND_INIT_SCRIPTS_FOLDER`, если он присутствует. Этот скрипт можно использовать для установки целевого приложения и всего остального, что нужно для инициализации CTF (например, размещения флага в известном месте)
3. (если _Frida_ включена) Скачивает подходящий `frida-server` на основе установленной версии и архитектуры устройства и запускает его
4. Запускает целевое приложение (указанное через `DROIDGROUND_APP_PACKAGE_NAME`). Если приложение не установлено, _DroidGround_ завершит работу.
5. Настраивает _REST API_, серверы _WebSocket_ и потоковую передачу экрана
Вот пример скрипта `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"
```
Для продакшн-развёртывания (в реальном CTF) вы можете заранее подготовить заданное количество экземпляров DroidGround или разрешить пользователям создавать экземпляры (с ограничением или, возможно, связав каждую команду/пользователя с конкретным экземпляром). По этой причине мы также добавили простой [пример спавнера](https://github.com/secforce/droidground/blob/main/examples/spawner).
Как уже упоминалось, вы можете создать задачу, где флаг можно эксфильтровать через сетевой запрос, и использовать переменную окружения `DROIDGROUND_NUM_TEAMS`, чтобы избежать создания множества экземпляров (что может быть дорого). Папка [net-multi-step](https://github.com/secforce/droidground/blob/main/examples/apps/net-multi-step) содержит хороший пример того, как реализовать такие задачи.
## 💡 Советы
Вот несколько рекомендаций по настройке вашего Android CTF:
- Будьте осторожны при включении **Frida Full Mode** — игрок получит полный контроль над устройством (именно поэтому мы сделали **Frida Jail Mode**, как описано в [Frida Library](https://github.com/secforce/droidground/blob/main/library)).
- Будьте осторожны при включении **Терминала** — игрок получит полный контроль над устройством.
- Будьте осторожны при включении функции **Выключение**.
- Если вы планируете сделать флаг видимым прямо в UI, возможно, стоит найти способ создавать разные экземпляры (по одному на команду/игрока)
При тестировании конфигурации перед выходом в продакшн может быть полезно получить **поверхность атаки** целевого приложения. Это то, что игроки не должны видеть, поскольку обнаружение и анализ поверхности атаки — часть их задачи!
Поэтому предоставляется `GET`-эндпоинт, доступный по адресу `/attackSurface`, защищённый токеном (который нужно использовать как значение заголовка `Authorization`), случайно генерируемым при загрузке и выводимым в логи (следовательно, доступным только системным администраторам).
Если вы хотите использовать собственные Frida-скрипты в режиме jail, вам просто нужно примонтировать папку, содержащую их, в Docker-контейнер:
```yaml
volumes:
- <Frida library folder>:/droidground/library
```
Файл `library.json` (как в [library](https://github.com/secforce/droidground/blob/main/library/library.json)) необходим, чтобы указать приложению список доступных скриптов.
## 🛠 Разработка
Запустить всё это не должно быть слишком сложно, но перед началом у вас должны быть установлены следующие инструменты:
- `frida` (только если вы включаете _Frida_)
- `node` (это Node-приложение, он вам нужен!)
- `adb` (ну, мы полагаемся на него для связи с устройством)
- _JDK_ (нужен для сборки companion-приложения)
После этого вы можете просто выполнить следующее:
```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
```
После этого вам просто нужно задать переменные **env**, а затем запустить `npm run dev`, и всё готово. Удачного режима разработки!
## 🤝 Участие в разработке
Pull requests приветствуются! Пожалуйста, сначала откройте issue, чтобы обсудить крупные изменения. Особенно приветствуются идеи для новых CTF-воркфлоу или типов задач.
## 📚 Благодарности
Разработано [Angelo Delicato](https://github.com/thelicato) [@SECFORCE](https://www.secforce.com).
Раздел _server_ во многом опирается на потрясающую работу [@yume-chan](https://github.com/yume-chan/ya-webadb); вероятно, этого приложения не существовало бы без его замечательной работы.
Приложение _companion_ во многом основано на [aya server](https://github.com/liriliri/aya/tree/master/server), который работает так же, как [scrcpy server](https://github.com/Genymobile/scrcpy). Более подробную информацию можно найти в соответствующем [README](https://github.com/secforce/droidground/blob/main/companion/README.md).
## 🪪 Лицензия
_DroidGround_ выпускается под [лицензией GPL-3.0](https://github.com/SECFORCE/droidground/blob/main/LICENSE)