Skip to content

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

VulnLabApp (Android)

An intentionally vulnerable Android application for learning and practising Android mobile security testing. Every vulnerability is deliberately introduced — each class carries a comment explaining what is broken, why it matters, and what the fix looks like.

Companion to the my Android blog series.


Requirements

Tool Version
Android Studio Hedgehog (2023.1) or later
compileSdk 34
minSdk 21 (Android 5.0)
targetSdk 28 (intentional — enables legacy storage and file:// chain reproduction)
Device / Emulator Physical device recommended for Frida-based labs

No third-party product SDKs. Builds clean from Android Studio or the Gradle wrapper.


Build and run

git clone https://github.com/nirajkharel/VulnLabApp.git
cd VulnLabApp
./gradlew assembleDebug

Install on a connected device or running emulator:

adb install app/build/outputs/apk/debug/app-debug.apk
adb shell am start -n com.vulnlab.app/.MainActivity

For dynamic analysis with Frida, push frida-server to a rooted device and attach:

adb push frida-server /data/local/tmp/
adb shell "chmod 755 /data/local/tmp/frida-server && /data/local/tmp/frida-server &"
frida -U -f com.vulnlab.app -l your-script.js

App structure

app/src/main/
├── AndroidManifest.xml                        # Exported components, permissions, providers
├── java/com/vulnlab/app/
│   ├── MainActivity.java                      # Entry point, menu
│   ├── VulnApplication.java                   # Application class
│   ├── activities/
│   │   ├── LoginActivity.java                 # Auth, SharedPreferences, PII logging
│   │   ├── WebViewActivity.java               # WebView, JS bridge, SSRF, file:// read
│   │   ├── CryptoActivity.java                # Weak crypto (ECB, hardcoded IV, weak key)
│   │   ├── KeystoreActivity.java              # Keystore without auth binding
│   │   ├── CommandInjectionActivity.java      # Runtime.exec with user input
│   │   ├── IntentRedirectorActivity.java      # Intent redirection, Parcelable hijack
│   │   ├── FileWriteActivity.java             # Arbitrary file write via intent
│   │   ├── DynamicCodeActivity.java           # DexClassLoader from /sdcard/
│   │   ├── ReflectionActivity.java            # Class.forName from intent extra
│   │   ├── OAuthCallbackActivity.java         # OAuth code/token logging, CSRF, JWT fragment leak
│   │   ├── StreamUriActivity.java             # openInputStream on caller-supplied URI
│   │   ├── FileProviderActivity.java          # Overbroad FileProvider root path
│   │   ├── ProviderGrantActivity.java         # takePersistableUriPermission escalation
│   │   ├── ShareSecretActivity.java           # Persistent URI grant on private provider
│   │   ├── NotificationActivity.java          # Mutable PendingIntent, notification spoofing
│   │   ├── TaskHijackActivity.java            # StrandHogg task hijacking
│   │   ├── NetworkActivity.java               # HostnameVerifier bypass, NSC misconfiguration
│   │   ├── VulnPreferenceActivity.java        # Fragment injection
│   │   ├── NavHostActivity.java               # Navigation component unvalidated arguments
│   │   ├── DetectionActivity.java             # Root / Frida / debugger detection
│   │   ├── DeepLinkActivity.java              # App Link without autoVerify
│   │   ├── CrossAppClassLoaderActivity.java   # Cross-app ClassLoader Parcelable (Valsamaras)
│   │   ├── PlayIntegrityActivity.java         # Play Integrity local decode bypass
│   │   ├── CordovaBridgeActivity.java         # Cordova bridge exec / readFile from JS
│   │   ├── ReactNativeBridgeActivity.java     # React Native NativeModule inspection
│   │   ├── ImplicitBroadcastActivity.java     # Implicit broadcast / sticky broadcast leak
│   │   ├── StickyBroadcastActivity.java       # Sticky broadcast eavesdropping
│   │   ├── WeakPermissionActivity.java        # Weak custom permission (normal level)
│   │   └── JanusInfoActivity.java             # Janus v1 signing info
│   ├── providers/
│   │   ├── VulnContentProvider.java           # Path traversal, SQL injection
│   │   └── SecretProvider.java                # Private provider reachable via mutable PI grant
│   ├── receivers/
│   │   ├── ImplicitBroadcastReceiver.java     # No permission on exported receiver
│   │   ├── WeakPermissionReceiver.java        # Receiver behind normal-level permission
│   │   └── BootReceiver.java                  # Sends sticky broadcast on BOOT_COMPLETED
│   └── services/
│       └── AlarmService.java                  # Fires mutable PendingIntent
└── res/
    └── xml/
        ├── network_security_config.xml        # NSC misconfiguration
        └── file_paths.xml                     # FileProvider root path = "/"

Vulnerabilities

WebView

ID Location Description
webview-file-scheme-arbitrary-read WebViewActivity setAllowFileAccessFromFileURLs(true) — JS loaded from a file:// URL can fetch() any file on the device
javascript-interface-rce WebViewActivity addJavascriptInterface exposes exec(String) and readFile(String) to any JS in the WebView
cookie-manager-cross-origin WebViewActivity CookieManager.setAcceptThirdPartyCookies(true) — third-party iframes receive session cookies
http-fetch-ssrf-android WebViewActivity JS bridge fetch() method issues arbitrary HTTP requests server-side using the app's credentials
jwt-token-fragment-leak OAuthCallbackActivity Access token appended to a URL fragment and passed to WebViewActivity, where it lands in the fragment and may be forwarded to subresources

Intent and IPC

ID Location Description
intent-redirection-arbitrary-activity-launch IntentRedirectorActivity getParcelableExtra("next_intent") forwarded to startActivity() without component validation — any exported component reachable
parcelable-redirection IntentRedirectorActivity Caller-supplied Parcelable deserialized before the caller's identity is checked — gadget-chain entry point
stream-uri-read StreamUriActivity openInputStream called on a URI from getIntent() with no allowlist — attacker reads private content provider data
file-write-via-intent FileWriteActivity Filename and content taken from intent extras and written to the filesystem without path canonicalization
reflection-class-loading-intent ReflectionActivity Class.forName(intent.getStringExtra("class_name")) — attacker triggers static initializers or constructor side-effects on any class
cross-app-classloader-parcelable CrossAppClassLoaderActivity Parcelable deserialization using the caller app's ClassLoader (Valsamaras BH EU 2024) — attacker-controlled class instantiated

Content providers

ID Location Description
content-provider-path-traversal VulnContentProvider openFile() builds a path from the URI segment without normalization — ../ traverses outside the intended directory
content-resolver-sql-injection VulnContentProvider query() concatenates the caller's selection argument directly into an SQL query — full SQL injection
file-provider-overbroad-root-path FileProviderActivity, file_paths.xml FileProvider <root-path path="/" /> — any file on the device shareable via a content URI
provider-grant-escalation ProviderGrantActivity, ShareSecretActivity takePersistableUriPermission retained after the granting activity finishes; direction B hands callers a persistent read grant on the private SecretProvider

Broadcasts

ID Location Description
implicit-broadcast-leak ImplicitBroadcastActivity, ImplicitBroadcastReceiver Session token, login status, and OAuth tokens sent in implicit broadcasts with no android:permission — any app receives them
sticky-broadcast-eavesdropping StickyBroadcastActivity, BootReceiver sendStickyBroadcast persists OAuth tokens in system memory; any app calling registerReceiver(null, filter) receives the last value immediately

PendingIntent

ID Location Description
mutable-pending-intent-hijack NotificationActivity, AlarmService FLAG_MUTABLE PendingIntent built from a target intent — receiver can modify extras or action before it fires; Tier 2 variant uses an empty base intent, allowing a NotificationListenerService to fill in all fields and steal a URI grant on SecretProvider

Cryptography

ID Location Description
android-crypto-misuse CryptoActivity AES/ECB mode; hardcoded static IV for CBC; password used directly as key material without KDF; MD5 for integrity; SecureRandom seeded with a fixed value
android-keystore-without-auth-binding KeystoreActivity KeyStore key generated without setUserAuthenticationRequired(true) — usable without biometric or PIN, survives screen-lock bypass

Network

ID Location Description
hostname-verifier-bypass NetworkActivity Custom HostnameVerifier returns true for all hostnames — MITM with any certificate accepted
nsc-trust-anchors-override network_security_config.xml User-installed CA certificates trusted for all domains; cleartextTrafficPermitted="true" for api.vulnlabapp.example.com

Authentication and session

ID Location Description
mobile-oauth-intent-redirect OAuthCallbackActivity OAuth authorization code and tokens logged to Logcat — readable by any app with READ_LOGS; state parameter never validated (CSRF)
logging-pii-in-release LoginActivity Log.d emits email, password, and session token in the release build

Deep links and URL schemes

ID Location Description
app-link-autoverify-false DeepLinkActivity android:autoVerify intentionally omitted from the https:// intent filter — any app can register the same scheme and intercept the link
nav-component-complementary-argument NavHostActivity Navigation Safe Args destination receives an argument from the deep-link URI without validation — arbitrary fragment or destination reachable

Code execution

ID Location Description
command-injection-android CommandInjectionActivity User input concatenated into Runtime.getRuntime().exec() — shell command injection
dynamic-code-loading DynamicCodeActivity DexClassLoader loads a .dex from a caller-supplied /sdcard/ path — arbitrary code execution
cordova-ionic-bridge-rce CordovaBridgeActivity Fake Cordova exec() bridge exposes System.exec and FileSystem.readFile to any JS loaded in the WebView
react-native-bridge-inspection ReactNativeBridgeActivity Simulated @ReactMethod SystemModule.exec and AuthModule.getStoredToken callable from JS — shell execution and token exfiltration

Anti-analysis and detection

ID Location Description
root-detection-bypass-methodology DetectionActivity Filesystem, su binary, and package-manager checks — all bypassable with Frida hooks
frida-detection-bypass-methodology DetectionActivity /proc/self/maps scan for frida and port 27042 probe — bypassable by patching the scan
anti-frida-anti-debug-methodology DetectionActivity TracerPid read from /proc/self/status and ptrace(PTRACE_TRACEME) self-attach check

Build and signing

ID Location Description
debuggable-release-build build.gradle debuggable true in the release build type — ADB debugging and Frida attach work without a rooted device
no-obfuscation build.gradle minifyEnabled false in release — full class and method names visible in apktool or jadx output
janus-v1-signing JanusInfoActivity APK signed with v1 only (no v2/v3) on devices running Android 5.0–7.x — Janus vulnerability allows prepending a DEX to the APK without invalidating the signature

Miscellaneous

ID Location Description
fragment-injection VulnPreferenceActivity PreferenceActivity.isValidFragment() returns true for all fragments — attacker launches any Fragment class as a privileged activity
task-hijacking-strandhogg TaskHijackActivity No taskAffinity or launchMode restriction on the main task — an attacker app with a matching affinity and singleTask intercepts the next launcher tap
weak-protection-custom-permission AndroidManifest.xml, WeakPermissionActivity, WeakPermissionReceiver com.vulnlab.app.SENSITIVE_ACTION declared with protectionLevel="normal" — any installed app can request and receive this permission without user confirmation
play-integrity-bypass PlayIntegrityActivity Simulated Play Integrity verdict decoded locally from a static token with no signature verification — verdict trivially spoofed

Disclaimer

This application is for educational and security research purposes only. All hardcoded values (bundle IDs, API keys, endpoints) are fictional. Do not install on a production device or distribute outside a lab environment.

About

Lab for android application pentesting

Resources

Stars

8 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages