Web & Mobile Application Security case study

Android Application Security Assessment: Beetlebug

Performed a controlled Android application assessment using static analysis, ADB-driven dynamic testing, storage inspection, and backend validation to identify eight security weaknesses.

Skills demonstrated

  • Mapped application resources, exported activities, embedded values, and backend URLs.
  • Pulled SQLite and Shared Preferences artifacts and verified plaintext sensitive data.
  • Monitored Logcat for credit-card and PII leakage.
  • Validated SQL injection, public Firebase access, and unauthenticated administrator activity invocation.
  • Assigned retrospective risk ratings and paired every finding with actionable remediation (see Findings Summary).

Tools used

  • JADX
  • ADB
  • Logcat
  • SQLite Browser
  • curl
  • jq
  • Android emulator

Project detail

Findings Summary

Severities and remediations below were assigned retrospectively from the documented evidence using standard OWASP/CVSS-style judgment (Critical / High / Medium / Low). They were not part of the original lab write-up.

This assessment documents 8 security weaknesses, matching the objective count.

IDIssueOWASP categorySeverityFixEvidence
BB-01Folder-unlock PIN hardcoded in strings.xmlOWASP Mobile M1:2024 Improper Credential UsageHighDo not embed secrets in resources; derive or fetch unlock secrets from a protected server-side check; obfuscation alone is insufficient.Refs 1-3
BB-02Promo code hardcoded and discount enforced client-sideOWASP Mobile M7:2024 Insufficient Binary ProtectionsMediumValidate promo codes and pricing on the server; treat the client as untrusted.Refs 4-5
BB-03Username, password and flag stored in plaintext Shared PreferencesOWASP Mobile M9:2024 Insecure Data StorageHighUse the Android Keystore / EncryptedSharedPreferences; never store passwords in plaintext preferences.Refs 6-7
BB-04Master PIN stored as readable text in local SQLite user.dbOWASP Mobile M9:2024 Insecure Data StorageHighStore only salted hashes (or server-side verification) for PINs; encrypt the database at rest if local storage is required.Refs 8-9
BB-05SQL injection returns other users' usernames, passwords and card valuesOWASP Mobile M4:2024 Insufficient Input/Output ValidationCriticalUse parameterized queries / ORM bindings; never concatenate user input into SQL; minimize sensitive columns on-device.Ref 10
BB-06Firebase Realtime Database readable without authenticationOWASP Mobile M8:2024 Security MisconfigurationCriticalLock down Firebase security rules to authenticated, authorized access; remove public .json read; audit rules in CI.Refs 11-14
BB-07Card number and flag written to LogcatOWASP Mobile M6:2024 Inadequate Privacy ControlsHighStrip PII/PAN from logs; use guarded logging levels; scrub Logcat output in release builds.Refs 15-16
BB-08Exported b33tleAdministrator activity opens the admin dashboard without authenticationOWASP Mobile M3:2024 Insecure Authentication/AuthorizationHighSet exported=false (or require a signature/permission); enforce auth inside the activity before showing admin UI.Refs 17-18

Technical walkthrough

Lab evidence and investigation steps.

