<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">网站</a> |
<a href="https://droidground.com/demo" target="_blank">演示</a>
</p>
在传统的 **CTF 挑战**中,通常会将 flag 隐藏在系统文件中,要求攻击者利用漏洞来获取它们。然而,在 Android 世界中,这种方法效果不佳。APK 文件很容易被下载和逆向,因此**将 flag 放在设备上通常使其变得轻而易举**,可以通过静态分析或模拟器技巧来提取。这严重限制了创建逼真的、以运行时为重点的挑战的能力。
_DroidGround_ 正是为解决这个问题而设计的。
它是一个定制构建的平台,用于在**受控**且**逼真**的环境中托管 Android 移动黑客挑战,其中**攻击者受到恰到好处的限制**,从而必须以预期的方式解决挑战。
重要的是,参与者可能被**限制在应用环境内**。该工具的模块化设计允许设置用户是否可以生成 shell、读取任意文件或侧载工具。一切都可以设置成只有通过理解和利用应用本身才能获取 flag。
## 📋 目录
- [🧭 概述](#-概述)
- [✨ 功能](#-功能)
- [📸 截图](#-截图)
- [⚙️ 配置](#️-配置)
- [🧩 使用场景](#-使用场景)
- [⚙️ 使用方法](#️-使用方法)
- [💡 提示](#-提示)
- [🛠 开发](#-开发)
- [🤝 贡献](#-贡献)
- [📚 致谢](#-致谢)
- [🪪 许可证](#-许可证)
## 🧭 概述
_DroidGround_ 支持各种在传统 CTF 设置中难以实现的 _Android_ 挑战。例如,在远程代码执行(RCE)挑战中,玩家可能会收到一个 APK 用于本地分析。在发现漏洞后,他们可以开发一个 Frida 脚本,并通过 DroidGround 在真实目标设备上运行它,以从内部存储中提取 flag。其他挑战类型可能涉及隐藏的 activity、自定义广播 intent、service 利用,或使用预加载工具进行动态分析。
借助实时设备流式传输、对功能的细粒度控制、Frida 集成以及可定制的设置和重置脚本,DroidGround 使 CTF 组织者能够构建安全、灵活且逼真的 Android 挑战,远远超出通常所能实现的范围。
## ✨ 功能
DroidGround 提供了一套丰富的服务器控制功能。
- **实时设备屏幕**(通过 `scrcpy`),可选鼠标、触摸和键盘控制
- **重置挑战状态**
- **重启应用 / 启动 Activity / 启动 Service**
- **发送广播 Intent**
- **关机 / 重启设备**
- **下载 Bugreport(bugreportz)**
- **Frida 脚本**
- 从预加载库运行(受限模式)
- 运行任意脚本(完整模式)
- **文件浏览器**
- **终端访问**
- **APK 管理**
- **Logcat 查看器**
- **Exploit 服务器**(如果启用了团队模式)
几乎所有功能都是**模块化**的,并通过环境变量定义,确保对挑战范围进行精确控制。
## 📸 截图
|  |  |
| ------------------------------------------------------ | ----------------------------------------------------- |
| 概述 | 启动 Activity |
|  |  |
| Frida 受限模式 | Frida 完整模式 |
|  |  |
| 文件浏览器 | 应用管理器 |
|  |  |
| 终端 | 日志 |
## ⚙️ 配置
根目录中的 `.env.sample` 文件是一个很好的起点。以下是当前支持的所有环境变量的完整列表:
| 变量 | 描述 | 默认值 |
| ------------------------------------- | --------------------------------------------------------------------------------- | ----------- |
| `DROIDGROUND_BASE_PATH` | Web 应用的路径(用于托管在子路径下) | - |
| `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` | Android 设备的 IP(`adb`)(仅网络模式) | - |
| `DROIDGROUND_DEVICE_PORT` | Android 设备的端口(`adb`)(仅网络模式) | - |
| `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` | 禁用广播 | `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` | exploit 应用处于活动状态的时间(秒) | `10` |
| `DROIDGROUND_EXPLOIT_APP_MAX_SIZE` | exploit 应用的最大大小(MB) | `50` |
| `DROIDGROUND_NUM_TEAMS` | 同时进行游戏的团队数量 | - |
| `DROIDGROUND_TEAM_TOKEN_<N>` | 第 n 个团队的 token。如果缺失则自动生成 | - |
| `DROIDGROUND_IP_STATIC` | 要显示的静态 IP 地址。它优先于 `DROIDGROUND_IP_IFACE` | - |
| `DROIDGROUND_IP_IFACE` | 用于显示 IP 地址的网络接口 | - |
| `DROIDGROUND_LOGO_LINK` | 可选设置 logo 点击跳转链接(例如,你的 CTF 主页) | - |
设置 `DROIDGROUND_SCRCPY_CONTROL_ENABLED=true` 并重启 DroidGround 以使设备屏幕可交互。点击或轻触屏幕以使其获得焦点,然后可以点击、拖动、滑动、使用多点触控、用鼠标滚轮滚动或输入。右键单击或按 Escape 键执行 Android 返回操作。Tab 和 Shift+Tab 将焦点移出屏幕。输入由所有查看设备的人共享,包括在团队模式下。默认仍为仅查看屏幕。文本输入使用 scrcpy 的 Android 按键注入,因此字符支持取决于设备的键盘映射。
`DROIDGROUND_IP_IFACE` 首先查找精确匹配,然后回退到以所提供值_开头_的第一个接口,因为 Docker 只允许在容器内指定网络接口**前缀**。
屏幕流式传输默认最大尺寸为 1280 像素,最高 60 fps,4 Mbps,以减少编码、网络和浏览器的工作量。这在嵌入式设备视图中以一些精细细节换取响应速度。设置 `DROIDGROUND_SCRCPY_MAX_SIZE=0` 和 `DROIDGROUND_SCRCPY_VIDEO_BIT_RATE=10000000` 可恢复之前的全分辨率质量设置。对于较慢的连接或浏览器,请尝试最大尺寸 `1024`、`30` fps 和 `2000000` 比特每秒。更改这些设置后请重启 DroidGround。
浏览器在可用时使用 WebCodecs,否则回退到软件 H.264 解码器。WebCodecs 需要安全上下文:远程部署请使用 HTTPS(localhost 也可以)。在远程 IP 或主机名上使用纯 HTTP 会使用软件解码。慢速查看器会跳转到新的关键帧,而不是累积视频积压。如果 1.5 秒内没有关键帧到达,DroidGround 会请求视频刷新;这支持诸如 ReDroid 的 `OMX.google.h264.encoder` 之类的编码器,其周期性 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. 启用 exploit 服务器功能,允许每个团队通过其 **_team token_** 使用自己的(非常简单的)exploit 服务器。
2. 安装和运行 exploit 应用将**需要** team token。每个安装的应用将绑定到一个团队,其他团队将无法运行它。
这允许在可以通过网络请求外泄 flag 的挑战中,与多个团队共享同一个 DroidGround 实例。这**大幅降低了 CTF 竞赛中 DroidGround 的部署成本**。
此外,如果该值设置为 `-1`,将启用所谓的**无限团队**模式。在此模式下,_概述_页面中将提供一个生成新 **_team token_** 的按钮。如果启用了此模式,所有 `DROIDGROUND_TEAM_TOKEN_<N>` 变量都将被忽略。
## 🧩 使用场景
以下是 DroidGround 的一些使用方式:
1. **隐藏 Activity**:找到并启动一个未暴露的 activity 以查看 flag(玩家的应用包含一个虚拟 flag)。
2. **RCE**:应用易受 RCE 攻击,flag 存储在设备上。
3. **Frida 插桩**:重载一个方法并使用脚本从私有内存中提取 flag。
## ⚙️ 使用方法
[examples](https://github.com/secforce/droidground/blob/main/examples/apps) 文件夹中提供了几个示例 _Docker Compose_ 文件。它们使用来自 [DroidGround 示例仓库](https://github.com/SECFORCE/droidground-samples) 的应用,该仓库将逐步增强以展示所有关键功能。它们也是了解如何设置自己的 CTF 的良好起点。
启动时 _DroidGround_ 会执行以下操作:
1. 使用 `adb` 建立连接
2. 如果存在,运行由 `DROIDGROUND_INIT_SCRIPTS_FOLDER` 指定的文件夹中的 `setup.sh`。此脚本可用于安装目标应用以及执行初始化 CTF 所需的其他所有操作(例如将 flag 放置在已知位置)
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 实例,或者你可能希望允许用户生成实例(有限制,或者将每个团队/用户与特定实例关联)。为此,我们还添加了一个简单的 [spawner 示例](https://github.com/secforce/droidground/blob/main/examples/spawner)。
或者,如前所述,你可以创建一个可以通过网络请求外泄 flag 的挑战,并利用 `DROIDGROUND_NUM_TEAMS` 环境变量来避免生成多个实例(这可能很昂贵)。[net-multi-step](https://github.com/secforce/droidground/blob/main/examples/apps/net-multi-step) 文件夹提供了一个很好的示例,说明如何提供此类挑战。
## 💡 提示
以下是一些设置 Android CTF 的建议:
- 启用 **Frida 完整模式**时要小心,玩家将拥有对设备的完全控制权(这就是我们制作 **Frida 受限模式**的原因,详见 [Frida 库](https://github.com/secforce/droidground/blob/main/library))。
- 启用**终端**时要小心,玩家将拥有对设备的完全控制权。
- 启用**关机**功能时要小心。
- 如果你计划让 flag 直接在 UI 中可见,你可能需要找到一种生成不同实例的方法(每个团队/玩家一个)
在生产环境之前测试设置时,获取目标应用的**攻击面**可能会很有用。这是玩家不应该看到的内容,因为发现和分析攻击面是他们工作的一部分!
因此,提供了一个可通过 `/attackSurface` 访问的 `GET` 端点,并使用在启动期间随机生成并打印在日志中的 token(需要用作 `Authorization` 头的值)进行保护(因此只有系统管理员可以访问)。
如果你想在受限模式下使用自己的 Frida 脚本,只需将包含它们的文件夹绑定挂载到 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 Request!请先开一个 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 LICENSE](https://github.com/SECFORCE/droidground/blob/main/LICENSE) 下发布