
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">ウェブサイト</a> |
<a href="https://droidground.com/demo" target="_blank">デモ</a>
</p>
従来の**CTFチャレンジ**では、システム上のファイルにフラグを隠し、攻撃者が脆弱性を悪用してそれを取得する必要があるようにするのが一般的です。しかし、Androidの世界ではこのアプローチはうまく機能しません。APKファイルは簡単にダウンロードでき、リバースエンジニアリングも容易であるため、**デバイス上にフラグを置くと、静的解析やエミュレータのトリックを使って抽出するのは通常たやすくなってしまいます**。これにより、現実的でランタイムに焦点を当てたチャレンジを作成する能力が著しく制限されます。
_DroidGround_ はこの問題を解決するために設計されました。
これは、Androidモバイルハッキングチャレンジを**制御された**かつ**現実的な**環境でホストするためにカスタム構築されたプラットフォームであり、**攻撃者は意図された方法でチャレンジを解くことを要求される程度にちょうどよく制約**されます。
重要な点として、参加者は**アプリ環境内に閉じ込められる**場合があります。このツールのモジュール性により、ユーザーがシェルを起動できるかどうか、任意のファイルを読み取れるかどうか、ツールをサイドロードできるかどうかを設定できます。フラグを取得する唯一の方法がアプリ自体を理解し悪用することになるように、すべてをセットアップできます。
## 📋 目次
- [🧭 概要](#-overview)
- [✨ 機能](#-features)
- [📸 スクリーンショット](#-screenshots)
- [⚙️ 設定](#️-configuration)
- [🧩 ユースケース](#-use-cases)
- [⚙️ 使用方法](#️-usage)
- [💡 ヒント](#-tips)
- [🛠 開発](#-development)
- [🤝 コントリビューション](#-contributing)
- [📚 クレジット](#-credits)
- [🪪 ライセンス](#-license)
## 🧭 概要
_DroidGround_ は、従来のCTF環境では実装が難しい多種多様な_Android_チャレンジを可能にします。例えば、リモートコード実行(RCE)チャレンジでは、プレイヤーはローカル分析用のAPKを受け取るかもしれません。脆弱性を発見した後、Fridaスクリプトを作成し、DroidGroundを通じて実際のターゲットデバイス上で実行して内部ストレージからフラグを抽出できます。他のチャレンジタイプには、隠しアクティビティ、カスタムブロードキャストインテント、サービスの悪用、またはプリロードされたツールを使用した動的解析などがあります。
リアルタイムのデバイスストリーミング、機能に対するきめ細かな制御、Frida統合、カスタマイズ可能なセットアップおよびリセットスクリプトにより、DroidGroundはCTF主催者が、通常可能な範囲をはるかに超えた、安全で柔軟かつ現実的なAndroidチャレンジを構築できるようにします。
## ✨ 機能
DroidGroundは、サーバー制御による豊富な機能セットを提供します。
- **リアルタイムデバイス画面**(`scrcpy`経由)、オプションでマウス、タッチ、キーボード操作が可能
- **チャレンジ状態のリセット**
- **アプリの再起動 / アクティビティの開始 / サービスの開始**
- **ブロードキャストインテントの送信**
- **デバイスのシャットダウン / 再起動**
- **バグレポートのダウンロード(bugreportz)**
- **Fridaスクリプティング**
- プリロードされたライブラリから実行(ジェイルモード)
- 任意のスクリプトを実行(フルモード)
- **ファイルブラウザ**
- **ターミナルアクセス**
- **APK管理**
- **Logcatビューア**
- **エクスプロイトサーバー**(チームモードが有効な場合)
ほぼすべての機能は**モジュール式**であり、環境変数を介して定義されるため、チャレンジの範囲を正確に制御できます。
## 📸 スクリーンショット
|  |  |
| ------------------------------------------------------ | ----------------------------------------------------- |
| 概要 | アクティビティ開始 |
|  |  |
| Frida Jailed モード | 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デバイス(`adb`)のIP(ネットワークモードのみ) | - |
| `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` | バグレポートを無効化 | `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` | エクスプロイトアプリがアクティブになる時間(秒) | `10` |
| `DROIDGROUND_EXPLOIT_APP_MAX_SIZE` | エクスプロイトアプリの最大サイズ(MB) | `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 で画面からフォーカスを移動します。入力はデバイスを閲覧している全員で共有されます。チームでのエクスプロイト実行中は、そのチームとして認証された閲覧者だけが画面の表示や操作を行えます。デフォルトでは引き続き閲覧専用の画面です。テキスト入力は 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. エクスプロイトサーバー機能が有効になり、各チームが自身の **_チームトークン_** を介して独自の(非常にシンプルな)エクスプロイトサーバーを使用できるようになります。
2. エクスプロイトアプリのインストールと実行には **_チームトークン_** が **必須** になります。インストールされた各アプリはチームに紐付けられ、他のチームはそれを実行できません。
3. あるチームのエクスプロイトアプリが実行されている間、他のチームやトークンを持たない閲覧者には、別のチームのエクスプロイトが実行中であることを説明する黒い画面が表示されます。サーバーはビデオを保留し、それらのデバイス入力を拒否します。対象アプリが再起動すると共有ディスプレイが再開します。自分のチームの実行を視聴するには、デバイス下の **Team token for display** にトークンを入力してください。UI からエクスプロイトを開始すると、そのブラウザのディスプレイも自動的に認証されます。トークンは URL ではなく WebSocket 経由で送信され、現在のページのメモリ内に保持されます。これは Unlimited Teams モードでも同様に適用されます。チームモードでない場合、ディスプレイは共有されたままです。
これにより、ネットワークリクエスト経由でフラグを窃取できるチャレンジにおいて、同じ DroidGround インスタンスを複数のチームで共有できるようになります。これは CTF コンペティションにおける **DroidGround のデプロイコストを大幅に削減** します。
さらに、値を `-1` に設定すると、いわゆる **Unlimited Teams** モードが有効になります。このモードでは、_Overview_ ページに新しい **_チームトークン_** を生成するボタンが表示されます。このモードが有効な場合、すべての `DROIDGROUND_TEAM_TOKEN_<N>` 変数は無視されます。
## 🧩 ユースケース
DroidGround の活用方法をいくつか紹介します:
1. **隠されたアクティビティ**: 公開されていないアクティビティを見つけて起動し、フラグを確認します(プレイヤーのアプリにはダミーのフラグが含まれています)。
2. **RCE**: アプリはRCEに対して脆弱であり、フラグはデバイス上に保存されています。
3. **Fridaインストルメンテーション**: メソッドをオーバーロードし、スクリプトを使用してプライベートメモリからフラグを抽出します。
## ⚙️ 使用方法
サンプルの_Docker Compose_ファイルがいくつか[examples](https://github.com/secforce/droidground/blob/main/examples/apps)フォルダに用意されています。これらは[DroidGround samples repo](https://github.com/SECFORCE/droidground-samples)のアプリを使用しており、主要な機能をすべて紹介できるよう段階的に強化されていきます。また、独自のCTFをセットアップする方法を理解するための良い出発点にもなります。
起動時、_DroidGround_は以下の処理を行います:
1. `adb`との接続をセットアップする
2. `DROIDGROUND_INIT_SCRIPTS_FOLDER`で指定されたフォルダ内に`setup.sh`が存在する場合、それを実行する。このスクリプトは、ターゲットアプリのインストールや、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インスタンスをプロビジョニングするか、ユーザーがインスタンスを起動できるようにする(制限を設ける、あるいは各チーム/ユーザーを特定のインスタンスに関連付ける)ことを検討するかもしれません。そのため、シンプルな[spawnerの例](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 Library](https://github.com/secforce/droidground/blob/main/library) で詳述されている **Frida Jail Mode** を用意しました)。
- **Terminal** を有効にする際は注意してください。プレイヤーはデバイスを完全に制御できるようになります。
- **Shutdown** 機能を有効にする際は注意してください。
- フラグをUI上で直接見えるようにする予定がある場合は、異なるインスタンスを起動する方法(チーム/プレイヤーごとに1つ)を見つけることを検討してください。
本番環境に移行する前にセットアップをテストする際、対象アプリの**攻撃対象領域**を把握しておくと役立つ場合があります。これはプレイヤーが見るべきものではありません。攻撃対象領域を発見・分析することはプレイヤーの仕事の一部だからです!
そのため、`/attackSurface` でアクセス可能な `GET` エンドポイントが提供されており、起動時にランダムに生成されログに出力されるトークン(`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_(コンパニオンアプリのビルドに必要です)
その後は、以下を実行するだけです:
```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` を実行するだけで準備完了です。楽しい開発を!
## 🤝 コントリビューション
プルリクエストを歓迎します!大きな変更については、まず issue を開いて議論してください。新しい CTF ワークフローやチャレンジタイプのアイデアは特に歓迎します。
## 📚 クレジット
[Angelo Delicato](https://github.com/thelicato) [@SECFORCE](https://www.secforce.com) によって開発されました。
_server_ セクションは [@yume-chan](https://github.com/yume-chan/ya-webadb) による素晴らしい成果に大きく依存しており、彼の素晴らしい仕事がなければこのアプリは存在しなかったでしょう。
_companion_ アプリは、[scrcpy server](https://github.com/Genymobile/scrcpy) と同じように動作する [aya server](https://github.com/liriliri/aya/tree/master/server) に大きく基づいています。詳細は専用の [README](https://github.com/secforce/droidground/blob/main/companion/README.md) を参照してください。
## 🪪 ライセンス
_DroidGround_ は [GPL-3.0 LICENSE](https://github.com/SECFORCE/droidground/blob/main/LICENSE) の下でリリースされています。