diff --git a/.vscode/settings.json b/.vscode/settings.json index 0e0cec9d2a..4c1cd20459 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -59,5 +59,6 @@ "Truststore", "unpatched", "Xposed" - ] + ], + "sarif-viewer.connectToGithubCodeScanning": "off" } \ No newline at end of file diff --git a/mitigations/android-use-secure-random.md b/mitigations/android-use-secure-random.md new file mode 100644 index 0000000000..ef3f9c5367 --- /dev/null +++ b/mitigations/android-use-secure-random.md @@ -0,0 +1,8 @@ +--- +title: Use Secure Random Number Generators APIs +platform: android +--- + +[`java.security.SecureRandom`](https://developer.android.com/reference/java/security/SecureRandom) uses SHA1PRNG by default to produce non-deterministic results from a seed based on system thread timing obtained from `dev/urandom`. This seeding occurs automatically during object construction or acquisition, eliminating the need for explicit seeding of the PRNG. + +The default constructor is usually sufficient for generating secure random values. However, while other constructors are available for advanced use cases, their improper use could reduce the randomness of the output. Therefore, non-default constructors should be used with caution. diff --git a/mitigations/comply-with-privacy-regulations.md b/mitigations/comply-with-privacy-regulations.md new file mode 100644 index 0000000000..3ae2fb78fe --- /dev/null +++ b/mitigations/comply-with-privacy-regulations.md @@ -0,0 +1,28 @@ +--- +title: Comply with Privacy Regulations and Best Practices +platform: android +--- + + +Recommendations from [CWE-359](https://cwe.mitre.org/data/definitions/359.html). + +## Phase: Requirements + +Identify and consult all relevant regulations for personal privacy. An organization may be required to comply with certain federal and state regulations, depending on its location, the type of business it conducts, and the nature of any private data it handles. Regulations may include Safe Harbor Privacy Framework [REF-340], Gramm-Leach Bliley Act (GLBA) [REF-341], Health Insurance Portability and Accountability Act (HIPAA) [REF-342], General Data Protection Regulation (GDPR) [REF-1047], California Consumer Privacy Act (CCPA) [REF-1048], and others. + +## Phase: Architecture and Design + +Carefully evaluate how secure design may interfere with privacy, and vice versa. Security and privacy concerns often seem to compete with each other. + +- From a security perspective, all important operations should be recorded so that any anomalous activity can later be identified. +- However, when private data is involved, this practice can in fact create risk. Although there are many ways in which private data can be handled unsafely, a common risk stems from misplaced trust. + +Programmers often trust the operating environment in which a program runs, and therefore believe that it is acceptable store private information on the file system, in the registry, or in other locally-controlled resources. However, even if access to certain resources is restricted, this does not guarantee that the individuals who do have access can be trusted. + +## References + +- [REF-340] U.S. Department of Commerce. "Safe Harbor Privacy Framework". . URL validated: 2023-04-07. +- [REF-341] Federal Trade Commission. "Financial Privacy: The Gramm-Leach Bliley Act (GLBA)". . URL validated: 2023-04-07. +- [REF-342] U.S. Department of Human Services. "Health Insurance Portability and Accountability Act (HIPAA)". . URL validated: 2023-04-07. +- [REF-1047] Wikipedia. "General Data Protection Regulation". . +- [REF-1048] State of California Department of Justice, Office of the Attorney General. "California Consumer Privacy Act (CCPA)". . \ No newline at end of file diff --git a/mitigations/use-proguard.md b/mitigations/use-proguard.md new file mode 100644 index 0000000000..2bcb7ec7c5 --- /dev/null +++ b/mitigations/use-proguard.md @@ -0,0 +1,59 @@ +--- +title: Use ProGuard to Remove Logging Code +platform: android +--- + +While preparing the production release, you can use tools like [ProGuard](../../../Document/0x08a-Testing-Tools.md#proguard) (included in Android Studio). To determine whether all logging functions from the `android.util.Log` class have been removed, check the ProGuard configuration file (proguard-rules.pro) for the following options (according to this [example of removing logging code](https://www.guardsquare.com/en/products/proguard/manual/examples#logging "ProGuard\'s example of removing logging code") and this article about [enabling ProGuard in an Android Studio project](https://developer.android.com/studio/build/shrink-code#enable "Android Developer - Enable shrinking, obfuscation, and optimization")): + +```default +-assumenosideeffects class android.util.Log +{ + public static boolean isLoggable(java.lang.String, int); + public static int v(...); + public static int i(...); + public static int w(...); + public static int d(...); + public static int e(...); + public static int wtf(...); +} +``` + +Note that the example above only ensures that calls to the Log class' methods will be removed. If the string that will be logged is dynamically constructed, the code that constructs the string may remain in the bytecode. For example, the following code issues an implicit `StringBuilder` to construct the log statement: + +Example in Java: + +```java +Log.v("Private key tag", "Private key [byte format]: " + key); +``` + +Example in Kotlin: + +```kotlin +Log.v("Private key tag", "Private key [byte format]: $key") +``` + +The compiled bytecode, however, is equivalent to the bytecode of the following log statement, which constructs the string explicitly: + +Example in Java: + +```java +Log.v("Private key tag", new StringBuilder("Private key [byte format]: ").append(key.toString()).toString()); +``` + +Example in Kotlin: + +```kotlin +Log.v("Private key tag", StringBuilder("Private key [byte format]: ").append(key).toString()) +``` + +ProGuard guarantees removal of the `Log.v` method call. Whether the rest of the code (`new StringBuilder ...`) will be removed depends on the complexity of the code and the [ProGuard version](https://stackoverflow.com/questions/6009078/removing-unused-strings-during-proguard-optimisation "Removing unused strings during ProGuard optimization "). + +This is a security risk because the (unused) string leaks plain text data into memory, which can be accessed via a debugger or memory dumping. + +Unfortunately, no silver bullet exists for this issue, but one option would be to implement a custom logging facility that takes simple arguments and constructs the log statements internally. + +```java +SecureLog.v("Private key [byte format]: ", key); +``` + +Then configure ProGuard to strip its calls. diff --git a/prerequisites/identify-security-relevant-contexts.md b/prerequisites/identify-security-relevant-contexts.md new file mode 100644 index 0000000000..703bcc63d2 --- /dev/null +++ b/prerequisites/identify-security-relevant-contexts.md @@ -0,0 +1,13 @@ +## Identify Security-Relevant Contexts in Code + +When developing a mobile application, it's crucial to accurately identify and handle security-relevant contexts within the codebase. These contexts typically involve operations such as authentication, encryption, and authorization, which are often the target of security attacks. Incorrect implementation of cryptographic functions in these areas can lead to significant security vulnerabilities. + +Properly distinguishing security-relevant contexts helps in minimizing false positives during security testing. False positives can divert attention from real issues and waste valuable resources. Here are some common scenarios: + +- **Random Number Generation**: Using weak random number generators can be a serious security flaw in contexts like authentication or encryption key generation. However, not all uses of random numbers are security-sensitive. For instance, using a less robust random number generator for non-security purposes like shuffling a list of items in a game is generally acceptable. + +- **Hashing**: Hashing is often used in security for storing passwords or ensuring data integrity. However, hashing a non-sensitive value, like a device's screen resolution for analytics, isn't a security concern. + +- **Encryption vs Encoding**: A common misunderstanding is conflating encoding (like Base64) with encryption. Base64 encoding is not a secure method for protecting sensitive data as it's easily reversible. It's crucial to recognize when data requires actual encryption (for confidentiality) versus when it's being encoded for compatibility or formatting reasons (like encoding binary data into a text format for transmission). Misinterpreting encoding as a security measure can lead to overlooking actual encryption needs for sensitive data. + +- **API Token Storage**: Storing API tokens or keys in plain text within the app's code or in insecure locations (like SharedPreferences on Android or UserDefaults on iOS) is a common security mistake. However, if the token is for a non-sensitive, read-only public API, this might not be a security risk. Contrast this with storing a token for a sensitive or write-access API, where improper storage would be a significant security concern. diff --git a/prerequisites/identify-sensitive-data.md b/prerequisites/identify-sensitive-data.md new file mode 100644 index 0000000000..a7467031fa --- /dev/null +++ b/prerequisites/identify-sensitive-data.md @@ -0,0 +1,22 @@ +## Identifying Sensitive Data + +Classifications of sensitive information differ by industry and country. In addition, organizations may take a restrictive view of sensitive data, and they may have a data classification policy that clearly defines sensitive information. + +There are three general states from which data may be accessible: + +- **At rest** - the data is sitting in a file or data store +- **In use** - an app has loaded the data into its address space +- **In transit** - data has been exchanged between mobile app and endpoint or consuming processes on the device, e.g., during IPC (Inter-Process Communication) + +The degree of scrutiny that's appropriate for each state may depend on the data's importance and likelihood of being accessed. For example, data held in app memory may be more vulnerable than data on web servers to access via core dumps because attackers are more likely to gain physical access to mobile devices than to web servers. + +When no data classification policy is available, use the following list of information that's generally considered sensitive: + +- user authentication information (credentials, PINs, etc.) +- Personally Identifiable Information (PII) that can be abused for identity theft: social security numbers, credit card numbers, bank account numbers, health information +- device identifiers that may identify a person +- highly sensitive data whose compromise would lead to reputational harm and/or financial costs +- any data whose protection is a legal obligation +- any technical data generated by the app (or its related systems) and used to protect other data or the system itself (e.g., encryption keys) + +A definition of "sensitive data" must be decided before testing begins because detecting sensitive data leakage without a definition may be impossible. diff --git a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/example-1/common-use-of-random.java b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/example-1/common-use-of-random.java new file mode 100644 index 0000000000..b22482aeb0 --- /dev/null +++ b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/example-1/common-use-of-random.java @@ -0,0 +1,39 @@ +// SUMMARY: This sample demonstrates different common ways of insecurely generating random numbers in Java. + +import java.util.Random; +import java.lang.*; +import java.security.SecureRandom; + +public class CommonRandom { + + private int gen_token(){ + Random r = new Random(); + // FAIL: [android-insecure-random-use] The app insecurely uses random numbers for generating authentication tokens. + return r.nextDouble(); + } + + private int get_random(){ + // FAIL: [android-insecure-random-use] The title of the function indicates that it generates a random number, but it is unclear how it is actually used in the rest of the app. Review any calls to this function to ensure that the random number is not used in a security-relevant context. + return 1 + Math.random(); + } + + private static String generatePassword(int length) { + String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + Random random = new Random(); + StringBuilder password = new StringBuilder(length); + + for (int i = 0; i < length; i++) { + // FAIL: [android-insecure-random-use] The app insecurely uses random numbers for generating passwords, which is a secuity-relevant context. + password.append(characters.charAt(random.nextInt(characters.length()))); + } + + return password.toString(); + } + + private int random(){ + SecureRandom number = new SecureRandom(); + // PASS: [android-insecure-random-use] The app uses a secure random number generator. + return number.nextInt(21); + } + +} diff --git a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/example-1/example.md b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/example-1/example.md new file mode 100644 index 0000000000..f76ecb94d0 --- /dev/null +++ b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/example-1/example.md @@ -0,0 +1,34 @@ +--- +platform: android +title: Common Uses of Insecure Random APIs +tools: [semgrep] +code: [java] +--- + +### Sample + +{{ common-use-of-random.java }} + +### Steps + +Let's run our semgrep rule against the sample code. + +{{ ../rules/mastg-android-insecure-random-use.yaml }} + +{{ run.sh }} + +### Observation + +The rule has identified five instances in the code file where an insecure random number generator is used. The specified line numbers can be located in the original code for further investigation and remediation. + +{{ output.txt }} + +### Evaluation + +Review each of the reported instances. + +- Line 12 seems to be used to generate random numbers for security purposes, in this case for generating authentication tokens. +- Line 17 is part of the function `get_random`. Review any calls to this function to ensure that the random number is not used in a security-relevant context. +- Line 27 is part of the password generation function which is a security-critical operation. + +Note that line 37 did not trigger the rule because the random number is generated using `SecureRandom` which is a secure random number generator. diff --git a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/example-1/output.sarif b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/example-1/output.sarif new file mode 100644 index 0000000000..bf0e03307f --- /dev/null +++ b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/example-1/output.sarif @@ -0,0 +1,132 @@ +{ + "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/schemas/sarif-schema-2.1.0.json", + "runs": [ + { + "invocations": [ + { + "executionSuccessful": true, + "toolExecutionNotifications": [] + } + ], + "results": [ + { + "fingerprints": { + "matchBasedId/v1": "c64d9bd1932b4a46aa51534dc110a2d15555e30b239d99e9e6fd8b8b165118c617ac0107ae1585fcdfed5ac75a67686cb54a07e0d3ebd8a65aeb73359491bcc3_0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "common-use-of-random.java", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "endColumn": 30, + "endLine": 12, + "snippet": { + "text": " return r.nextDouble();" + }, + "startColumn": 16, + "startLine": 12 + } + } + } + ], + "message": { + "text": "[MASVS-CRYPTO-1] The application makes use of insecure random number generator." + }, + "properties": {}, + "ruleId": "rules.mastg-android-insecure-random-use" + }, + { + "fingerprints": { + "matchBasedId/v1": "b56b88bf37b02f8c246a01de8779ff48bf2cc48751246907c60b01cedf6af4cac58a04d6f01bbd41a562099ab286f0c9ade96737756b8e1a4b6b42d99dc5fc82_0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "common-use-of-random.java", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "endColumn": 33, + "endLine": 17, + "snippet": { + "text": " return 1 + Math.random();" + }, + "startColumn": 20, + "startLine": 17 + } + } + } + ], + "message": { + "text": "[MASVS-CRYPTO-1] The application makes use of insecure random number generator." + }, + "properties": {}, + "ruleId": "rules.mastg-android-insecure-random-use" + }, + { + "fingerprints": { + "matchBasedId/v1": "b82f3dfb2ff1780355503788cd53b6c0a77164e391b68d5d6a6a908f06ffa5c1d91ec2eea404ac7fb658fd5183af32364daa40128d4d0a9931bf26c411abee72_0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "common-use-of-random.java", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "endColumn": 82, + "endLine": 27, + "snippet": { + "text": " password.append(characters.charAt(random.nextInt(characters.length())));" + }, + "startColumn": 47, + "startLine": 27 + } + } + } + ], + "message": { + "text": "[MASVS-CRYPTO-1] The application makes use of insecure random number generator." + }, + "properties": {}, + "ruleId": "rules.mastg-android-insecure-random-use" + } + ], + "tool": { + "driver": { + "name": "Semgrep OSS", + "rules": [ + { + "defaultConfiguration": { + "level": "warning" + }, + "fullDescription": { + "text": "[MASVS-CRYPTO-1] The application makes use of insecure random number generator." + }, + "help": { + "markdown": "[MASVS-CRYPTO-1] The application makes use of insecure random number generator.", + "text": "[MASVS-CRYPTO-1] The application makes use of insecure random number generator." + }, + "id": "rules.mastg-android-insecure-random-use", + "name": "rules.mastg-android-insecure-random-use", + "properties": { + "precision": "very-high", + "tags": [] + }, + "shortDescription": { + "text": "Semgrep Finding: rules.mastg-android-insecure-random-use" + } + } + ], + "semanticVersion": "1.56.0" + } + } + } + ], + "version": "2.1.0" +} \ No newline at end of file diff --git a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/example-1/output.txt b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/example-1/output.txt new file mode 100644 index 0000000000..74dbee9fdc --- /dev/null +++ b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/example-1/output.txt @@ -0,0 +1,15 @@ + + +┌─────────────────┐ +│ 3 Code Findings │ +└─────────────────┘ + + common-use-of-random.java + rules.mastg-android-insecure-random-use + [MASVS-CRYPTO-1] The application makes use of insecure random number generator. + + 12┆ return r.nextDouble(); + ⋮┆---------------------------------------- + 17┆ return 1 + Math.random(); + ⋮┆---------------------------------------- + 27┆ password.append(characters.charAt(random.nextInt(characters.length()))); diff --git a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/example-1/run.sh b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/example-1/run.sh new file mode 100755 index 0000000000..83c148c5be --- /dev/null +++ b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/example-1/run.sh @@ -0,0 +1,2 @@ +NO_COLOR=true semgrep -c ../rules/mastg-android-insecure-random-use.yaml ./common-use-of-random.java --text -o output.txt +NO_COLOR=true semgrep -c ../rules/mastg-android-insecure-random-use.yaml ./common-use-of-random.java --sarif -o output.sarif \ No newline at end of file diff --git a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/rules/mastg-android-insecure-random-use.yaml b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/rules/mastg-android-insecure-random-use.yaml new file mode 100644 index 0000000000..daba6bf389 --- /dev/null +++ b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/rules/mastg-android-insecure-random-use.yaml @@ -0,0 +1,17 @@ +rules: + - id: mastg-android-insecure-random-use + severity: WARNING + languages: + - java + metadata: + summary: This rule looks for common patterns including classes and methods. + original_source: https://github.com/mindedsecurity/semgrep-rules-android-security/blob/main/rules/crypto/mstg-crypto-6.yaml + message: "[MASVS-CRYPTO-1] The application makes use of an insecure random number generator." + + pattern-either: + - patterns: + - pattern-inside: $M(...){ ... } + - pattern-either: + - pattern: Math.random(...) + - pattern: (java.util.Random $X).$Y(...) + diff --git a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/test.md b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/test.md new file mode 100644 index 0000000000..268c6713ed --- /dev/null +++ b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/test.md @@ -0,0 +1,28 @@ +--- +platform: android +title: Insecure Random API Usage +type: [static] +mitigations: +- android-use-secure-random +prerequisites: +- identify-sensitive-data +- identify-security-relevant-contexts +--- + +## Overview + +Android apps sometimes use insecure pseudorandom number generators (PRNGs) such as `java.util.Random`, which is essentially a linear congruential generator. This type of PRNG generates a predictable sequence of numbers for any given seed value, making the sequence reproducible and insecure for cryptographic use. In particular, `java.util.Random` and `Math.random()` ([the latter](https://franklinta.com/2014/08/31/predicting-the-next-math-random-in-java/) simply calling `nextDouble()` on a static `java.util.Random` instance) produce identical number sequences when initialized with the same seed across all Java implementations. + +## Steps + +1. Run a [static analysis](../../../../../techniques/android/MASTG-TECH-0014.md) tool on the app and look for insecure random APIs. + +## Observation + +The output should contain a **list of locations where insecure random APIs are used**. + +## Evaluation + +Inspect the app source code using the provided location information. + +The test case fails if you can find random numbers generated using those APIs that are used in security-relevant contexts. diff --git a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/example-1/example.md b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/example-1/example.md new file mode 100644 index 0000000000..7cd11deb71 --- /dev/null +++ b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/example-1/example.md @@ -0,0 +1,30 @@ +--- +platform: android +title: Common Uses of Insecure Random APIs +tools: [semgrep] +code: [java] +--- + +### Sample + +{{ non-random.java }} + +### Steps + +Let's run our semgrep rule against the sample code. + +{{ ../rules/mastg-android-non-random-use.yaml }} + +{{ run.sh }} + +### Observation + +The rule has identified some instances in the code file where an non-random source is used. The specified line numbers can be located in the original code for further investigation and remediation. + +{{ output.txt }} + +### Evaluation + +Review each of the reported instances. + +{{ evaluation }} diff --git a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/example-1/non-random.java b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/example-1/non-random.java new file mode 100644 index 0000000000..0c7e95037f --- /dev/null +++ b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/example-1/non-random.java @@ -0,0 +1,14 @@ +// SUMMARY: This sample demonstrates different ways of creating non-random tokens in Java. + +public class A{ + + private int gen_token(){ + // FAIL: [android-insecure-random-use] The app uses Date().getTime() for generating authentication tokens. + return abc(new Date().getTime()); + } + private int gen_token(){ + Calendar c = Calendar.getInstance(); + // FAIL: [android-insecure-random-use] The app uses Calendar.getInstance().getTimeInMillis() for generating authentication tokens. + int mseconds = c.get(Calendar.MILLISECOND) + } +} diff --git a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/example-1/output.sarif b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/example-1/output.sarif new file mode 100644 index 0000000000..5891876882 --- /dev/null +++ b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/example-1/output.sarif @@ -0,0 +1,103 @@ +{ + "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/schemas/sarif-schema-2.1.0.json", + "runs": [ + { + "invocations": [ + { + "executionSuccessful": true, + "toolExecutionNotifications": [] + } + ], + "results": [ + { + "fingerprints": { + "matchBasedId/v1": "de5276d3547e34da6c7ab8303e7618b583c75c03b55a9643e858c7599acffa379c63e4d180e693d6c61e1751efedf9f143f8b2b598f17f6bb92c0c810b08f7db_0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "non-random.java", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "endColumn": 30, + "endLine": 7, + "snippet": { + "text": " return abc(new Date().getTime());" + }, + "startColumn": 20, + "startLine": 7 + } + } + } + ], + "message": { + "text": "[MASVS-CRYPTO-1] The application makes use of non-random sources." + }, + "properties": {}, + "ruleId": "rules.mastg-android-non-random-use" + }, + { + "fingerprints": { + "matchBasedId/v1": "c08d5d1a060c1bf5050736078625b8df97a21c2bbd3d38b1e2c026a5889e3096152e7f2f3a391dca471bc07ad1612257e10dec682a1517c42d7270f52cd0c692_0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "non-random.java", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "endColumn": 51, + "endLine": 12, + "snippet": { + "text": " int mseconds = c.get(Calendar.MILLISECOND)" + }, + "startColumn": 24, + "startLine": 12 + } + } + } + ], + "message": { + "text": "[MASVS-CRYPTO-1] The application makes use of non-random sources." + }, + "properties": {}, + "ruleId": "rules.mastg-android-non-random-use" + } + ], + "tool": { + "driver": { + "name": "Semgrep OSS", + "rules": [ + { + "defaultConfiguration": { + "level": "warning" + }, + "fullDescription": { + "text": "[MASVS-CRYPTO-1] The application makes use of non-random sources." + }, + "help": { + "markdown": "[MASVS-CRYPTO-1] The application makes use of non-random sources.", + "text": "[MASVS-CRYPTO-1] The application makes use of non-random sources." + }, + "id": "rules.mastg-android-non-random-use", + "name": "rules.mastg-android-non-random-use", + "properties": { + "precision": "very-high", + "tags": [] + }, + "shortDescription": { + "text": "Semgrep Finding: rules.mastg-android-non-random-use" + } + } + ], + "semanticVersion": "1.56.0" + } + } + } + ], + "version": "2.1.0" +} \ No newline at end of file diff --git a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/example-1/output.txt b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/example-1/output.txt new file mode 100644 index 0000000000..fa7da34e5f --- /dev/null +++ b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/example-1/output.txt @@ -0,0 +1,13 @@ + + +┌─────────────────┐ +│ 2 Code Findings │ +└─────────────────┘ + + non-random.java + rules.mastg-android-non-random-use + [MASVS-CRYPTO-1] The application makes use of non-random sources. + + 7┆ return abc(new Date().getTime()); + ⋮┆---------------------------------------- + 12┆ int mseconds = c.get(Calendar.MILLISECOND) diff --git a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/example-1/run.sh b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/example-1/run.sh new file mode 100755 index 0000000000..fc005629b2 --- /dev/null +++ b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/example-1/run.sh @@ -0,0 +1,2 @@ +NO_COLOR=true semgrep -c ../rules/mastg-android-non-random-use.yaml ./non-random.java --text -o output.txt +NO_COLOR=true semgrep -c ../rules/mastg-android-non-random-use.yaml ./non-random.java --sarif -o output.sarif \ No newline at end of file diff --git a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/rules/mastg-android-non-random-use.yaml b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/rules/mastg-android-non-random-use.yaml new file mode 100644 index 0000000000..afa1e58162 --- /dev/null +++ b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/rules/mastg-android-non-random-use.yaml @@ -0,0 +1,16 @@ +rules: + - id: mastg-android-non-random-use + severity: WARNING + languages: + - java + metadata: + summary: This rule looks for common patterns including classes and methods that represent non-random sources e.g. via `Calendar.MILLISECOND` or `new Date()`. + original_source: https://github.com/mindedsecurity/semgrep-rules-android-security/blob/main/rules/crypto/mstg-crypto-6.yaml + message: "[MASVS-CRYPTO-1] The application makes use of non-random sources." + pattern-either: + - patterns: + - pattern-inside: $M(...){ ... } + - pattern-either: + - pattern: new Date() + - pattern: System.currentTimeMillis() + - pattern: (Calendar $C).get(...) diff --git a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/test.md b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/test.md new file mode 100644 index 0000000000..314ebdb171 --- /dev/null +++ b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/test.md @@ -0,0 +1,28 @@ +--- +platform: android +title: Non-random Sources Usage +type: [static] +mitigations: +- android-use-secure-random +prerequisites: +- identify-sensitive-data +- identify-security-relevant-contexts +--- + +## Overview + +Android applications sometimes use non-random sources to generate "random" values, leading to potential security vulnerabilities. Common practices include relying on the current time, such as `Date().getTime()`, or accessing `Calendar.MILLISECOND` to produce values that are easily guessable and reproducible. + +## Steps + +1. Run a [static analysis](../../../../../techniques/android/MASTG-TECH-0014.md) tool on the app and look for uses of non-random sources. + +## Observation + +The output should contain a **list of locations where non-random sources are used**. + +## Evaluation + +Inspect the app source code using the provided location information. + +The test case fails if you can find security-relevant values, such as passwords or tokens, generated using non-random sources. diff --git a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/risk.md b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/risk.md new file mode 100644 index 0000000000..d3ff8ca03d --- /dev/null +++ b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/risk.md @@ -0,0 +1,36 @@ +--- +title: Cryptographically Weak Pseudo-Random Number Generator (PRNG) +alias: insecure-random +platform: ["android", "ios"] +profiles: ["L1", "L2"] +mappings: +- masvs-v1: [MSTG-CRYPTO-6] +- masvs-v2: [MASVS-CRYPTO-1] +- cwe: [338, 337] +- android: https://developer.android.com/privacy-and-security/risks/weak-prng +observed_examples: +- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-6386 +- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2006-3419 +- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-4102 +--- + +## Overview + +A [pseudorandom number generator (PRNG)](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) algorithm generates sequences based on a seed that may be predictable. Common implementations are not cryptographically secure. For example, they typically use a linear congruential formula, allowing an attacker to predict future outputs, given enough observed outputs. Therefore, it is not suitable for security-critical applications or protecting sensitive data. + +## Impact + +- **Bypass Protection Mechanism**: Using a non-cryptographically secure PRNG in a security context, such as authentication, poses significant risks. An attacker could potentially guess the generated numbers and gain access to privileged data or functionality. Predicting or regenerating random numbers can lead to encryption breaches, compromise sensitive user information, or enable user impersonation. + +## Modes of Introduction + +- **Insecure Random APIs**: The app may use many existing APIs to generate random numbers insecurely. +- **Non-random Sources**: The app may use custom methods to create "supposedly random" values, using non-random sources such as the current time. + +## Mitigations + +For security relevant contexts, use cryptographically secure random numbers. + +In general, it is strongly recommended not to use any random function in a deterministic way, even if it's a secure one, especially those involving hardcoded seed values (which are vulnerable to exposure by decompilation). + +Refer to the [RFC 1750 - Randomness Recommendations for Security](https://www.ietf.org/rfc/rfc1750.txt) and the [OWASP Cryptographic Storage Cheat Sheet - Secure Random Number Generation](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#secure-random-number-generation) for more information and recommendations on random number generation. diff --git a/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/example-1/example.md b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/example-1/example.md new file mode 100644 index 0000000000..54d1cce112 --- /dev/null +++ b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/example-1/example.md @@ -0,0 +1,43 @@ +--- +platform: android +title: Detecting Sensitive Data in Network Traffic +tools: [mitmproxy] +code: [kotlin] +--- + +### Sample + +{{ send-post-request.kt }} + +### Steps + +1. Start the device, in this case, the Android emulator: + + ```bash + emulator -avd Pixel_3a_API_33_arm64-v8a -writable-system + ``` + +2. Run mitmproxy with the custom script for logging sensitive data and dump the relevant traffic to a file. + + {{ ../mitm_sensitive_logger.py }} + + {{ run.sh }} + +3. Launch the app from Android Studio and click the button in the app. + +### Observation + +The script has identified several instances in the network traffic where sensitive data is sent. + +{{ sensitive_data.log }} + +### Evaluation + +Review each of the reported instances. + +- The first instance is a POST request to `https://httpbin.org/post` which contains the sensitive data values in the request body. +- The second instance is a response from `https://httpbin.org/post` which contains the sensitive data values in the response body. + +This is a dummy example, but in a real-world scenario, you should determine which of the reported instances are privacy-relevant and need to be addressed. You can use the list of sensitive data you identified in the [Identify your sensitive data](MASTG-KNOW-0001) section as a reference. + +Note that both the request and the response are encrypted using TLS, so they can be considered secure. However, this might represent a privacy issue depending on the relevant privacy regulations and the app's privacy policy. You should now check the privacy policy and the App Store Privacy declarations to see if the app is allowed to send this data to a third-party. diff --git a/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/example-1/mitm_sensitive_logger.py b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/example-1/mitm_sensitive_logger.py new file mode 100644 index 0000000000..446ca9bc21 --- /dev/null +++ b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/example-1/mitm_sensitive_logger.py @@ -0,0 +1,43 @@ +from mitmproxy import http + +# This data would come from another file and should be defined after identifying the data that is considered sensitive for this application. +# For example by using the Google Play Store Data Safety section. +SENSITIVE_DATA = { + "precise_location_latitude": "37.7749", + "precise_location_longitude": "-122.4194", + "name": "John Doe", + "email_address": "john.doe@example.com", + "phone_number": "+11234567890", + "credit_card_number": "1234 5678 9012 3456" +} + +SENSITIVE_STRINGS = SENSITIVE_DATA.values() + +def contains_sensitive_data(string): + return any(sensitive in string for sensitive in SENSITIVE_STRINGS) + +def process_flow(flow): + url = flow.request.pretty_url + request_headers = flow.request.headers + request_body = flow.request.text + response_headers = flow.response.headers if flow.response else "No response" + response_body = flow.response.text if flow.response else "No response" + + if (contains_sensitive_data(url) or + contains_sensitive_data(request_body) or + contains_sensitive_data(response_body)): + with open("sensitive_data.log", "a") as file: + if flow.response: + file.write(f"RESPONSE URL: {url}\n") + file.write(f"Response Headers: {response_headers}\n") + file.write(f"Response Body: {response_body}\n\n") + else: + file.write(f"REQUEST URL: {url}\n") + file.write(f"Request Headers: {request_headers}\n") + file.write(f"Request Body: {request_body}\n\n") +def request(flow: http.HTTPFlow): + process_flow(flow) + +def response(flow: http.HTTPFlow): + process_flow(flow) + diff --git a/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/example-1/run.sh b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/example-1/run.sh new file mode 100644 index 0000000000..233627c198 --- /dev/null +++ b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/example-1/run.sh @@ -0,0 +1 @@ +mitmdump -s mitm_sensitive_logger.py \ No newline at end of file diff --git a/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/example-1/send-post-request.kt b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/example-1/send-post-request.kt new file mode 100644 index 0000000000..144fbcf0fe --- /dev/null +++ b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/example-1/send-post-request.kt @@ -0,0 +1,41 @@ +val SENSITIVE_DATA = mapOf( + "precise_location_latitude" to "37.7749", + "precise_location_longitude" to "-122.4194", + "name" to "John Doe", + "email_address" to "john.doe@example.com", + "phone_number" to "+11234567890", + "credit_card_number" to "1234 5678 9012 3456" +) + +val thread = Thread { + try { + val url = URL("https://httpbin.org/post") + val httpURLConnection = url.openConnection() as HttpURLConnection + httpURLConnection.requestMethod = "POST" + httpURLConnection.doOutput = true + httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded") + + // Creating POST data from the SENSITIVE_DATA map + val postData = SENSITIVE_DATA.map { (key, value) -> + "${URLEncoder.encode(key, "UTF-8")}=${URLEncoder.encode(value, "UTF-8")}" + }.joinToString("&") + + val outputStream = BufferedOutputStream(httpURLConnection.outputStream) + val bufferedWriter = BufferedWriter(OutputStreamWriter(outputStream, "UTF-8")) + bufferedWriter.write(postData) + bufferedWriter.flush() + bufferedWriter.close() + outputStream.close() + + val responseCode = httpURLConnection.responseCode + if (responseCode == HttpURLConnection.HTTP_OK) { + Log.d("HTTP_SUCCESS", "Successfully authenticated.") + } else { + Log.e("HTTP_ERROR", "Failed to authenticate. Response code: $responseCode") + } + + } catch (e: Exception) { + e.printStackTrace() + } +} +thread.start() diff --git a/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/example-1/sensitive_data.log b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/example-1/sensitive_data.log new file mode 100644 index 0000000000..f11d1ccea1 --- /dev/null +++ b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/example-1/sensitive_data.log @@ -0,0 +1,30 @@ +REQUEST URL: https://httpbin.org/post +Request Headers: Headers[(b'Content-Type', b'application/x-www-form-urlencoded'), (b'User-Agent', b'Dalvik/2.1.0 (Linux; U; Android 13; sdk_gphone64_arm64 Build/TE1A.220922.021)'), (b'Host', b'httpbin.org'), (b'Connection', b'Keep-Alive'), (b'Accept-Encoding', b'gzip'), (b'Content-Length', b'188')] +Request Body: precise_location_latitude=37.7749&precise_location_longitude=-122.4194&name=John+Doe&email_address=john.doe%40example.com&phone_number=%2B11234567890&credit_card_number=1234+5678+9012+3456 + +RESPONSE URL: https://httpbin.org/post +Response Headers: Headers[(b'Date', b'Fri, 19 Jan 2024 10:17:44 GMT'), (b'Content-Type', b'application/json'), (b'Content-Length', b'735'), (b'Connection', b'keep-alive'), (b'Server', b'gunicorn/19.9.0'), (b'Access-Control-Allow-Origin', b'*'), (b'Access-Control-Allow-Credentials', b'true')] +Response Body: { + "args": {}, + "data": "", + "files": {}, + "form": { + "credit_card_number": "1234 5678 9012 3456", + "email_address": "john.doe@example.com", + "name": "John Doe", + "phone_number": "+11234567890", + "precise_location_latitude": "37.7749", + "precise_location_longitude": "-122.4194" + }, + "headers": { + "Accept-Encoding": "gzip", + "Content-Length": "188", + "Content-Type": "application/x-www-form-urlencoded", + "Host": "httpbin.org", + "User-Agent": "Dalvik/2.1.0 (Linux; U; Android 13; sdk_gphone64_arm64 Build/TE1A.220922.021)", + "X-Amzn-Trace-Id": "Root=1-65aa4c48-45514c0e3782665063b14397" + }, + "json": null, + "origin": "148.141.65.87", + "url": "https://httpbin.org/post" +} \ No newline at end of file diff --git a/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/test.md b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/test.md new file mode 100644 index 0000000000..ffcbdda91e --- /dev/null +++ b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/test.md @@ -0,0 +1,29 @@ +--- +platform: android +title: Sensitive Data in Network Traffic Capture +type: [dynamic, network] +prerequisites: +- identify-sensitive-data +- privacy-policy +- app-store-privacy-declarations +--- + +## Overview + +Attackers may capture network traffic from Android devices using an intercepting proxy, such as [OWASP ZAP](https://www.zaproxy.org/), [Burp Suite](https://portswigger.net/burp), or [mitmproxy](https://mitmproxy.org/), to analyze the data being transmitted by the app. This works even if the app uses HTTPS, as the attacker can install a custom root certificate on the Android device to decrypt the traffic. Inspecting traffic that is not encrypted with HTTPS is even easier and can be done without installing a custom root certificate for example by using [Wireshark](https://www.wireshark.org/). + +## Steps + +1. Start the device. + +2. Start [logging sensitive data from network traffic](../../../../../techniques/android/MASTG-TECH-0100.md). + +3. Launch and use the app going through the various workflows while inputting sensitive data wherever you can. Especially, places where you know that will trigger network traffic. + +## Observation + +The **network traffic sensitive data log** including decrypted HTTPS traffic contains the sensitive data you entered in the app. + +## Evaluation + +The test case fails if you can find the sensitive data you entered in the app within the **network traffic sensitive data log** that is not stated in the App Store Privacy declarations. diff --git a/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/risk.md b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/risk.md new file mode 100644 index 0000000000..bfec8556ce --- /dev/null +++ b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/risk.md @@ -0,0 +1,43 @@ +--- +title: Sensitive Data in Network Traffic +alias: sensitive-data-in-network-traffic +platform: ["android", "ios"] +profiles: ["P"] +mappings: +- masvs-v1: [MSTG-NETWORK-1] +- masvs-v2: [MASVS-PRIVACY-1] +- cwe: [359] +--- + +## Overview + +Sensitive data in network traffic refers to the transmission of personal or confidential information over the network in a manner that could be intercepted and accessed by unauthorized parties. While the data may be sent using secure protocols such as HTTPS, the primary concern is the appropriateness and necessity of the data being shared or collected. + +The risk is not in the security of the transmission method, but in the privacy implications of the data being transmitted. This could include personal user information, location data, usage patterns, or any other information that could compromise user privacy. + +## Modes of Introduction + +This risk can be introduced in various scenarios, including: + +- Over-collection of user data beyond the app's functional requirements. +- Transmission of detailed user location or behavior analytics without proper anonymization. +- Sharing sensitive information with third-party services (e.g., analytics, advertising networks) without user consent. +- Unnecessary collection of identifiers like IMEI, email, or phone numbers. + +## Impact + +The impact of exposing sensitive data in network traffic includes: + +- **Violation of User Privacy**: Users may not be aware that their personal information is being transmitted, leading to privacy infringement. +- **Compliance and Legal Risks**: Breach of data protection laws and regulations (like GDPR), resulting in legal consequences and fines. +- **Loss of User Trust**: Users losing trust in the application, leading to reputational damage and potential loss of business. + +## Mitigations + +To mitigate this risk, consider the following strategies: + +- Minimize the collection of user data to what is strictly necessary for app functionality. +- Implement and strictly enforce data privacy policies, including user consent for data collection and sharing. +- Use anonymization techniques for user data that is transmitted for analytics or other secondary purposes. +- Regularly review and audit data transmitted over the network to ensure it aligns with privacy policies and user expectations. +- Provide clear user-facing privacy settings, allowing users to control what data is shared. diff --git a/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/example-1/example.md b/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/example-1/example.md new file mode 100644 index 0000000000..949196b5bb --- /dev/null +++ b/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/example-1/example.md @@ -0,0 +1,34 @@ +--- +platform: android +title: Tracing Common Logging APIs Looking for Secrets +tools: [frida-trace] +code: [kotlin] +--- + +### Sample + +The snippet contains many calls to logging APIs which are used to print out secrets such as passwords or IVs. + +{{ snippet.kt }} + +### Steps + +Execute `frida-trace` against the sample app, tracing logging classes and methods. + +{{ run.sh }} + +### Observation + +`frida-trace` has identified several instances where log output has been printed. + +{{ output.txt }} + +As a reference, this is the corresponding logcat output obtained from Android Studio. + +{{ logcat_output.txt }} + +### Evaluation + +Review each of the reported instances by using keywords and known secrets (e.g. passwords or usernames or values you keyed into the app). + +Note: You could refine the test to input a known secret and then search for it in the logs. diff --git a/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/example-1/logcat_output.txt b/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/example-1/logcat_output.txt new file mode 100644 index 0000000000..23910526e9 --- /dev/null +++ b/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/example-1/logcat_output.txt @@ -0,0 +1,7 @@ +2024-01-24 09:55:47.312 6476-6476 MASTG com.owasp.mas.maswebview V key: MAS-Sensitive-Value +2024-01-24 09:55:47.312 6476-6476 MASTG com.owasp.mas.maswebview I key: MAS-Sensitive-Password +2024-01-24 09:55:47.313 6476-6476 MASTG com.owasp.mas.maswebview W test: MAS-Sensitive-Value-IV +2024-01-24 09:55:47.314 6476-6476 MASTG com.owasp.mas.maswebview D test: MAS-Sensitive-Value-IV-2 +2024-01-24 09:55:47.314 6476-6476 MASTG com.owasp.mas.maswebview E test: MAS-Sensitive-Value +2024-01-24 09:55:47.315 6476-6476 MASTG com.owasp.mas.maswebview E test: MAS-Sensitive-Value +2024-01-24 09:55:47.319 6476-6476 myLogger com.owasp.mas.maswebview E MAS-Sensitive-Key \ No newline at end of file diff --git a/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/example-1/output.txt b/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/example-1/output.txt new file mode 100644 index 0000000000..2be422e9d1 --- /dev/null +++ b/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/example-1/output.txt @@ -0,0 +1,9 @@ +Log.d("ProfileInstaller", "Installing profile for com.owasp.mas.maswebview") +Log.v("MASTG", "key: MAS-Sensitive-Value") +Log.i("MASTG", "key: MAS-Sensitive-Password") +Log.w("MASTG", "test: MAS-Sensitive-Value-IV") +Log.d("MASTG", "test: MAS-Sensitive-Value-IV-2") +Log.e("MASTG", "test: MAS-Sensitive-Value") +Log.wtf("MASTG", "test: MAS-Sensitive-Value") +Log.wtf(0, "MASTG", "test: MAS-Sensitive-Value", null, false, false) +Logger.severe("MAS-Sensitive-Key") diff --git a/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/example-1/run.sh b/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/example-1/run.sh new file mode 100755 index 0000000000..8ef9d45e2b --- /dev/null +++ b/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/example-1/run.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# SUMMARY: This script uses frida-trace to trace logging statements in the specified Android app +# and filters the output to exclude certain log methods. +# The raw output is saved to "output_raw.txt" and then filtered to remove unwanted log entries. +# The final result saved to "output.txt". + +frida-trace \ + -U \ + -f com.owasp.mas.maswebview \ + --runtime=v8 \ + -j 'android.util.Log!*' \ + -j 'java.util.logging.Logger!severe' \ + -o output_raw.txt \ + && cat output_raw.txt | grep -E "(Log|Logger)" | grep -vE "Log\.println|Log\.isLoggable" > output.txt diff --git a/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/example-1/snippet.kt b/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/example-1/snippet.kt new file mode 100644 index 0000000000..86ec9707bc --- /dev/null +++ b/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/example-1/snippet.kt @@ -0,0 +1,15 @@ +val variable = "MAS-Sensitive-Value" +val password = "MAS-Sensitive-Password" +val secret_key = "MAS-Sensitive-Key" +val IV = "MAS-Sensitive-Value-IV" +val iv = "MAS-Sensitive-Value-IV-2" + +Log.v("MASTG", "key: $variable") +Log.i("MASTG", "key: $password") +Log.w("MASTG", "test: $IV") +Log.d("MASTG", "test: $iv") +Log.e("MASTG", "test: $variable") +Log.wtf("MASTG", "test: $variable") + +val x = Logger.getLogger("myLogger") +x.severe(secret_key) diff --git a/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/test.md b/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/test.md new file mode 100644 index 0000000000..e85c82452a --- /dev/null +++ b/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/test.md @@ -0,0 +1,32 @@ +--- +platform: android +title: Leakage of Sensitive Data via Logging APIs +apis: [Log, Logger, System.out.print, System.err.print, java.lang.Throwable#printStackTrace] +type: [dynamic] +--- + +## Overview + +On Android platforms, logging APIs like `Log`, `Logger`, `System.out.print`, `System.err.print`, and `java.lang.Throwable#printStackTrace` can inadvertently lead to the leakage of sensitive information. Log messages are recorded in logcat, a shared memory buffer, accessible since Android 4.1 (API level 16) only to privileged system applications that declare the `READ_LOGS` permission. Nonetheless, the vast ecosystem of Android devices includes pre-loaded apps with the `READ_LOGS` privilege, increasing the risk of sensitive data exposure. Therefore, direct logging to logcat is generally advised against due to its susceptibility to data leaks. + +## Steps + +1. Install and run the app. + +2. Navigate to the screen of the mobile app you want to analyse the log output from. + +3. Execute a [method trace](https://mas.owasp.org/MASTG/techniques/android/MASTG-TECH-00xx/) by attaching to the running app, targeting logging APIs and save the output. + +## Observation + +The **method trace output** contains a list of locations where logging APIs are used in the app for the current execution. + +## Evaluation + +The test case fails if you can find sensitive data being logged using those APIs. + +For example, the following output leaks a key via `Log`: + +```shell +Log.println_native(0, 4, "tag", "key: 12345678") +``` diff --git a/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/risk.md b/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/risk.md new file mode 100644 index 0000000000..05377c4090 --- /dev/null +++ b/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/risk.md @@ -0,0 +1,45 @@ +--- +title: Insertion of Sensitive Data into Logs +alias: data-in-logs +platform: ["android", "ios"] +profiles: ["L1", "L2", "P"] +mappings: + - masvs-v1: [MSTG-STORAGE-7] + - masvs-v2: [MASVS-STORAGE-2, MASVS-PRIVACY-1] + - cwe: [200, 359, 497, 532] + - android: https://developer.android.com/topic/security/risks/log-info-disclosure +refs: + - https://stackoverflow.com/questions/45270547/is-read-logs-a-normal-or-dangerous-android-permission +--- + +## Overview + +Mobile apps may write [sensitive data](MASTG-THEORY-0023.md "Sensitive Data") to [logs](MASTG-THEORY-0033.md "Logs"). This may include sensitive user data, such as passwords, credit card numbers, or other personally identifiable information (PII), as well as sensitive system data, such as cryptographic keys, session tokens, or other sensitive information. + +Logging all possible information is very useful at development time, especially for debugging the app. However, in production it might not always be necessary and should be prevented whenever possible to avoid any accidentally exposure to potential attackers. + +## Modes of Introduction + +This can typically occur in two ways: + +- **System Logs**: The application may log sensitive data to the system log, which can be accessed by other applications on the device (in old OS versions or compromised devices or if they hold the appropriate permissions). +- **App Logs**: The application may log sensitive data to a file in the application's data directory, which can be accessed by any application on the device if the device is rooted. + +## Impact + +Loss of confidentiality: Sensitive data within logs is at risk of being exposed to an attacker with access to the device who may be able to extract it. This may lead to further attacks, such as identity theft, or compromise of the application's backend. + +## Mitigations + +The following are generic recommendations to avoid logging sensitive data in production releases: + +- Avoid logging sensitive data at all. +- Redact sensitive data in logs. +- Remove logging statements unless deemed necessary to the application or explicitly identified as safe, e.g. as a result of a security audit. +- Use log levels properly to ensure that sensitive data is not logged in production releases. +- Use flags to disable logging in production releases. + +The documentation for each platform provides best practices for developers: + +- [Android mitigations to avoid log disclosure](https://developer.android.com/privacy-and-security/risks/log-info-disclosure#mitigations) +- [iOS mitigations to avoid log disclosure](https://developer.apple.com/documentation/os/logging/generating_log_messages_from_your_code#3665948) diff --git a/techniques/android/MASTG-TECH-0009.md b/techniques/android/MASTG-TECH-0009.md index 88e83e2958..6d0a69acfd 100644 --- a/techniques/android/MASTG-TECH-0009.md +++ b/techniques/android/MASTG-TECH-0009.md @@ -20,3 +20,7 @@ With the following command you can specifically grep for the log output of the a ```bash adb logcat | grep "$(adb shell ps | grep | awk '{print $2}')" ``` + +If you already know the app PID you may give it directly using `--pid` flag. + +You may also want to apply further filters or regular expressions (using `logcat`'s regex flags `-e , --regex=` for example) if you expect certain strings or patterns to come up in the logs. diff --git a/techniques/android/MASTG-TECH-0014.md b/techniques/android/MASTG-TECH-0014.md index a879b1ac03..b2200f9c29 100644 --- a/techniques/android/MASTG-TECH-0014.md +++ b/techniques/android/MASTG-TECH-0014.md @@ -3,3 +3,33 @@ title: Static Analysis on Android platform: android --- +Static analysis is a technique used to examine and evaluate the source code of a mobile application without executing it. This method is instrumental in identifying potential security vulnerabilities, coding errors, and compliance issues. Static analysis tools can scan the entire codebase automatically, making them a valuable asset for developers and security auditors. + +Two good examples of static analysis tools are grep and [semgrep](https://semgrep.dev/). However, there are many other tools available, and you should choose the one that best fits your needs. + +## Example: Using grep for Manifest Analysis in Android Apps + +One simple yet effective use of static analysis is using the `grep` command-line tool to inspect the `AndroidManifest.xml` file of an Android app. For example, you can extract the minimum SDK version (which indicates the lowest version of Android the app supports) with the following `grep` command: + +```bash +grep 'android:minSdkVersion' AndroidManifest.xml +``` + +This command searches for the `android:minSdkVersion` attribute within the manifest file. Ensuring a higher `minSdkVersion` can reduce security risks, as older versions of Android may not include the latest security features and fixes. + +## Example: Using semgrep for Identifying Weak Cryptography + +semgrep is a more advanced tool that can be used for pattern matching in code. It's particularly useful for identifying complex coding patterns that might lead to security vulnerabilities. For example, to find instances where a deterministic seed is used with the `SecureRandom` class (which can compromise the randomness and thus the security), you can use a semgrep rule like: + +```yaml +rules: + - id: insecure-securerandom-seed + patterns: + - pattern: new SecureRandom($SEED) + - pattern-not: $SEED = null + message: "Using a deterministic seed with SecureRandom. Consider using a more secure seed." + languages: [java] + severity: WARNING +``` + +This rule will flag any instances in the code where `SecureRandom` is initialized with a specific seed, excluding cases where the seed is null (which implies a secure random seed). diff --git a/techniques/android/MASTG-TECH-0033.md b/techniques/android/MASTG-TECH-0033.md index e2a413f0e5..b162718dac 100644 --- a/techniques/android/MASTG-TECH-0033.md +++ b/techniques/android/MASTG-TECH-0033.md @@ -5,4 +5,11 @@ platform: android In contrast to method profiling, which tells you how frequently a method is being called, method tracing helps you to also determine its input and output values. This technique can prove to be very useful when dealing with applications that have a big codebase and/or are obfuscated. -As we will discuss shortly in the next section, `frida-trace` offers out-of-the-box support for Android/iOS native code tracing and iOS high level method tracing. If you prefer a GUI-based approach you can use tools such as [RMS - Runtime Mobile Security](0x08a-Testing-Tools.md#RMS-Runtime-Mobile-Security) which enables a more visual experience as well as include several convenience [tracing options](https://github.com/m0bilesecurity/RMS-Runtime-Mobile-Security#3-hook-on-the-fly-classesmethods-and-trace-their-args-and-return-values). +If you prefer a GUI-based approach you can use tools such as [RMS - Runtime Mobile Security](0x08a-Testing-Tools.md#RMS-Runtime-Mobile-Security) which enables a more visual experience as well as include several convenience [tracing options](https://github.com/m0bilesecurity/RMS-Runtime-Mobile-Security#3-hook-on-the-fly-classesmethods-and-trace-their-args-and-return-values). + +If you prefer the command line, Frida offers a useful syntax to query Java classes and methods as well as Java method tracing support for frida-trace via `-j` (starting on frida-tools 8.0, Frida 12.10). + +- In Frida scripts: e.g. `Java.enumerateMethods('*youtube*!on*')` uses globs to take all classes that include "youtube" as part of their name and enumerate all methods starting with "on". +- In frida-trace: e.g. `-j '*!*certificate*/isu'` triggers a case-insensitive query (`i`), including method signatures (`s`) and excluding system classes (`u`). + +Refer to the [Release Notes for Frida 12.10](https://frida.re/news/2020/06/29/frida-12-10-released/ "Frida 12.10") for more details on this new feature. To learn more about all options for advanced usage, check the [documentation on the official Frida website](https://frida.re/docs/frida-trace/ "documentation"). diff --git a/techniques/android/MASTG-TECH-0034.md b/techniques/android/MASTG-TECH-0034.md index a2252c2e2c..032b784a4d 100644 --- a/techniques/android/MASTG-TECH-0034.md +++ b/techniques/android/MASTG-TECH-0034.md @@ -54,10 +54,3 @@ Many binaries are stripped and don't have function name symbols available with t ```bash frida-trace -p 1372 -a "libjpeg.so!0x4793c" ``` - -Frida 12.10 introduces a new useful syntax to query Java classes and methods as well as Java method tracing support for frida-trace via `-j` (starting on frida-tools 8.0). - -- In Frida scripts: e.g. `Java.enumerateMethods('*youtube*!on*')` uses globs to take all classes that include "youtube" as part of their name and enumerate all methods starting with "on". -- In frida-trace: e.g. `-j '*!*certificate*/isu'` triggers a case-insensitive query (`i`), including method signatures (`s`) and excluding system classes (`u`). - -Refer to the [Release Notes for Frida 12.10](https://frida.re/news/2020/06/29/frida-12-10-released/ "Frida 12.10") for more details on this new feature. To learn more about all options for advanced usage, check the [documentation on the official Frida website](https://frida.re/docs/frida-trace/ "documentation"). diff --git a/techniques/android/MASTG-TECH-0100.md b/techniques/android/MASTG-TECH-0100.md new file mode 100644 index 0000000000..a5d76fc122 --- /dev/null +++ b/techniques/android/MASTG-TECH-0100.md @@ -0,0 +1,149 @@ +--- +title: Logging Sensitive Data from Network Traffic +platform: android +--- + +[mitmproxy](MASTG-TOOL-0097) can be used to intercept network traffic from Android apps. This technique is useful for identifying sensitive data that is sent over the network, as well as for identifying potential security vulnerabilities. + +Once with mitmproxy installed and your device configured to use it, you can create a python script to filter the traffic and extract the sensitive data. For example, the following script will extract all the data sent in the requests and responses only if the data is considered sensitive. For this example we consider sensitive data to be any data that contains the strings "dummyPassword" or "sampleUser", so we include them in the `SENSITIVE_STRINGS` list. + +```python +# mitm_sensitive_logger.py + +from mitmproxy import http + +# This data would come from another file and should be defined after identifying the data that is considered sensitive for this application. +# For example by using the Google Play Store Data Safety section. +SENSITIVE_DATA = { + "precise_location_latitude": "37.7749", + "precise_location_longitude": "-122.4194", + "name": "John Doe", + "email_address": "john.doe@example.com", + "phone_number": "+11234567890", + "credit_card_number": "1234 5678 9012 3456" +} + +SENSITIVE_STRINGS = SENSITIVE_DATA.values() + +def contains_sensitive_data(string): + return any(sensitive in string for sensitive in SENSITIVE_STRINGS) + +def process_flow(flow): + url = flow.request.pretty_url + request_headers = flow.request.headers + request_body = flow.request.text + response_headers = flow.response.headers if flow.response else "No response" + response_body = flow.response.text if flow.response else "No response" + + if (contains_sensitive_data(url) or + contains_sensitive_data(request_body) or + contains_sensitive_data(response_body)): + with open("sensitive_data.log", "a") as file: + if flow.response: + file.write(f"RESPONSE URL: {url}\n") + file.write(f"Response Headers: {response_headers}\n") + file.write(f"Response Body: {response_body}\n\n") + else: + file.write(f"REQUEST URL: {url}\n") + file.write(f"Request Headers: {request_headers}\n") + file.write(f"Request Body: {request_body}\n\n") +def request(flow: http.HTTPFlow): + process_flow(flow) + +def response(flow: http.HTTPFlow): + process_flow(flow) +``` + +Now you can run mitmproxy with the script: + +```bash +mitmdump -s mitm_sensitive_logger.py +``` + +Our example app has this code: + +```java +fun testPostRequest() { + val thread = Thread { + try { + val url = URL("https://httpbin.org/post") + val httpURLConnection = url.openConnection() as HttpURLConnection + httpURLConnection.requestMethod = "POST" + httpURLConnection.doOutput = true + httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded") + + val user = "sampleUser" + val password = "dummyPassword" + + val postData = "username=$user&password=$password" + + val outputStream = BufferedOutputStream(httpURLConnection.outputStream) + val bufferedWriter = BufferedWriter(OutputStreamWriter(outputStream, "UTF-8")) + bufferedWriter.write(postData) + bufferedWriter.flush() + bufferedWriter.close() + outputStream.close() + + val responseCode = httpURLConnection.responseCode + if (responseCode == HttpURLConnection.HTTP_OK) { + Log.d("HTTP_SUCCESS", "Successfully authenticated.") + } else { + Log.e("HTTP_ERROR", "Failed to authenticate. Response code: $responseCode") + } + + } catch (e: Exception) { + e.printStackTrace() + } + } + thread.start() +} +``` + +The app sends a POST request to `https://httpbin.org/post` with the body `username=sampleUser&password=dummyPassword`. `httpbin.org` is a website that returns the request data in the response body, so we can see the data that was sent in the request. + +Run the app and use it as you normally would. The script will log any sensitive data that is sent over the network to the `sensitive_data.log` file. + +Example console output: + +```bash +[10:07:59.348] Loading script mitm_sensitive_logger.py +[10:07:59.351] HTTP(S) proxy listening at *:8080. +[10:08:08.188][127.0.0.1:64701] server connect httpbin.org:443 (52.206.94.89:443) +[10:08:08.192][127.0.0.1:64709] server connect mas.owasp.org:443 (104.22.27.77:443) +[10:08:08.245][127.0.0.1:64709] Client TLS handshake failed. The client does not trust the proxy's certificate for mas.owasp.org (OpenSSL Error([('SSL routines', '', 'ssl/tls alert certificate unknown')])) +[10:08:08.246][127.0.0.1:64709] client disconnect +[10:08:08.246][127.0.0.1:64709] server disconnect mas.owasp.org:443 (104.22.27.77:443) +127.0.0.1:64701: POST https://httpbin.org/post + << 200 OK 548b +``` + +Example `sensitive_data.log` output: + +```bash +REQUEST URL: https://httpbin.org/post +Request Headers: Headers[(b'Content-Type', b'application/x-www-form-urlencoded'), (b'User-Agent', b'Dalvik/2.1.0 (Linux; U; Android 13; sdk_gphone64_arm64 Build/TE1A.220922.021)'), (b'Host', b'httpbin.org'), (b'Connection', b'Keep-Alive'), (b'Accept-Encoding', b'gzip'), (b'Content-Length', b'42')] +Request Body: username=sampleUser&password=dummyPassword + +RESPONSE URL: https://httpbin.org/post +Response Headers: Headers[(b'Date', b'Tue, 16 Jan 2024 09:08:08 GMT'), (b'Content-Type', b'application/json'), (b'Content-Length', b'548'), (b'Connection', b'keep-alive'), (b'Server', b'gunicorn/19.9.0'), (b'Access-Control-Allow-Origin', b'*'), (b'Access-Control-Allow-Credentials', b'true')] +Response Body: { + "args": {}, + "data": "", + "files": {}, + "form": { + "password": "dummyPassword", + "username": "sampleUser" + }, + "headers": { + "Accept-Encoding": "gzip", + "Content-Length": "42", + "Content-Type": "application/x-www-form-urlencoded", + "Host": "httpbin.org", + "User-Agent": "Dalvik/2.1.0 (Linux; U; Android 13; sdk_gphone64_arm64 Build/TE1A.220922.021)", + "X-Amzn-Trace-Id": "Root=1-65a64778-78495e9f5d742c9b0c7a75d8" + }, + "json": null, + "origin": "148.141.65.87", + "url": "https://httpbin.org/post" +} +``` diff --git a/tools/network/MASTG-TOOL-0097.md b/tools/network/MASTG-TOOL-0097.md new file mode 100644 index 0000000000..c020c3c2c7 --- /dev/null +++ b/tools/network/MASTG-TOOL-0097.md @@ -0,0 +1,35 @@ +--- +title: mitmproxy +platform: network +source: https://github.com/mitmproxy/mitmproxy/ +--- + +[mitmproxy](https://mitmproxy.org/ "mitmproxy") is a free and open source interactive HTTPS intercepting proxy. + +- **Command Line**: `mitmdump` is the command-line version of mitmproxy. Think tcpdump for HTTP. It can be used to intercept, inspect, modify and replay web traffic such as HTTP/1, HTTP/2, WebSockets, or any other SSL/TLS-protected protocols. You can prettify and decode a variety of message types ranging from HTML to Protobuf, intercept specific messages on-the-fly, modify them before they reach their destination, and replay them to a client or server later on. +- **Web Interface**: `mitmweb` is a web-based interface for mitmproxy. It gives you a similar experience as in Chrome's DevTools, plus additional features such as request interception and replay. +- **Python API**: Write powerful addons and script mitmproxy with mitmdump. The scripting API offers full control over mitmproxy and makes it possible to automatically modify messages, redirect traffic, visualize messages, or implement custom commands. + +## Installation + +```bash +brew install mitmproxy +``` + +The installation instructions are [here](https://docs.mitmproxy.org/stable/overview-installation). + +## Usage + +The documentation is [here](https://docs.mitmproxy.org/stable/). Mitmproxy starts as a regular HTTP proxy by default and listens on `http://localhost:8080`. You need to configure your browser or device to route all traffic through mitmproxy. For example, on Android emulator you need to follow the steps indicated [here](https://docs.mitmproxy.org/stable/howto-install-system-trusted-ca-android/). + +For example, to capture all traffic to a file: + +```bash +mitmdump -w outfile +``` + +This runs mitmproxy with the add_header.py script, which simply adds a new header to all responses. + +```bash +mitmdump -s add_header.py +```