-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
base: master
Are you sure you want to change the base?
Changes from 8 commits
0cdcd45
536aacb
525a75e
ea8e1ed
31d6209
52d0619
99e15f8
a12122a
4618723
13118f7
ff3bf25
a45c42f
ccb8c1c
2037585
7e4ecf2
9078204
fab5dea
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
--- | ||
platform: android | ||
title: App leaking sensitive information to Firebase Analytics | ||
id: MASTG-DEMO-yyyy | ||
code: [kotlin] | ||
test: MASTG-TEST-xxxx | ||
--- | ||
|
||
## Sample | ||
|
||
This sample demonstrates an Android application that inadvertently leaks sensitive user information to Firebase Analytics. The app collects various types of sensitive data, such as user IDs, email addresses, and names, and sends this information to Firebase Analytics. | ||
|
||
> Note: To compile the test correctly, you need to include the Firebase Analytics library in the `build.gradle` file. i.e.`implementation("com.google.firebase:firebase-analytics:23.0.0")`. | ||
|
||
{{ MastgTest.kt }} | ||
|
||
## Steps | ||
|
||
Let's run our @MASTG-TOOL-0110 rule against the reversed Java code. | ||
|
||
{{ ../../../../rules/mastg-android-sensitive-data-to-embedded-firebase-analytics.yml }} | ||
|
||
{{ run.sh }} | ||
|
||
## Observation | ||
|
||
The rule detected 8 instances where sensitive data might be sent to Firebase Analytics. The findings include various types of sensitive information, such as user IDs, email addresses, and names, based on the rule's defined pattern. | ||
|
||
{{ output.txt }} | ||
|
||
## Evaluation | ||
|
||
After reviewing the decompiled code at the location specified in the output (file and line number), we can conclude that the test fails because the file written by this instance contains sensitive information, specifically a first and a last name, an email, a user ID, and a secret. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package org.owasp.mastestapp | ||
|
||
import android.content.Context | ||
import android.os.Bundle | ||
import com.google.firebase.analytics.FirebaseAnalytics | ||
|
||
class MastgTest(private val context: Context) { | ||
|
||
fun mastgTest(): String { | ||
val sensitiveString = "d3a447630194bd4b" | ||
val email = "user@example.com" | ||
val firstLast = "John Doe" | ||
val arbitraryUserId = "user12345" | ||
|
||
val analytics = FirebaseAnalytics.getInstance(context) | ||
|
||
// Test 1: logEvent with bundle | ||
val eventBundle = Bundle().apply { | ||
putString("user_email", email) | ||
putString("full_name", firstLast) | ||
} | ||
analytics.logEvent("event_name", eventBundle) | ||
|
||
// Test 2: setUserProperty | ||
analytics.apply { | ||
setUserProperty("name", firstLast) | ||
setUserProperty("email", email) | ||
} | ||
|
||
// Test 3: setUserId | ||
analytics.setUserId(arbitraryUserId) | ||
|
||
// Test 4: setDefaultEventParameters | ||
val defaultBundle = Bundle().apply { | ||
putString("default_key", sensitiveString) | ||
} | ||
analytics.setDefaultEventParameters(defaultBundle) | ||
|
||
return """Sensitive data: | ||
Email: $email | ||
Full Name: $firstLast | ||
User ID: $arbitraryUserId | ||
Sensitive String: $sensitiveString | ||
""".trimIndent() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package org.owasp.mastestapp; | ||
|
||
import android.content.Context; | ||
import android.os.Bundle; | ||
import com.google.firebase.analytics.FirebaseAnalytics; | ||
import kotlin.Metadata; | ||
import kotlin.jvm.internal.Intrinsics; | ||
import kotlin.text.StringsKt; | ||
|
||
/* compiled from: MastgTest.kt */ | ||
@Metadata(d1 = {"\u0000\u0018\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0003\n\u0002\u0010\u000e\n\u0000\b\u0007\u0018\u00002\u00020\u0001B\u000f\u0012\u0006\u0010\u0002\u001a\u00020\u0003¢\u0006\u0004\b\u0004\u0010\u0005J\u0006\u0010\u0006\u001a\u00020\u0007R\u000e\u0010\u0002\u001a\u00020\u0003X\u0082\u0004¢\u0006\u0002\n\u0000¨\u0006\b"}, d2 = {"Lorg/owasp/mastestapp/MastgTest;", "", "context", "Landroid/content/Context;", "<init>", "(Landroid/content/Context;)V", "mastgTest", "", "app_debug"}, k = 1, mv = {2, 0, 0}, xi = 48) | ||
/* loaded from: classes3.dex */ | ||
public final class MastgTest { | ||
public static final int $stable = 8; | ||
private final Context context; | ||
|
||
public MastgTest(Context context) { | ||
Intrinsics.checkNotNullParameter(context, "context"); | ||
this.context = context; | ||
} | ||
|
||
public final String mastgTest() { | ||
FirebaseAnalytics analytics = FirebaseAnalytics.getInstance(this.context); | ||
Intrinsics.checkNotNullExpressionValue(analytics, "getInstance(...)"); | ||
Bundle eventBundle = new Bundle(); | ||
eventBundle.putString("user_email", "user@example.com"); | ||
eventBundle.putString("full_name", "John Doe"); | ||
analytics.logEvent("event_name", eventBundle); | ||
analytics.setUserProperty("name", "John Doe"); | ||
analytics.setUserProperty("email", "user@example.com"); | ||
analytics.setUserId("user12345"); | ||
Bundle defaultBundle = new Bundle(); | ||
defaultBundle.putString("default_key", "d3a447630194bd4b"); | ||
analytics.setDefaultEventParameters(defaultBundle); | ||
return StringsKt.trimIndent("Sensitive data:\n\t\t\tEmail: user@example.com\n\t\t\tFull Name: John Doe\n\t\t\tUser ID: user12345\n\t\t\tSensitive String: d3a447630194bd4b\n\t\t\t"); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
|
||
|
||
┌─────────────────┐ | ||
│ 8 Code Findings │ | ||
└─────────────────┘ | ||
|
||
MastgTest_reversed.java | ||
❯❱ rules.mastg-android-sensitive-data-to-embedded-firebase-analytics | ||
[MASVS-PLATFORM-2] Sensitive data is being sent to Firebase Analytics | ||
|
||
26┆ eventBundle.putString("user_email", "user@example.com"); | ||
⋮┆---------------------------------------- | ||
27┆ eventBundle.putString("full_name", "John Doe"); | ||
⋮┆---------------------------------------- | ||
28┆ analytics.logEvent("event_name", eventBundle); | ||
⋮┆---------------------------------------- | ||
29┆ analytics.setUserProperty("name", "John Doe"); | ||
⋮┆---------------------------------------- | ||
30┆ analytics.setUserProperty("email", "user@example.com"); | ||
⋮┆---------------------------------------- | ||
31┆ analytics.setUserId("user12345"); | ||
⋮┆---------------------------------------- | ||
33┆ defaultBundle.putString("default_key", "d3a447630194bd4b"); | ||
⋮┆---------------------------------------- | ||
34┆ analytics.setDefaultEventParameters(defaultBundle); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
NO_COLOR=true semgrep -c ../../../../rules/mastg-android-sensitive-data-to-embedded-firebase-analytics.yml ./MastgTest_reversed.java > output.txt |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
rules: | ||
- id: mastg-android-sensitive-data-to-embedded-firebase-analytics | ||
severity: WARNING | ||
languages: [java] | ||
metadata: | ||
summary: "Detects sensitive data being sent to Firebase Analytics." | ||
message: "[MASVS-PLATFORM-2] Sensitive data is being sent to Firebase Analytics" | ||
mode: taint | ||
pattern-sources: | ||
- patterns: | ||
- pattern: '"$SECRET"' | ||
- metavariable-analysis: | ||
metavariable: $SECRET | ||
analyzer: entropy | ||
- patterns: | ||
- pattern: '"$EMAIL"' | ||
- metavariable-regex: | ||
metavariable: $EMAIL | ||
regex: (?i)[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,} | ||
- patterns: | ||
- pattern: '"$FULLNAME"' | ||
- metavariable-regex: | ||
metavariable: $FULLNAME | ||
regex: (?i)[A-Z][a-z]+ [A-Z][a-z]+ | ||
- patterns: | ||
- pattern: '"$UID"' | ||
- metavariable-regex: | ||
metavariable: $UID | ||
regex: (?i)user[0-9]+ | ||
pattern-sinks: | ||
- pattern: $FA.logEvent($EVT, $ARG) | ||
- pattern: $FA.setUserProperty($NAME, $ARG) | ||
- pattern: $FA.setUserId($ARG) | ||
- pattern: $FA.setDefaultEventParameters($ARG) | ||
- pattern: $BUNDLE.putString($K, $V) | ||
pattern-inside: | | ||
...; | ||
$FA.logEvent($EVT, $BUNDLE); | ||
...; | ||
pattern-propagators: | ||
- pattern: $BUNDLE.putString($K, $V) | ||
from: $V | ||
to: $BUNDLE |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
--- | ||
platform: android | ||
title: Sensitive Data Leaked via Embedded Libraries | ||
id: MASTG-TEST-xxxx // TODO | ||
type: [static, dynamic] | ||
weakness: MASWE-xxxA // TODO see https://github.com/OWASP/maswe/pull/11 | ||
prerequisites: | ||
- identify-sensitive-data | ||
- identify-embedded-libraries-with-network-access // TODO makes sense? get feedback | ||
profiles: [L1, L2] | ||
--- | ||
|
||
## Overview | ||
|
||
This test case focuses on identifying potentially sensitive data inadvertently leaked through embedded third-party libraries used by the application. For example, an app might use a third-party analytics SDK to track user behavior, but if the SDK is not properly configured, it could inadvertently send sensitive information (like PIIs - Personal Identifiable Information, or secrets) to that third-party service. | ||
|
||
## Steps | ||
|
||
1. Generate an SBOM. | ||
- For black-box testing, you can use tools like @MASTG-TOOL-0130 or @MASTG-TOOL-0134 with @MASG-TECH-0130 or @MASTG-TECH-0131 to identify all embedded/3rd-party libraries used by the app. | ||
- For grey/white-box testing, you can manually review the app's build files (like `build.gradle`) to identify dependencies. | ||
2. Shortlist the embedded/3rd-party libraries' APIs which have network functionality and that should not handle sensitive information. Look for permissions like `INTERNET` or `ACCESS_NETWORK_STATE`. | ||
- For black-box testing, you can research those libraries online or their codebase to see if they have network functionality. | ||
- For gray/white-box testing, you can manually review the app's merged manifest file in Android Studio or by manually generating with a command like `./gradlew app:processDebugManifest` and then inspecting the file in `app/build/intermediates/merged_manifests/debug/AndroidManifest.xml`. If possible, you can review the app's codebase. | ||
|
||
3. Identify common APIs of those libraries that are used to send data to their servers. | ||
- Use @MASTG-TECH-0110, potentially with @MASTG-TOOL-0108, to identify sensitive data pass to the APIs. | ||
- Alternatively use you can perform dynamic analysis by intercepting traffic using @MASTG-TECH-0120 and @MASTG-TECH-0121. Once you route the traffic through the interception proxy, you can try to sniff the traffic that passes between the app and app's known servers. All app requests that aren't sent directly to the app's server on which the main function is hosted should be evaluated. | ||
|
||
|
||
## Observation | ||
|
||
The output should contain a list of locations where sensitive information is passed to embedded/3rd-party libraries or a list of network requests to third-party servers that contain sensitive information. | ||
|
||
## Evaluation | ||
|
||
The test case fails if sensitive data is found to be passed to embedded/3rd-party libraries that have network functionality or if network requests to third-party servers contain sensitive information. |
Uh oh!
There was an error while loading. Please reload this page.