Skip to content

Commit 9923e07

Browse files
committed
Merge branch 'release/0.3.1'
2 parents d199c67 + 8b225ff commit 9923e07

36 files changed

Lines changed: 807 additions & 149 deletions

.env.sample

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,5 @@ DROIDGROUND_RESET_DISABLED=false # Feature enabled by default if not set otherwi
2424
DROIDGROUND_EXPLOIT_APP_DURATION=10 # The time (in seconds) the exploit app will be active before the target app is restarted. This field makes sense only if the App Manager is enabled. Default value is 10
2525
DROIDGROUND_NUM_TEAMS=0 # Number of teams playing, this enables the usage of team-based tokens/keys to lock down the usage of installed apps and log servers
2626
DROIDGROUND_TEAM_TOKEN_1=RANDOMSTRING # Token for team #1, this only makes sense if DROIDGROUND_NUM_TEAMS is higher than 0. If a team token is not explicitly defined it'll be randomly generated on boot and present in the output logs
27-
DROIDGROUND_IP_IFACE=eth0 # If this is set the UI will display the IP address associated with it. Useful to provide to the users the IP of the exploit server if dynamic. Empty by default
27+
DROIDGROUND_IP_STATIC=192.168.1.1 # Shows a static IP address in the Exploit Server page, this takes precedence over DROIDGROUND_IP_IFACE
28+
DROIDGROUND_IP_IFACE=eth0 # If this is set the UI will display the IP address associated with it. If an exact match is not found it will fallback to the first interface that starts with it. Useful to provide to the users the IP of the exploit server if dynamic. Empty by default

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<p align="center">
1010
<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>
1111
<a href="https://github.com/SECFORCE/droidground/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-GPL3-blue.svg"></a>
12+
<a href="https://blackhat.com/eu-25/arsenal/schedule/index.html#droidground-a-flexible-playground-for-android-ctf-challenges-47803"><img src="./docs/blackhat-2025.svg"></a>
1213
</p>
1314

1415
In traditional **CTF challenges**, it's common to hide flags in files on a system, requiring attackers to exploit vulnerabilities to retrieve them. However, in the Android world, this approach doesn't work well. APK files are easily downloadable and reversible, so **placing a flag on the device usually makes it trivial** to extract using static analysis or emulator tricks. This severely limits the ability to create realistic, runtime-focused challenges.
@@ -56,6 +57,7 @@ DroidGround provides a rich set of server-controlled features.
5657
- **Terminal Access**
5758
- **APK Management**
5859
- **Logcat Viewer**
60+
- **Exploit Server** (if team mode is enabled)
5961

6062
Almost all features are **modular** and defined via environment variables, ensuring precise control over the challenge scope.
6163

@@ -103,7 +105,10 @@ The `.env.sample` file in the root directory is a good starting point. This is t
103105
| `DROIDGROUND_EXPLOIT_APP_DURATION` | The time (in seconds) the exploit app will be active | `10` |
104106
| `DROIDGROUND_NUM_TEAMS` | The number of teams playing simultaneously | - |
105107
| `DROIDGROUND_TEAM_TOKEN_<N>` | The token for the nth team. Auto-generated if missing | - |
106-
| `DROIDGROUND_IP_IFACE` | The network interface for the displayed IP address. No IP is displayed if missing | - |
108+
| `DROIDGROUND_IP_STATIC` | The static IP address to display. It takes precedence over `DROIDGROUND_IP_IFACE` | - |
109+
| `DROIDGROUND_IP_IFACE` | The network interface for the displayed IP address | - |
110+
111+
The `DROIDGROUND_IP_IFACE` looks for an exact match first and fallbacks to the first interface that _starts with_ the provided value since Docker only allows to specify the network interface **prefix** within the container.
107112

108113
The usage of the `DROIDGROUND_NUM_TEAMS` variable slightly changes the behaviour of the application under the hood. If this option is set:
109114

@@ -147,6 +152,8 @@ echo "Install command executed"
147152

148153
For a production deploy (in a real CTF) you may want to provision a pre-defined number of DroidGround instances beforehand or you may want to allow the users to spawn instances (with a limitation or maybe associate each team/user with a specific instance). For this reason we also added a simple [spawner example](./examples/spawner).
149154

155+
Alternatively, as previously mentioned, you can create a challenge where the flag can be exfiltrated via a network request and leverage the `DROIDGROUND_NUM_TEAMS` env variable to avoid spawning multiple instances (which could be expensive). The [net-multi-step](./examples/apps/net-multi-step/) folder provides a good example on how to deliver this type of challenges.
156+
150157
## 💡 Tips
151158

