
Android CTF 챌린지를 위한 유연한 플레이그라운드입니다.
DroidGround
전통적인 CTF 챌린지에서는 시스템의 파일에 플래그를 숨겨 두고, 공격자가 취약점을 악용하여 이를 찾아내도록 하는 것이 일반적입니다. 하지만 Android 세계에서는 이러한 방식이 잘 통하지 않습니다. APK 파일은 쉽게 다운로드하고 리버싱할 수 있으므로, 기기에 플래그를 두는 것은 보통 정적 분석이나 에뮬레이터 트릭으로 쉽게 추출될 수 있게 만듭니다. 이는 현실적이고 런타임 중심의 챌린지를 만드는 능력을 심각하게 제한합니다.
_DroidGround_는 이 문제를 해결하기 위해 설계되었습니다.
이는 통제된 현실적인 환경에서 Android 모바일 해킹 챌린지를 호스팅하기 위해 맞춤 제작된 플랫폼으로, 공격자가 의도된 방식으로 챌린지를 해결해야만 하도록 적절히 제약을 받는 환경을 제공합니다.
중요한 점은 참가자가 **앱 환경 내부로 격리(jailed)**될 수 있다는 것입니다. 이 도구의 모듈성 덕분에 사용자가 셸을 실행할 수 있는지, 임의의 파일을 읽을 수 있는지, 도구를 사이드로드할 수 있는지 여부를 설정할 수 있습니다. 플래그를 얻을 수 있는 유일한 방법이 앱 자체를 이해하고 악용하는 것이 되도록 모든 것을 설정할 수 있습니다.
_DroidGround_는 기존 CTF 구성에서는 구현하기 어려운 다양한 Android 챌린지를 지원합니다. 예를 들어, 원격 코드 실행(RCE) 챌린지에서 플레이어는 로컬 분석을 위해 APK를 받을 수 있습니다. 취약점을 발견한 후에는 Frida 스크립트를 개발하여 DroidGround를 통해 실제 대상 기기에서 실행하고 내부 저장소에서 플래그를 추출할 수 있습니다. 다른 챌린지 유형으로는 숨겨진 액티비티, 커스텀 브로드캐스트 인텐트, 서비스 악용, 사전 로드된 도구를 사용한 동적 분석 등이 있습니다.
실시간 기기 스트리밍, 기능에 대한 세밀한 제어, Frida 통합, 사용자 정의 가능한 설정(setup) 및 초기화(reset) 스크립트를 통해 DroidGround는 CTF 운영자가 일반적으로 가능한 수준을 훨씬 뛰어넘는 안전하고 유연하며 현실적인 Android 챌린지를 구축할 수 있게 해줍니다.
DroidGround는 서버에서 제어되는 다양한 기능을 제공합니다.
scrcpy를 통해)거의 모든 기능은 모듈식이며 환경 변수를 통해 정의되므로 챌린지 범위를 정밀하게 제어할 수 있습니다.
루트 디렉터리의 .env.sample 파일이 좋은 시작점입니다. 다음은 현재 지원되는 모든 환경 변수의 전체 목록입니다:
DROIDGROUND_IP_IFACE는 먼저 정확히 일치하는 값을 찾고, Docker는 컨테이너 내에서 네트워크 인터페이스 **접두어(prefix)**만 지정할 수 있으므로 제공된 값으로 시작하는 첫 번째 인터페이스로 폴백(fallback)합니다.
DROIDGROUND_NUM_TEAMS 변수를 사용하면 내부적으로 애플리케이션의 동작이 약간 변경됩니다. 이 옵션이 설정된 경우:
이를 통해 네트워크 요청으로 플래그를 유출할 수 있는 챌린지에서 여러 팀이 동일한 DroidGround 인스턴스를 공유할 수 있습니다. 이는 CTF 대회에서 DroidGround 배포 비용을 대폭 절감합니다.
또한 값을 -1로 설정하면 소위 Unlimited Teams(무제한 팀) 모드가 활성화됩니다. 이 모드에서는 Overview 페이지에서 새 팀 토큰을 생성하는 버튼을 사용할 수 있습니다. 이 모드가 활성화되면 모든 DROIDGROUND_TEAM_TOKEN_<N> 변수는 무시됩니다.
DroidGround를 사용할 수 있는 몇 가지 방법은 다음과 같습니다:
examples 폴더에 몇 가지 샘플 Docker Compose 파일이 제공됩니다. 이 파일들은 DroidGround 샘플 저장소의 앱을 사용하며, 이 저장소는 모든 주요 기능을 선보이기 위해 점진적으로 개선될 예정입니다. 또한 자체 CTF를 설정하는 방법을 이해하기 위한 좋은 출발점이기도 합니다.
_DroidGround_는 부팅 시 다음을 수행합니다:
adb와의 연결을 설정합니다DROIDGROUND_INIT_SCRIPTS_FOLDER에 지정된 폴더에 setup.sh가 있으면 실행합니다. 이 스크립트는 대상 앱을 설치하고 CTF 초기화에 필요한 모든 작업(예: 알려진 위치에 플래그 배치)을 수행하는 데 사용할 수 있습니다.frida-server를 다운로드하여 시작합니다DROIDGROUND_APP_PACKAGE_NAME으로 지정된 앱)을 실행합니다. 앱이 설치되어 있지 않으면 _DroidGround_가 종료됩니다.다음은 샘플 setup.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 예제도 추가했습니다.
또는 앞서 언급한 대로 네트워크 요청을 통해 플래그를 유출할 수 있는 챌린지를 만들고 DROIDGROUND_NUM_TEAMS 환경 변수를 활용하여 (비용이 많이 들 수 있는) 여러 인스턴스 생성을 피할 수 있습니다. net-multi-step 폴더는 이러한 유형의 챌린지를 운영하는 방법에 대한 좋은 예를 제공합니다.
Android CTF를 설정할 때 유용한 몇 가지 제안 사항은 다음과 같습니다:
프로덕션에 투입하기 전에 설정을 테스트할 때 대상 앱의 **공격 표면(attack surface)**을 확인하는 것이 유용할 수 있습니다. 공격 표면을 발견하고 분석하는 것은 플레이어의 몫이므로 플레이어가 볼 수 없는 항목입니다!
따라서 /attackSurface에서 접근할 수 있는 GET 엔드포인트가 제공되며, 부팅 중에 무작위로 생성되어 로그에 출력되는(따라서 sysadmin만 접근할 수 있는) 토큰(Authorization 헤더의 값으로 사용해야 함)으로 보호됩니다.
jail 모드에서 자체 Frida 스크립트를 사용하려면 해당 스크립트가 포함된 폴더를 Docker 컨테이너에 바인드 마운트(bind-mount)하기만 하면 됩니다:
volumes:
- <Frida library folder>:/droidground/library
library에 있는 것과 같은 library.json 파일이 있어야 애플리케이션에 사용 가능한 스크립트 목록을 알릴 수 있습니다.
실행 환경을 구축하는 것은 그리 어렵지 않지만, 시작하기 전에 다음 도구가 설치되어 있어야 합니다:
frida (_Frida_를 활성화하는 경우에만)node (Node 앱이므로 반드시 필요합니다!)adb (기기와 통신하기 위해 여기에 의존합니다)그런 다음 아래 명령을 실행하기만 하면 됩니다:
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를 실행하면 됩니다. 즐거운 개발 되세요!
풀 리퀘스트는 언제나 환영합니다! 주요 변경 사항을 논의하려면 먼저 이슈를 열어 주세요. 새로운 CTF 워크플로우나 챌린지 유형에 대한 아이디어는 특히 감사히 여겨집니다.
Angelo Delicato @SECFORCE가 개발했습니다.
server 부분은 @yume-chan이 해낸 놀라운 작업에 크게 의존하고 있습니다. 그의 놀라운 작업이 없었다면 이 앱은 아마 존재하지 않았을 것입니다.
companion 앱은 scrcpy server와 동일한 방식으로 작동하는 aya server를 기반으로 합니다. 자세한 내용은 해당 README에서 확인할 수 있습니다.
_DroidGround_는 GPL-3.0 LICENSE에 따라 배포됩니다.
![]() | ![]() |
|---|
| 개요 | 액티비티 시작 |
![]() | ![]() |
| Frida Jail 모드 | Frida Full 모드 |
![]() | ![]() |
| 파일 브라우저 | 앱 관리자 |
![]() | ![]() |
| 터미널 | 로그 |
| 변수 | 설명 | 기본값 |
|---|
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 | 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 | 버그 리포트 비활성화 | 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_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 메인 페이지) | - |