-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Add Tests and Demos about "Sensitive Data Stored Unencrypted via SQLite" #3534
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 5 commits
6bc899e
dbc2643
640c3f2
2e1c845
326e445
d9fc682
5dd5634
f413d42
4a53c5e
de2f3e2
6cd521d
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 |
|---|---|---|
| @@ -1,9 +1,35 @@ | ||
| --- | ||
| platform: android | ||
| title: Reserved for MASWE-0006 - Unencrypted SQLite Storage (Alternative Demo) | ||
| title: Sensitive Data in Unencrypted SQLite | ||
| id: MASTG-DEMO-0068 | ||
| code: [kotlin] | ||
| test: MASTG-TEST-0304 | ||
|
macik09 marked this conversation as resolved.
|
||
| status: placeholder | ||
| note: This placeholder reserves the ID for a potential alternative or expanded demo related to unencrypted SQLite storage, linked to the MASTG-TEST-0304 test case. | ||
| status: new | ||
| --- | ||
|
|
||
| ### Sample | ||
|
|
||
| The snippet below shows sample code that uses the default SQLite API (`context.openOrCreateDatabase`) to store sensitive data, including PII and an access token, without any encryption. | ||
|
|
||
| {{ MastgTest.kt }} | ||
|
|
||
| ### Steps | ||
|
|
||
| 1. Install the app on a device (@MASTG-TECH-0005) | ||
| 2. Make sure you have @MASTG-TOOL-0004 installed on your machine | ||
| 3. Click the **Start** button | ||
| 4. Execute `run.sh`. | ||
|
|
||
| The script `run.sh` pulls the database file (`PrivateUnencryptedData.db`) and queries its content: | ||
|
|
||
| {{ run.sh }} | ||
|
|
||
| ### Observation | ||
|
|
||
| The output contains the extracted content from the `Users` table, showing the sensitive PII (email address) and the access token stored in **plaintext**. | ||
|
|
||
| {{ output.txt }} | ||
|
|
||
| ### Evaluation | ||
|
|
||
| This test fails because the app uses the standard SQLite API to store sensitive data, specifically an access token (secret) and the user's email address (PII), in its sandbox without additional encryption. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| package org.owasp.mastestapp | ||
|
|
||
| import android.content.Context | ||
| import android.database.sqlite.SQLiteDatabase | ||
| import android.util.Log | ||
|
|
||
| class MastgTest (private val context: Context){ | ||
|
|
||
|
|
||
| fun writeSensitiveDataToUnencryptedSQLite() { | ||
| val username = "demoUser_sqlite" | ||
| val userEmail = "john.doe@maswe-0006.com" | ||
| val accessToken = "ghp_1234567890abcdefghijklmnopqrstuvABCD" | ||
| val dbName = "PrivateUnencryptedData" | ||
|
|
||
| try { | ||
| val db: SQLiteDatabase = context.openOrCreateDatabase( | ||
| dbName, | ||
| Context.MODE_PRIVATE, | ||
| null | ||
| ) | ||
|
|
||
| db.execSQL("CREATE TABLE IF NOT EXISTS Users(Username VARCHAR, Email VARCHAR, Token VARCHAR);") | ||
|
|
||
|
|
||
| db.execSQL("DELETE FROM Users;") | ||
|
|
||
| db.execSQL("INSERT INTO Users VALUES('$username', '$userEmail', '$accessToken');") | ||
|
|
||
| db.close() | ||
| Log.i("MASTG-SQLITE", "Data written to unencrypted database: $dbName. Ready for ADB extraction.") | ||
|
|
||
| } catch (e: Exception) { | ||
| Log.e("MASTG-SQLITE", "Error writing data to SQLite: ${e.message}") | ||
| } | ||
| } | ||
|
|
||
| fun mastgTest(): String { | ||
| writeSensitiveDataToUnencryptedSQLite() | ||
| return "SQLite Demo Complete. Database 'PrivateUnencryptedData' created with PII and Token." | ||
| } | ||
| } |
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This Java file does not seem to be the Java file resulting from decompiling the DEMO app. As commented previously, follow the DEMO guidelines (https://mas.owasp.org/contributing/writing-content/mastg-demo.instructions/) to provide these files accordingly. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package org.owasp.mastestapp; | ||
|
|
||
| import android.content.Context; | ||
| import android.util.Log; | ||
| import kotlin.Metadata; | ||
| import kotlin.jvm.internal.Intrinsics; | ||
|
|
||
| /* 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() throws Exception { | ||
| DemoResults r = new DemoResults("0000"); | ||
| try { | ||
| Log.d("MASTG-TEST", "Hello from the OWASP MASTG Test app."); | ||
| r.add(Status.PASS, "The app implemented a demo which passed the test with the following value: 'Hello from the OWASP MASTG Test app.'"); | ||
| r.add(Status.FAIL, "The app implemented a demo which failed the test."); | ||
| throw new Exception("Example exception: Method not implemented."); | ||
| } catch (Exception e) { | ||
| r.add(Status.ERROR, e.toString()); | ||
| return r.toJson(); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| --- Users Table Content --- | ||
| demoUser_sqlite|john.doe@maswe-0006.com|MASTG_ACCESS_TOKEN_B4C8D2F0E7A |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| #!/bin/bash | ||
|
macik09 marked this conversation as resolved.
|
||
|
|
||
| PACKAGE="org.owasp.mastestapp" | ||
| DB_NAME="PrivateUnencryptedData" | ||
| DB_PATH="/data/data/$PACKAGE/databases/$DB_NAME" | ||
| SDCARD_PULL_PATH="/sdcard/$DB_NAME.db" | ||
| OUTPUT_DB_FILE="${DB_NAME}.db" | ||
| OUTPUT_TXT_FILE="output.txt" | ||
|
|
||
| # Copy Database to the sdcard | ||
| if ! adb shell "run-as $PACKAGE cp databases/$DB_NAME $SDCARD_PULL_PATH"; then | ||
| echo "run-as failed, trying su" | ||
| adb shell "su 0 sh -c 'cp $DB_PATH $SDCARD_PULL_PATH'" | ||
| fi | ||
|
|
||
| # Pull the file to the host machine | ||
| adb pull "$SDCARD_PULL_PATH" . | ||
|
|
||
| echo "--- Users Table Content ---" > $OUTPUT_TXT_FILE | ||
| sqlite3 "$OUTPUT_DB_FILE" "SELECT * FROM Users;" >> $OUTPUT_TXT_FILE | ||
|
|
||
| adb shell "rm $SDCARD_PULL_PATH" 2>/dev/null | ||
| rm $OUTPUT_DB_FILE 2>/dev/null | ||
|
macik09 marked this conversation as resolved.
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,66 @@ | ||
| --- | ||
| title: Sensitive Data Stored Unencrypted via SQLite | ||
| platform: android | ||
| title: Sensitive Data Stored Unencrypted via SQLite | ||
| id: MASTG-TEST-0304 | ||
| type: [static, dynamic] | ||
| weakness: MASWE-0006 | ||
| best-practices: [] | ||
| best-practices: [MASTG-BEST-0074] | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add a new MASTG-BEST file for this. I think you just need one for all these PRs where you cover the best practices for MASWE-0006 on Android
|
||
| profiles: [L1, L2] | ||
| status: placeholder | ||
| note: This test checks if the app uses the default SQLite API (e.g., `SQLiteOpenHelper`, `context.openOrCreateDatabase`) to store sensitive data (e.g., tokens, PII) in an unencrypted database file within the app's sandbox. It confirms the absence of secure alternatives like SQLCipher or encrypted databases. | ||
| status: new | ||
| --- | ||
|
|
||
| ## Overview | ||
|
|
||
| This test verifies whether an app stores sensitive data — such as tokens, credentials, or personally identifiable information (PII) — in SQLite databases without encryption. | ||
|
macik09 marked this conversation as resolved.
Outdated
|
||
| SQLite databases created using APIs like `SQLiteOpenHelper` or `context.openOrCreateDatabase` are not encrypted by default. | ||
| The goal of this test is to determine whether the app relies on plaintext SQLite storage instead of secure alternatives (e.g., SQLCipher or encrypted database frameworks). | ||
|
|
||
| --- | ||
|
|
||
| ## Steps | ||
|
|
||
| ### Static Analysis | ||
|
|
||
| 1. Obtain the application package (e.g., APK file) using @MASTG-TECH-0003. | ||
|
|
||
| 2. Use a static analysis technique (@MASTG-TECH-0014) to review the code and identify references to SQLite APIs such as: | ||
| - `SQLiteOpenHelper` | ||
| - `context.openOrCreateDatabase` | ||
| - `SQLiteDatabase#insert`, `query`, `execSQL`, etc. | ||
|
|
||
| 3. Review database creation and insertion logic to determine whether: | ||
| - the database is created using default (unencrypted) SQLite, | ||
| - no encryption layer or secure wrapper is applied (e.g., SQLCipher), | ||
| - sensitive fields (tokens, secrets, PII) are inserted without transformation or protection. | ||
|
|
||
| ### Dynamic Analysis | ||
|
|
||
| 1. Install and run the app on a rooted or emulated device (@MASTG-TECH-0005). | ||
|
|
||
| 2. Trigger app functionality that processes or stores sensitive data. | ||
|
|
||
| 3. Access the app's private storage and locate SQLite database files (e.g., files with `db`, `sqlite`, `sqlite3`). This requires accessing the app data directories (@MASTG-TECH-0008). | ||
|
|
||
| 4. Extract the database file from the device to the host machine using @MASTG-TECH-0003. | ||
|
|
||
| 5. Inspect the database content using a suitable tool, applying the technique for Dynamic Analysis (@MASTG-TECH-0015) to confirm whether sensitive data is stored in plaintext. | ||
|
|
||
| --- | ||
|
|
||
| ## Observation | ||
|
|
||
| The output should indicate: | ||
|
|
||
| - which SQLite databases the app creates, | ||
| - whether sensitive data (tokens, secrets, PII) is present inside these databases, | ||
| - whether the stored values appear in plaintext. | ||
|
|
||
| --- | ||
|
|
||
| ## Evaluation | ||
|
|
||
| The test fails if: | ||
|
|
||
| - sensitive data is stored using the default, unencrypted SQLite implementation, | ||
| - no encryption mechanism (SQLCipher or equivalent) protects the stored data, | ||
| - sensitive values inside the database can be read in plaintext through static or dynamic analysis. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The DEMO must follow the content guidelines (https://mas.owasp.org/contributing/writing-content/mastg-demo.instructions).
For example, the "Evaluation" section should explain each relevant line of the output that is used as an evidence to give a FAIL to the test.