diff --git a/demos/android/MASVS-STORAGE/MASTG-DEMO-0010/MASTG-DEMO-0010.md b/demos/android/MASVS-STORAGE/MASTG-DEMO-0010/MASTG-DEMO-0010.md new file mode 100644 index 0000000000..d0093b7298 --- /dev/null +++ b/demos/android/MASVS-STORAGE/MASTG-DEMO-0010/MASTG-DEMO-0010.md @@ -0,0 +1,42 @@ +--- +platform: android +title: File System Snapshots from Internal Storage +id: MASTG-DEMO-0010 +tools: [adb] +code: [kotlin] +test: MASTG-TEST-0207 +--- + +### Sample + +The snippet below shows sample code that creates a file on the **internal storage** using using the [`filesDir`](https://developer.android.com/reference/android/content/Context#getFilesDir()) property of the context object. + +{{ MastgTest.kt }} + +### Steps + +1. Install an app on your device. +2. Execute `run_before.sh`. +3. Open an app and exercise it to trigger file creations. +4. Execute `run_after.sh`. +5. Close the app once you finish testing. + +{{ run_before.sh # run_after.sh }} + +### Observation + +There is a list of all created files inside `output.txt`. + +{{ output.txt }} + +Their content is inside the `./new_files/` directory and contains: + +A password: + +{{ new_files/secret.txt }} + +The file was created in `/data/user/0/org.owasp.mastestapp/files/` which is equivalent to `/data/data/org.owasp.mastestapp/files/`. + +### Evaluation + +This test fails because the file is not encrypted and contains sensitive data (a password). You can further confirm this by reverse engineering the app and inspecting the code. diff --git a/demos/android/MASVS-STORAGE/MASTG-DEMO-0010/MastgTest.kt b/demos/android/MASVS-STORAGE/MASTG-DEMO-0010/MastgTest.kt new file mode 100644 index 0000000000..ffbda12fce --- /dev/null +++ b/demos/android/MASVS-STORAGE/MASTG-DEMO-0010/MastgTest.kt @@ -0,0 +1,32 @@ +package org.owasp.mastestapp + +import android.content.Context +import android.util.Log +import java.io.File +import java.io.FileOutputStream +import java.io.IOException + +class MastgTest (private val context: Context){ + + fun mastgTest(): String { + mastgTestWriteIntFile() + return "SUCCESS!!\n\nFile has been written to internal files dir" + } + + private fun mastgTestWriteIntFile() { + val internalStorageDir = context.filesDir + val fileName = File(internalStorageDir, "secret.txt") + val fileContent = "secr3tPa\$\$W0rd\n" + + try { + FileOutputStream(fileName).use { output -> + output.write(fileContent.toByteArray()) + Log.d("WriteInternalStorage", "File written to internal storage successfully.") + } + } catch (e: IOException) { + Log.e("WriteInternalStorage", "Error writing file to internal storage", e) + } + } + +} + diff --git a/demos/android/MASVS-STORAGE/MASTG-DEMO-0010/new_files/secret.txt b/demos/android/MASVS-STORAGE/MASTG-DEMO-0010/new_files/secret.txt new file mode 100644 index 0000000000..f5d3c92de6 --- /dev/null +++ b/demos/android/MASVS-STORAGE/MASTG-DEMO-0010/new_files/secret.txt @@ -0,0 +1 @@ +secr3tPa$$W0rd \ No newline at end of file diff --git a/demos/android/MASVS-STORAGE/MASTG-DEMO-0010/output.txt b/demos/android/MASVS-STORAGE/MASTG-DEMO-0010/output.txt new file mode 100644 index 0000000000..55e6205ba0 --- /dev/null +++ b/demos/android/MASVS-STORAGE/MASTG-DEMO-0010/output.txt @@ -0,0 +1 @@ +/data/user/0/org.owasp.mastestapp/files/secret.txt diff --git a/demos/android/MASVS-STORAGE/MASTG-DEMO-0010/run_after.sh b/demos/android/MASVS-STORAGE/MASTG-DEMO-0010/run_after.sh new file mode 100755 index 0000000000..e2ecb93f13 --- /dev/null +++ b/demos/android/MASVS-STORAGE/MASTG-DEMO-0010/run_after.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# SUMMARY: List all files created after the creation date of a file created in run_before + +adb shell "find /data/user/0/org.owasp.mastestapp/ -type f -newer /data/local/tmp/test_start" > output.txt +adb shell "rm /data/local/tmp/test_start" +mkdir -p new_files +while read -r line; do + adb pull "$line" ./new_files/ +done < output.txt diff --git a/demos/android/MASVS-STORAGE/MASTG-DEMO-0010/run_before.sh b/demos/android/MASVS-STORAGE/MASTG-DEMO-0010/run_before.sh new file mode 100755 index 0000000000..a29096474f --- /dev/null +++ b/demos/android/MASVS-STORAGE/MASTG-DEMO-0010/run_before.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# SUMMARY: This script creates a dummy file to mark a timestamp that we can use later +# on to identify files created while the app was being exercised + +adb shell "touch /data/local/tmp/test_start" diff --git a/tests/android/MASVS-STORAGE/MASTG-TEST-0207.md b/tests/android/MASVS-STORAGE/MASTG-TEST-0207.md new file mode 100644 index 0000000000..77b3c6df67 --- /dev/null +++ b/tests/android/MASVS-STORAGE/MASTG-TEST-0207.md @@ -0,0 +1,36 @@ +--- +platform: android +title: Data Stored in the App Sandbox at Runtime +id: MASTG-TEST-0207 +type: [dynamic, filesystem] +mitigations: +- android-use-keystore +- android-use-androidx-security +prerequisites: +- identify-sensitive-data +weakness: MASWE-0006 +--- + +## Overview + +The goal of this test is to retrieve the files written to the **internal storage** and inspect them regardless of the APIs used to write them. It uses a simple approach based on [file retrieval from the device storage](/MASTG/techniques/android/MASTG-TECH-0002) before and after the app is exercised to identify the files created during the app's execution and to check if they contain sensitive data. + +## Steps + +1. Start the device. + +2. Take a first [copy of the app's private data directory](/MASTG/techniques/android/MASTG-TECH-0008.md) to have as a reference for offline analysis. + +3. Launch and use the app going through the various workflows while inputting sensitive data wherever you can. Taking note of the data you input can help identify it later using tools to search for it. + +4. Take a second copy of the app's private data directory for offline analysis and make a diff using the first copy to identify all files created or modify during your testing session. + +## Observation + +The output should contain a list of files that were created in the app's private storage during execution. + +## Evaluation + +Attempt to identify and decode data that has been encoded using methods such as base64 encoding, hexadecimal representation, URL encoding, escape sequences, wide characters and common data obfuscation methods such as xoring. Also consider identifying and decompressing compressed files such as tar or zip. These methods obscure but do not protect sensitive data. + +Search the extracted data for items such as keys, passwords and any sensitive data inputted into the app. The test case fails if you find any of this sensitive data. diff --git a/weaknesses/MASVS-STORAGE/MASWE-0006.md b/weaknesses/MASVS-STORAGE/MASWE-0006.md index 8f88ad19a2..d173605ba0 100644 --- a/weaknesses/MASVS-STORAGE/MASWE-0006.md +++ b/weaknesses/MASVS-STORAGE/MASWE-0006.md @@ -7,20 +7,33 @@ profiles: [L2] mappings: masvs-v1: [MSTG-STORAGE-2] masvs-v2: [MASVS-STORAGE-1, MASVS-CRYPTO-2] + mastg-v1: [MASTG-TEST-0052, MASTG-TEST-0001] + cwe: [311] + android: https://developer.android.com/privacy-and-security/risks/backup-leaks#risk:-storing-sensitive-data-unencrypted +refs: + - https://developer.apple.com/documentation/uikit/protecting_the_user_s_privacy/encrypting_your_app_s_files +status: new +--- -draft: - description: Sensitive data may be stored in internal locations without encryption - and may be accessible to other apps under certain conditions. - topics: - - envelope encryption (DEK+KEK) or equivalent (Android) - - Android Security Lib usage (EncryptedFile/EncryptedSharedPreferences) (Android) - - Don't roll your own storage encryption, use platform provided APIs EncryptedFile/EncryptedSharedPreferences. - (Android) - - iOS KeyChain DataProtection classes (iOS) - - envelope encryption (DEK+KEK) or equivalent (iOS) - - sensitive data must not encoded (e.g. base64, simple bit operations such as XOR - or bit flipping) instead of encrypted -status: draft +## Overview ---- +Mobile apps may need to store sensitive data locally within private storage locations such as the application sandbox and this data is at risk of exposure via, for example, incorrect file permissions, an app vulnerability, device vulnerability or data backup mechanisms. + +[Sensitive data](../../prerequisites/identify-sensitive-data.md "Sensitive Data") may include personally identifiable information (PII), passwords, cryptographic keys or session tokens. + +## Impact + +- **Loss of Confidentiality**: Under the right conditions an attacker could extract sensitive data stored internally within the application sandbox leading to loss of confidentiality and enable further attacks such as identity theft or account takeover. + +## Modes of Introduction + +- **Data Stored Unencrypted**: Sensitive data is written to the app's private data directory (sandbox) unencrypted. +- **Hardcoded Encryption Key**: Sensitive data is encrypted but the key is hardcoded inside the application. +- **Encryption Key Stored on Filesystem**: Sensitive data is encrypted but the key is stored alongside it or in another easily accessible location. +- **Encryption Used is Insufficient**: Sensitive data is encrypted but the encryption is not considered to be strong. + +## Mitigations +- Avoid storing sensitive data locally if not required for application functionality to reduce the likelihood and impact of this weakness. For example keeping PII server-side, rendering it at time of use, and removing any cached data on logout. +- Store cryptographic keys exclusively using the platform's hardware-backed keystore solution, such as the Android Keystore or the iOS Keychain. +- For storing other files and preferences, use platform-provided features for encrypting data at rest or other techniques implementing envelope encryption with Data Encryption Keys (DEK) and Key Encryption Keys (KEK) or equivalent methods. For example, on Android, use [EncryptedFile](https://developer.android.com/reference/androidx/security/crypto/EncryptedFile) or [EncryptedSharedPreferences](https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences); on iOS, use [iOS Data Protection](https://developer.apple.com/documentation/uikit/protecting_the_user_s_privacy/encrypting_your_app_s_files).