152159
Here are some suggestions for setting up your Android CTF:

docs/blackhat-2025.svg

Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Hidden Activity
2+
3+
This is the simplest example ever to showcase basic _DroidGround's_ features.
4+
The target application is downloaded from the [samples](https://github.com/SECFORCE/droidground-samples) and it only contains an "hidden" exported activity that displays the flag.
5+
This "challenge" can be easily solved just by using the "Start Activity" feature in the "Overview" page.
6+
7+
This example also showcases the `DROIDGROUND_BASE_PATH` env variable, which runs DroidGround on a subpath.
8+
9+
Take a look at other examples for more realistic challenges.
Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# The ./init.d folder should contain the "setup.sh" and "reset.sh" scripts
22

33
services:
4-
docker-android:
4+
android-device:
55
image: halimqarroum/docker-android:api-33
66
devices:
77
- /dev/kvm
@@ -16,19 +16,5 @@ services:
1616
- 4242:4242
1717
volumes:
1818
- ./init.d:/init.d
19-
environment:
20-
- DROIDGROUND_BASE_PATH=/random1
21-
- DROIDGROUND_APP_PACKAGE_NAME=com.droidground.hiddenactivity
22-
- DROIDGROUND_ADB_HOST=localhost
23-
- DROIDGROUND_ADB_PORT=5037
24-
- DROIDGROUND_DEVICE_TYPE=network
25-
- DROIDGROUND_DEVICE_HOST=docker-android
26-
- DROIDGROUND_DEVICE_PORT=5555
27-
- DROIDGROUND_INIT_SCRIPTS_FOLDER=/init.d
28-
- DROIDGROUND_HOST=0.0.0.0
29-
- DROIDGROUND_PORT=4242
30-
- DROIDGROUND_APP_MANAGER_DISABLED=true
31-
- DROIDGROUND_FRIDA_DISABLED=true
32-
- DROIDGROUND_START_RECEIVER_DISABLED=true
33-
- DROIDGROUND_START_SERVICE_DISABLED=true
34-
- DROIDGROUND_TERMINAL_DISABLED=true
19+
env_file:
20+
- hidden-activity.env

examples/apps/hidden-activity/compose.redroid.debian.yaml

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,17 @@
77
# The ./init.d folder should contain the "setup.sh" and "reset.sh" scripts
88

99
services:
10-
redroid:
10+
android-device:
1111
privileged: true
1212
volumes:
1313
- /dev/binder1:/dev/binder
1414
- /dev/binder2:/dev/hwbinder
1515
- /dev/binder3:/dev/vndbinder
1616
ports:
1717
- 5555:5555 # No need to expose this, but it's useful for debugging purposes
18-
container_name: redroid14
18+
container_name: redroid
1919
image: redroid/redroid:14.0.0-latest
20+
command: ["ro.debuggable=0", "ro.boot.verifiedbootstate=orange"]
2021
droidground:
2122
build: ../../..
2223
container_name: droidground
@@ -25,18 +26,5 @@ services:
2526
- 4242:4242
2627
volumes:
2728
- ./init.d:/init.d
28-
environment:
29-
- DROIDGROUND_APP_PACKAGE_NAME=com.droidground.hiddenactivity
30-
- DROIDGROUND_ADB_HOST=localhost
31-
- DROIDGROUND_ADB_PORT=5037
32-
- DROIDGROUND_DEVICE_TYPE=network
33-
- DROIDGROUND_DEVICE_HOST=redroid
34-
- DROIDGROUND_DEVICE_PORT=5555
35-
- DROIDGROUND_INIT_SCRIPTS_FOLDER=/init.d
36-
- DROIDGROUND_HOST=0.0.0.0
37-
- DROIDGROUND_PORT=4242
38-
- DROIDGROUND_APP_MANAGER_DISABLED=true
39-
- DROIDGROUND_FRIDA_DISABLED=true
40-
- DROIDGROUND_START_RECEIVER_DISABLED=true
41-
- DROIDGROUND_START_SERVICE_DISABLED=true
42-
- DROIDGROUND_TERMINAL_DISABLED=true
29+
env_file:
30+
- hidden-activity.env

examples/apps/hidden-activity/compose.redroid.ubuntu.yaml

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@
1010
# The ./init.d folder should contain the "setup.sh" and "reset.sh" scripts
1111

1212
services:
13-
redroid:
13+
android-device:
1414
privileged: true
1515
ports:
1616
- 5555:5555 # No need to expose this, but it's useful for debugging purposes
17-
container_name: redroid14
17+
container_name: redroid
1818
image: redroid/redroid:14.0.0-latest
19+
command: ["ro.debuggable=0", "ro.boot.verifiedbootstate=orange"]
1920
droidground:
2021
build: ../../..
2122
container_name: droidground
@@ -24,18 +25,5 @@ services:
2425
- 4242:4242
2526
volumes:
2627
- ./init.d:/init.d
27-
environment:
28-
- DROIDGROUND_APP_PACKAGE_NAME=com.droidground.hiddenactivity
29-
- DROIDGROUND_ADB_HOST=localhost
30-
- DROIDGROUND_ADB_PORT=5037
31-
- DROIDGROUND_DEVICE_TYPE=network
32-
- DROIDGROUND_DEVICE_HOST=redroid
33-
- DROIDGROUND_DEVICE_PORT=5555
34-
- DROIDGROUND_INIT_SCRIPTS_FOLDER=/init.d
35-
- DROIDGROUND_HOST=0.0.0.0
36-
- DROIDGROUND_PORT=4242
37-
- DROIDGROUND_APP_MANAGER_DISABLED=true
38-
- DROIDGROUND_FRIDA_DISABLED=true
39-
- DROIDGROUND_START_RECEIVER_DISABLED=true
40-
- DROIDGROUND_START_SERVICE_DISABLED=true
41-
- DROIDGROUND_TERMINAL_DISABLED=true
28+
env_file:
29+
- hidden-activity.env
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
DROIDGROUND_BASE_PATH=/random1
2+
DROIDGROUND_APP_PACKAGE_NAME=com.droidground.hiddenactivity
3+
DROIDGROUND_ADB_HOST=localhost
4+
DROIDGROUND_ADB_PORT=5037
5+
DROIDGROUND_DEVICE_TYPE=network
6+
DROIDGROUND_DEVICE_HOST=android-device
7+
DROIDGROUND_DEVICE_PORT=5555
8+
DROIDGROUND_INIT_SCRIPTS_FOLDER=/init.d
9+
DROIDGROUND_HOST=0.0.0.0
10+
DROIDGROUND_PORT=4242
11+
DROIDGROUND_APP_MANAGER_DISABLED=true
12+
DROIDGROUND_FRIDA_DISABLED=true
13+
DROIDGROUND_START_RECEIVER_DISABLED=true
14+
DROIDGROUND_START_SERVICE_DISABLED=true
15+
DROIDGROUND_TERMINAL_DISABLED=true

examples/apps/multi-step/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Multi Step
2+
3+
This example showcases a more realistic intent-based CTF challenge where the user has to develop an exploit application in order to get the flag.
4+
The target application is downloaded from the [samples](https://github.com/SECFORCE/droidground-samples) and it contains an exported activity with a state machine within it. The goal of the player is to send the appropriate intents in the correct order to reach the final state and get the flag.
5+
6+
This example showcases the _App Manager_ feature which allows to install and run exploit applications. Since the flag is actively displayed on the screen, challenges like this one would require the organizers to either queue the access to DroidGround or spawn different instances for each team. For a more cost-effective solution take a look at [net-multi-step](../net-multi-step/).
Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# The ./init.d folder should contain the "setup.sh" and "reset.sh" scripts
22

33
services:
4-
docker-android:
4+
android-device:
55
image: halimqarroum/docker-android:api-33
66
devices:
77
- /dev/kvm
@@ -16,18 +16,5 @@ services:
1616
- 4242:4242
1717
volumes:
1818
- ./init.d:/init.d
19-
environment:
20-
- DROIDGROUND_APP_PACKAGE_NAME=com.droidground.multistep
21-
- DROIDGROUND_ADB_HOST=localhost
22-
- DROIDGROUND_ADB_PORT=5037
23-
- DROIDGROUND_DEVICE_TYPE=network
24-
- DROIDGROUND_DEVICE_HOST=docker-android
25-
- DROIDGROUND_DEVICE_PORT=5555
26-
- DROIDGROUND_INIT_SCRIPTS_FOLDER=/init.d
27-
- DROIDGROUND_HOST=0.0.0.0
28-
- DROIDGROUND_PORT=4242
29-
- DROIDGROUND_APP_MANAGER_DISABLED=true
30-
- DROIDGROUND_FRIDA_DISABLED=true
31-
- DROIDGROUND_START_RECEIVER_DISABLED=true
32-
- DROIDGROUND_START_SERVICE_DISABLED=true
33-
- DROIDGROUND_TERMINAL_DISABLED=true
19+
env_file:
20+
- multi-step.env

0 commit comments

Comments
 (0)