-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Port MASTG-TEST-0004: App Exposing Sensitive Data to Embedded Libraries #3485
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
36 commits
Select commit
Hold shift + click to select a range
0cdcd45
Deprecate old test
Diolor 536aacb
Add mitmproxy in TECH-0108
Diolor 525a75e
Create the v2 TEST
Diolor ea8e1ed
Create a demo based on the test
Diolor 31d6209
Fix lint
Diolor 52d0619
Fix lint
Diolor 99e15f8
Fix lint
Diolor a12122a
Fix lint
Diolor 4618723
Remove prerequisite
Diolor 13118f7
Rewrite test to include frida
Diolor ff3bf25
Move to Privacy
Diolor a45c42f
Move Firebase Analytics dependency
Diolor ccb8c1c
Move Firebase Analytics dependency
Diolor 2037585
Update title to clarify sensitive information exposure in Firebase An…
Diolor 7e4ecf2
Allocate IDs
Diolor 9078204
Merge remote-tracking branch 'origin/master' into port-MASTG-TEST-0004
Diolor fab5dea
Allocate IDs
Diolor 4351d41
Update weakness reference in MASTG-TEST-0297.md
Diolor 625d6b3
Merge branch 'master' into port-MASTG-TEST-0004
cpholguera dc4e504
Merge branch 'master' into port-MASTG-TEST-0004
cpholguera 2e7adb8
Split test into 4 smaller tests.
Diolor 1d02dae
Fix id
Diolor 4dea6df
Add demo for dynamic evaluation of sensitive data in runtime
Diolor 0bc53db
Update demos/android/MASVS-PRIVACY/MASTG-DEMO-00de3/hooks.js
Diolor 1183269
Apply suggestions from code review
Diolor 64fcf89
Update references in MASTG-TEST-02te4.md and MASTG-TEST-0004.md
Diolor af21b06
Apply suggestions from code review
Diolor f91db2e
add UI automation
cpholguera 5aae326
Merge branch 'master' into port-MASTG-TEST-0004
Diolor b088cdd
Remove MASTG-DEMO-00de1
Diolor b3f7659
Refine documentation for SDK method observations and data handling tests
Diolor 2c5e4bd
Moved to #3595
Diolor 57a91ab
correct output
cpholguera f638528
Last set of minor tweaks including title updates, links to data safet…
cpholguera 3d7ee2e
fix IDs
cpholguera 8b5aca8
Merge branch 'master' into port-MASTG-TEST-0004
cpholguera File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
39 changes: 39 additions & 0 deletions
39
demos/android/MASVS-PRIVACY/MASTG-DEMO-0081/MASTG-DEMO-0081.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| --- | ||
| platform: android | ||
| title: Sensitive User Data Sent to Firebase Analytics with Frida | ||
| id: MASTG-DEMO-0081 | ||
| code: [kotlin] | ||
| test: MASTG-TEST-0319 | ||
| --- | ||
|
|
||
| ## Sample | ||
|
|
||
| This sample collects the following [sensitive user data](https://support.google.com/googleplay/android-developer/answer/10787469?hl=en#types&zippy=%2Cdata-types) and sends it to Firebase Analytics using the `logEvent` method: | ||
|
|
||
| - User ID (**Data type:** User IDs, **Category:** Personal info) | ||
| - Blood type (**Data type:** Health info, **Category:** Health and fitness) | ||
|
|
||
| For the sake of this demo, we pretend that the app is published on Google Play and that the data types collected are not disclosed in the [Data safety section](https://support.google.com/googleplay/android-developer/answer/10787469?hl=en#types&zippy=%2Cdata-types). | ||
|
|
||
| {{ MainActivity.kt # MastgTest.kt # build.gradle.kts.libs }} | ||
|
|
||
| ## Steps | ||
|
|
||
| 1. Install the app on a device (@MASTG-TECH-0005) | ||
| 2. Make sure you have @MASTG-TOOL-0001 installed on your machine and the frida-server running on the device | ||
| 3. Run `run.sh` to spawn the app with Frida | ||
| 4. Select a blood type from the dropdown | ||
| 5. Click the **Start** button | ||
| 6. Stop the script by pressing `Ctrl+C` and/or `q` to quit the Frida CLI | ||
|
|
||
| {{ hooks.js # run.sh }} | ||
|
|
||
| ## Observation | ||
|
|
||
| The output shows all instances of `logEvent` calls to the Firebase Analytics SDK found at runtime, along with the parameters sent. A backtrace is also provided to help identify the location in the code. | ||
|
|
||
| {{ output.json }} | ||
|
|
||
| ## Evaluation | ||
|
|
||
| This test **fails** because sensitive data (`blood_type` parameter) is being sent to Firebase Analytics via the `logEvent` method for a particular user (`user_id` parameter) and this data collection is not disclosed in the Data safety section on Google Play (as we indicated in the sample description). | ||
158 changes: 158 additions & 0 deletions
158
demos/android/MASVS-PRIVACY/MASTG-DEMO-0081/MainActivity.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,158 @@ | ||
| package org.owasp.mastestapp | ||
|
|
||
| import android.os.Bundle | ||
| import androidx.activity.ComponentActivity | ||
| import androidx.activity.compose.setContent | ||
| import androidx.activity.enableEdgeToEdge | ||
| import androidx.compose.foundation.layout.Column | ||
| import androidx.compose.foundation.layout.padding | ||
| import androidx.compose.material3.Button | ||
| import androidx.compose.material3.DropdownMenu | ||
| import androidx.compose.material3.DropdownMenuItem | ||
| import androidx.compose.material3.Text | ||
| import androidx.compose.runtime.Composable | ||
| import androidx.compose.runtime.getValue | ||
| import androidx.compose.runtime.mutableStateOf | ||
| import androidx.compose.runtime.remember | ||
| import androidx.compose.runtime.setValue | ||
| import androidx.compose.ui.Modifier | ||
| import androidx.compose.ui.graphics.Color | ||
| import androidx.compose.ui.platform.LocalContext | ||
| import androidx.compose.ui.platform.testTag | ||
| import androidx.compose.ui.text.AnnotatedString | ||
| import androidx.compose.ui.text.SpanStyle | ||
| import androidx.compose.ui.text.buildAnnotatedString | ||
| import androidx.compose.ui.text.font.FontFamily | ||
| import androidx.compose.ui.text.withStyle | ||
| import androidx.compose.ui.tooling.preview.Preview | ||
| import androidx.compose.ui.unit.dp | ||
| import androidx.compose.ui.unit.sp | ||
| import kotlinx.serialization.json.Json | ||
| import kotlinx.serialization.json.JsonArray | ||
| import kotlinx.serialization.json.decodeFromJsonElement | ||
|
|
||
| const val MASTG_TEXT_TAG = "mastgTestText" | ||
|
|
||
| class MainActivity : ComponentActivity() { | ||
| override fun onCreate(savedInstanceState: Bundle?) { | ||
| super.onCreate(savedInstanceState) | ||
| enableEdgeToEdge() | ||
| setContent { | ||
| MainScreen() | ||
| } | ||
| } | ||
| } | ||
|
|
||
| fun UpdateDisplayString( | ||
| defaultMessage: String, | ||
| result: String | ||
| ): AnnotatedString { | ||
| return buildAnnotatedString { | ||
| append(defaultMessage) | ||
| try { | ||
| val jsonArrayFromString = Json.parseToJsonElement(result) as JsonArray | ||
| val demoResults = jsonArrayFromString.map { Json.decodeFromJsonElement<DemoResult>(it) } | ||
|
|
||
| for (demoResult in demoResults) { | ||
| when (demoResult.status) { | ||
| Status.PASS -> { | ||
| withStyle(style = SpanStyle(color = Color.Green)) { | ||
| append("MASTG-DEMO-${demoResult.demoId} demonstrated a successful test:\n${demoResult.message}\n\n") | ||
| } | ||
| } | ||
|
|
||
| Status.FAIL -> { | ||
| withStyle(style = SpanStyle(color = Color(0xFFFF9800))) { | ||
| append("MASTG-DEMO-${demoResult.demoId} demonstrated a failed test:\n${demoResult.message}\n\n") | ||
| } | ||
| } | ||
|
|
||
| Status.ERROR -> { | ||
| withStyle(style = SpanStyle(color = Color.Red)) { | ||
| append("MASTG-DEMO-${demoResult.demoId} failed:\n${demoResult.message}\n\n") | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } catch (_: Exception) { | ||
| // not a valid set of DemoResult, so print the result without any parsing | ||
| append(result) | ||
| } | ||
| } | ||
|
|
||
| } | ||
|
|
||
| @Preview | ||
| @Composable | ||
| fun MainScreen() { | ||
| val defaultMessage = "Click \"Start\" to send the data.\n\n" | ||
| var displayString by remember { mutableStateOf(buildAnnotatedString { append(defaultMessage) }) } | ||
| var selectedBloodType by remember { mutableStateOf("") } | ||
| val context = LocalContext.current | ||
| val mastgTestClass = MastgTest(context) | ||
| // By default run the test in a separate thread, this ensures that network tests such as those using SSLSocket work properly. | ||
| // However, some tests which interact with UI elements need to run on the main thread. | ||
| // You can set shouldRunInMainThread = true in MastgTest.kt for those tests. | ||
| val runInMainThread = MastgTest::class.members | ||
| .find { it.name == "shouldRunInMainThread" } | ||
| ?.call(mastgTestClass) as? Boolean ?: false | ||
|
|
||
| BaseScreen( | ||
| onStartClick = { | ||
| if (runInMainThread) { | ||
| val result = mastgTestClass.mastgTest(selectedBloodType) | ||
| displayString = UpdateDisplayString(defaultMessage, result) | ||
| } else { | ||
| Thread { | ||
| val result = mastgTestClass.mastgTest(selectedBloodType) | ||
| android.os.Handler(android.os.Looper.getMainLooper()).post { | ||
| displayString = UpdateDisplayString(defaultMessage, result) | ||
| } | ||
| }.start() | ||
| } | ||
| } | ||
| ) { | ||
| Column(modifier = Modifier.padding(16.dp)) { | ||
| // Normal visible selection UI: list of radio buttons for blood types | ||
| val bloodTypes = listOf("A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-") | ||
|
cpholguera marked this conversation as resolved.
|
||
|
|
||
| var expanded by remember { mutableStateOf(false) } | ||
|
|
||
| Button(onClick = { expanded = !expanded }) { | ||
| Text("Select Blood Type") | ||
| } | ||
| DropdownMenu( | ||
| expanded = expanded, | ||
| onDismissRequest = { expanded = false } | ||
| ) { | ||
| bloodTypes.forEach { | ||
| DropdownMenuItem( | ||
| text = { Text(it) }, | ||
| onClick = { | ||
| selectedBloodType = it | ||
| expanded = false | ||
| } | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| if (selectedBloodType.isNotEmpty()) { | ||
| Text( | ||
| modifier = Modifier.padding(vertical = 16.dp), | ||
| color = Color.White, | ||
| text = "Selected Blood Type: $selectedBloodType" | ||
| ) | ||
| } | ||
|
|
||
| Text( | ||
| modifier = Modifier | ||
| .padding(top = 8.dp) | ||
| .testTag(MASTG_TEXT_TAG), | ||
| text = displayString, | ||
| color = Color.White, | ||
| fontSize = 16.sp, | ||
| fontFamily = FontFamily.Monospace | ||
| ) | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| package org.owasp.mastestapp | ||
|
|
||
| import android.content.Context | ||
| import com.google.firebase.analytics.FirebaseAnalytics | ||
| import com.google.firebase.analytics.logEvent | ||
| import kotlin.random.Random | ||
|
|
||
| class MastgTest(context: Context) { | ||
|
|
||
| val analytics = FirebaseAnalytics.getInstance(context) | ||
|
|
||
| // Random arbitrary number for the sake of the demo | ||
| val userId: String = (1..8).map { Random.nextInt(0, 10) }.joinToString("") | ||
|
|
||
| fun mastgTest(bloodType: String): String { | ||
| analytics.logEvent("user_blood_type") { | ||
| param("user_id", userId) | ||
| param("blood_type", bloodType) | ||
| } | ||
|
|
||
| return """ | ||
| 'user_blood_type' event was sent to Firebase Analytics. | ||
|
|
||
| User id: $userId | ||
| Blood type: $bloodType | ||
| """.trimIndent() | ||
| } | ||
| } |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| Running on Pixel_4_API_34_Manually_Created | ||
| > Flow flow | ||
| Take screenshot before... COMPLETED | ||
| Tap on "Select Blood Type"... COMPLETED | ||
| Tap on "A+"... COMPLETED | ||
| Tap on "Start"... COMPLETED | ||
| Take screenshot after... COMPLETED |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| FLOW="flow.yaml" | ||
|
|
||
| # Start Frida and redirect stdout and stderr to file | ||
| ./run.sh 2>&1 & | ||
|
|
||
| FRIDA_PID=$! | ||
|
|
||
| # Run Maestro (https://docs.maestro.dev/getting-started/installing-maestro) | ||
| maestro test "$FLOW" > auto.log 2>&1 | ||
| MAESTRO_EXIT=$? | ||
|
|
||
| # Stop Frida when Maestro completes | ||
| kill "$FRIDA_PID" 2>/dev/null || true | ||
|
|
||
| exit "$MAESTRO_EXIT" |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions
1
demos/android/MASVS-PRIVACY/MASTG-DEMO-0081/build.gradle.kts.libs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| implementation("com.google.firebase:firebase-analytics:23.0.0") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| appId: org.owasp.mastestapp | ||
| --- | ||
| #- launchApp | ||
| - takeScreenshot: before | ||
| - tapOn: "Select Blood Type" | ||
| - tapOn: "A+" | ||
| - tapOn: "Start" | ||
| - takeScreenshot: after |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| var target = { | ||
| category: "PRIVACY", | ||
| hooks: [ | ||
| { | ||
| class: "com.google.firebase.analytics.FirebaseAnalytics", | ||
| methods: [ | ||
| "logEvent" | ||
| ] | ||
| } | ||
| ] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| { | ||
| "type": "summary", | ||
| "hooks": [ | ||
| { | ||
| "class": "com.google.firebase.analytics.FirebaseAnalytics", | ||
| "method": "logEvent", | ||
| "overloads": [ | ||
| { | ||
| "args": [ | ||
| "java.lang.String", | ||
| "android.os.Bundle" | ||
| ] | ||
| } | ||
| ] | ||
| } | ||
| ], | ||
| "totalHooks": 1, | ||
| "errors": [], | ||
| "totalErrors": 0 | ||
| } | ||
| { | ||
| "id": "68f13e77-c2aa-4778-be90-fc7a5c50af60", | ||
| "type": "hook", | ||
| "category": "PRIVACY", | ||
| "time": "2025-12-04T14:03:05.046Z", | ||
| "class": "com.google.firebase.analytics.FirebaseAnalytics", | ||
| "method": "logEvent", | ||
| "instanceId": 33276343, | ||
| "stackTrace": [ | ||
| "com.google.firebase.analytics.FirebaseAnalytics.logEvent(Native Method)", | ||
| "org.owasp.mastestapp.MastgTest.mastgTest(MastgTest.kt:35)", | ||
| "org.owasp.mastestapp.MainActivityKt.MainScreen$lambda$15$lambda$14(MainActivity.kt:107)", | ||
| "org.owasp.mastestapp.MainActivityKt.$r8$lambda$REihytfpbfdEl1cb3dLDlSFXk5M(Unknown Source:0)", | ||
| "org.owasp.mastestapp.MainActivityKt$$ExternalSyntheticLambda2.run(D8$$SyntheticClass:0)", | ||
| "java.lang.Thread.run(Thread.java:1119)" | ||
| ], | ||
| "inputParameters": [ | ||
| { | ||
| "declaredType": "java.lang.String", | ||
| "value": "user_blood_type" | ||
| }, | ||
| { | ||
| "declaredType": "android.os.Bundle", | ||
| "value": "<instance: android.os.Bundle>", | ||
| "runtimeType": "android.os.Bundle", | ||
| "instanceId": "130116900", | ||
| "instanceToString": "Bundle[{blood_type=A+, user_id=87495975}]" | ||
| } | ||
| ], | ||
| "returnValue": [ | ||
| { | ||
| "declaredType": "void", | ||
| "value": "void" | ||
| } | ||
| ] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| #!/bin/bash | ||
| ../../../../utils/frida/android/run.sh ./hooks.js |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| --- | ||
| platform: android | ||
| title: References to SDK APIs Known to Handle Sensitive User Data | ||
| id: MASTG-TEST-0318 | ||
| type: [static] | ||
| weakness: MASWE-0112 | ||
| profiles: [P] | ||
| --- | ||
|
|
||
| ## Overview | ||
|
|
||
| This test verifies whether an app uses SDK (third-party library) APIs known to handle sensitive user data (e.g., as defined in [Google Play's Data safety section](https://support.google.com/googleplay/android-developer/answer/10787469?hl=en#types&zippy=%2Cdata-types) or the relevant privacy regulations). | ||
|
|
||
| As a prerequisite, we need to identify the SDK API methods it uses as entry points for data collection by reviewing the library's documentation or codebase. For example, [Google Analytics for Firebase](https://firebase.google.com/docs/analytics) in its class `FirebaseAnalytics` provides methods such as [`setUserId`](https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics#setUserId(java.lang.String)), [`setUserProperty`](https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics#setUserProperty(java.lang.String,%20java.lang.String)), and [`logEvent`](https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics#logEvent(java.lang.String,%20android.os.Bundle)) that can be used to collect user data. | ||
|
|
||
| > Note: This test detects only **potential** sensitive user data handling. For **confirming** that actual user data are being shared, please refer to @MASTG-TEST-0319. | ||
|
|
||
| ## Steps | ||
|
|
||
| 1. Use @MASTG-TECH-0013 to reverse engineer the app. | ||
| 2. Use @MASTG-TECH-0014 to look for uses of these methods where sensitive user data may be passed to the SDK. | ||
|
|
||
| ## Observation | ||
|
|
||
| The output should list the locations where SDK methods are called. | ||
|
|
||
| ## Evaluation | ||
|
|
||
| The test case fails if you can find the use of these SDK methods in the app code, indicating that the app is sharing sensitive user data with the third-party SDK. If no such references are found, the test case passes. |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.