Open on GitHub
Ref 1: Static analysis in JADX shows the folder-unlock PIN being compared against a resource string instead of a value generated or protected at runtime.
Ref 1: Static analysis in JADX shows the folder-unlock PIN being compared against a resource string instead of a value generated or protected at runtime.
Ref 2: The referenced value in strings.xml exposes the hardcoded unlock PIN, allowing the secret to be recovered directly from the decompiled APK.
Ref 2: The referenced value in `strings.xml` exposes the hardcoded unlock PIN, allowing the secret to be recovered directly from the decompiled APK.
Ref 3: Entering the recovered PIN unlocks the protected folder and confirms that an embedded client-side secret can be used to complete the challenge.
Ref 3: Entering the recovered PIN unlocks the protected folder and confirms that an embedded client-side secret can be used to complete the challenge.
Ref 4: The promo-code activity contains a hardcoded discount value, making the code recoverable through reverse engineering.
Ref 4: The promo-code activity contains a hardcoded discount value, making the code recoverable through reverse engineering.
Ref 5: Submitting the recovered promo code applies the discount in the application, demonstrating that the promotion logic is enforced on the client and can be abused repeatedly.
Ref 5: Submitting the recovered promo code applies the discount in the application, demonstrating that the promotion logic is enforced on the client and can be abused repeatedly.
Ref 6: Pulling shared_pref_flag.xml with ADB reveals that the application stores the submitted username, password, and flag value in plaintext Shared Preferences.
Ref 6: Pulling `shared_pref_flag.xml` with ADB reveals that the application stores the submitted username, password, and flag value in plaintext Shared Preferences.
Ref 7: The Shared Preferences challenge screen shows the same credentials entered in the app, linking the plaintext XML artifact back to user-controlled input.
Ref 7: The Shared Preferences challenge screen shows the same credentials entered in the app, linking the plaintext XML artifact back to user-controlled input.
Ref 8: ADB is used to pull user.db from the application data directory, showing that the local SQLite database is accessible for offline inspection on a test device.
Ref 8: ADB is used to pull `user.db` from the application data directory, showing that the local SQLite database is accessible for offline inspection on a test device.
Ref 9: After pulling user.db, DB Browser for SQLite shows the master PIN stored as readable text in the users table.
Ref 9: After pulling `user.db`, DB Browser for SQLite shows the master PIN stored as readable text in the `users` table.
Ref 10: A basic SQL injection payload bypasses the intended lookup and returns multiple users, including usernames, passwords, and credit-card values.
Ref 10: A basic SQL injection payload bypasses the intended lookup and returns multiple users, including usernames, passwords, and credit-card values.
Ref 11: Reviewing strings.xml also exposes the Firebase Realtime Database URL, which provides a direct backend target for access-control testing.
Ref 11: Reviewing `strings.xml` also exposes the Firebase Realtime Database URL, which provides a direct backend target for access-control testing.
Ref 12: Querying the Firebase .json endpoint with curl and formatting it with jq returns database records without authentication, confirming public read access.
Ref 12: Querying the Firebase `.json` endpoint with `curl` and formatting it with `jq` returns database records without authentication, confirming public read access.
Ref 13: The unauthenticated Firebase response includes the challenge flag and other user-submitted fields, showing the impact of the misconfigured database rules.
Ref 13: The unauthenticated Firebase response includes the challenge flag and other user-submitted fields, showing the impact of the misconfigured database rules.
Ref 14: The Firebase challenge screen explains the expected network call pattern, tying the exposed database URL to the in-app misconfiguration test.
Ref 14: The Firebase challenge screen explains the expected network call pattern, tying the exposed database URL to the in-app misconfiguration test.
Ref 15: The card number, expiry date, and CVV entered into the payment form are sensitive values that should not be persisted or emitted in application logs.
Ref 15: The card number, expiry date, and CVV entered into the payment form are sensitive values that should not be persisted or emitted in application logs.
Ref 16: Inspecting Logcat after submitting the payment form shows the card number and flag printed by the app, confirming sensitive-data leakage through logs.
Ref 16: Inspecting Logcat after submitting the payment form shows the card number and flag printed by the app, confirming sensitive-data leakage through logs.
Ref 17: The Android manifest exposes app.beetlebug.ctf.b33tleAdministrator, allowing the admin activity to be launched from outside the normal app flow.
Ref 17: The Android manifest exposes `app.beetlebug.ctf.b33tleAdministrator`, allowing the admin activity to be launched from outside the normal app flow.
Ref 18: Launching the exported component with adb shell am start -n app.beetlebug/.ctf.b33tleAdministrator opens the admin dashboard without authentication.
Ref 18: Launching the exported component with `adb shell am start -n app.beetlebug/.ctf.b33tleAdministrator` opens the admin dashboard without authentication.