-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Port MASTG-TEST-0080: Testing Enforced Updating (ios) and MASTG-TEST-0036: Testing Enforced Updating (android) #3048
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 all commits
e6d9bfc
31d64dc
7220338
7d41c6c
83e5433
e782b90
4842b6d
d874bfe
b30aced
087c243
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| --- | ||
| platform: android | ||
| title: Testing Enforced Updating | ||
| id: MASTG-TEST-0x80-1 | ||
| type: [dynamic] | ||
| weakness: MASWE-0075 | ||
| profiles: [L2] | ||
| --- | ||
|
|
||
| ## Overview | ||
|
|
||
| This test verifies whether the app enforces an update (@MASTG-KNOW-0023) when directed by the backend. In a backend-gated flow, the app typically sends the current app version (for example, via `BuildConfig.VERSION_NAME`/`BuildConfig.VERSION_CODE`) and receives a response indicating whether the version is supported. Alternatively, the app may use the [Google Play In-App Updates APIs](https://developer.android.com/guide/playcore/in-app-updates) for an immediate update (for example, [`AppUpdateManager`](https://developer.android.com/reference/com/google/android/play/core/appupdate/AppUpdateManager)). | ||
|
|
||
| ## Steps | ||
|
|
||
| 1. Apply @MASTG-TECH-0011 (MITM) to capture launch traffic and initial API calls. Filter for headers, parameters, or body fields carrying version information (for example, `X-App-Version`, `version`, `build`, `minVersion`). | ||
| 2. Use @MASTG-TECH-0033 (dynamic instrumentation) to hook relevant classes or methods that retrieve the app version (such as `BuildConfig.VERSION_NAME`) or that are specifically related to update flows (for example, `AppUpdateManager#getAppUpdateInfo`, `AppUpdateManager#startUpdateFlowForResult`, or the code that evaluates `minVersion`). | ||
|
|
||
| ## Observation | ||
|
|
||
| The output should contain: | ||
|
|
||
| - a network traffic trace showing version values in requests and corresponding backend responses for different versions | ||
| - a method trace showing which APIs were called | ||
|
|
||
| ## Evaluation | ||
|
|
||
| The test case fails if the app does not implement enforced updating. For example, if it neither uses the Play In-App Updates API nor performs backend-gated version checks or if it implements them incorrectly. | ||
|
|
||
| **Additional Verification:** | ||
|
|
||
| Validate whether the backend indicates that an update is required but the app still allows you to continue using it (this may require manual testing). For example: | ||
|
|
||
| - Try to dismiss any update prompts or navigate around them. | ||
| - Modify requests to present an older version (for example, change `version`/`build`), replay the request, and observe whether the backend response changes (for example, an error or a field indicating an update is required). |
|
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 test is also being added in https://github.com/OWASP/mastg/pull/3462/files#diff-a9d53408e3663c96701c37c093b01bd6f1a167e734915d13c6f1cdc2a6a02bf0 Let's make sure that any final content from here is added as suggestions to that PR or the test is removed from that PR and only added in this one. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| --- | ||
| platform: android | ||
| title: Testing Enforced Updating | ||
| id: MASTG-TEST-0x80 | ||
| type: [static] | ||
| weakness: MASWE-0075 | ||
| profiles: [L2] | ||
| --- | ||
|
|
||
| ## Overview | ||
|
|
||
| This test verifies whether the app enforces an update (@MASTG-KNOW-0023) when directed by the backend. The app should either send its current version to the backend or retrieve the minimum supported version and prevent usage until the app is updated. | ||
|
|
||
| On Android, enforced updates are commonly implemented using the Google Play In-App Updates API or a custom backend-gated flow that evaluates the app version retrieved via `BuildConfig.VERSION_NAME`/`BuildConfig.VERSION_CODE` (or `PackageInfo` via `PackageManager`). | ||
|
|
||
| Specifically, look for: | ||
|
|
||
| - Google Play In-App Updates classes and methods: `AppUpdateManagerFactory.create`, `AppUpdateManager#getAppUpdateInfo`, `UpdateAvailability.UPDATE_AVAILABLE`, `AppUpdateType.IMMEDIATE`/`FLEXIBLE`, `startUpdateFlowForResult`/`requestUpdateFlow`. | ||
| - Version retrieval points: `BuildConfig.VERSION_NAME`, `BuildConfig.VERSION_CODE` (or `PackageInfo` via `PackageManager`). | ||
| - Strings like `X-App-Version`, `version`, `minVersion` that may indicate version checks in network requests or other parts of the code. | ||
|
|
||
| ## Steps | ||
|
|
||
| 1. Apply @MASTG-TECH-0014 (static analysis) and search for Android update/version APIs used before authentication (for example, in `Application.onCreate`, splash/bootstrap flows, or initial `Activity.onCreate`). | ||
|
|
||
| ## Observation | ||
|
|
||
| The output should contain a list of code locations where the app retrieves or sends its version (for example, `BuildConfig.VERSION_NAME` or `PackageInfo`) and uses the Google Play In-App Updates APIs (for example, `AppUpdateManager`, `startUpdateFlowForResult`), or evaluates a backend `minVersion` response, along with a call graph snippet showing these checks execute before authentication. | ||
|
|
||
| ## Evaluation | ||
|
|
||
| The test case fails if no code paths implement an enforced update before authentication, if the identified logic is not reachable prior to authentication, or if the app displays a mandatory update message but still allows you to continue using the app (for example, dismissing the dialog or navigating around it). | ||
|
|
||
| Note that this evaluation requires manual review of the identified code paths in the reverse engineered code to confirm whether they implement enforced updating correctly. | ||
|
|
||
| For example, you should try to trace the control flow to confirm that version evaluation leads to an enforced update path, such as: | ||
| - Immediate update flow (`AppUpdateType.IMMEDIATE`), or | ||
| - A custom blocking UI (for example, a full-screen dialog/`Activity` that disables navigation) when backend `minVersion` > current version. | ||
|
|
||
| Alternatively, you can use dynamic analysis (see @MASTG-TEST-0x80-1) to confirm the identified code paths execute before authentication and enforce updating as expected. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| --- | ||
| platform: ios | ||
| title: Testing Enforced Updating | ||
| id: MASTG-TEST-0x80-2 | ||
| type: [dynamic] | ||
| weakness: MASWE-0075 | ||
| profiles: [L2] | ||
| --- | ||
|
|
||
| ## Overview | ||
|
|
||
| This test verifies whether the app enforces an update when directed by the backend. On iOS, apps typically read `CFBundleShortVersionString`/`CFBundleVersion` (for example, via `Bundle.main.infoDictionary`), send the version to a backend using [`URLSession`](https://developer.apple.com/documentation/foundation/urlsession "URLSession"), and enforce a minimum supported version returned by the backend. Some apps also query the App Store using the iTunes Search API lookup endpoint (for example, `https://itunes.apple.com/lookup?bundleId=<bundleId>` or `https://itunes.apple.com/lookup?id=<appId>`) to retrieve the latest published version from the App Store response (for example, `results[0].version`). If an update is required, the app should block usage and optionally redirect you to the App Store using [`UIApplication.open`](https://developer.apple.com/documentation/uikit/uiapplication/open(_:options:completionhandler:) "UIApplication.open") or present a StoreKit view (for example, [`SKStoreProductViewController`](https://developer.apple.com/documentation/storekit/skstoreproductviewcontroller "SKStoreProductViewController")). | ||
|
|
||
| ## Steps | ||
|
|
||
| 1. Apply @MASTG-TECH-0063 (MITM) to capture launch traffic and initial API calls. Filter for headers, parameters, or body fields carrying version information (for example, `X-App-Version`, `version`, `build`, `minVersion`). Additionally, look for requests to `https://itunes.apple.com/lookup` with `bundleId` or `id` (and optional `country`) parameters and note fields like `resultCount`, `results[0].version`, and `results[0].trackViewUrl` in the JSON response. | ||
| 2. Use dynamic instrumentation to hook relevant classes or methods that retrieve the app version (for example, `Bundle.main.infoDictionary["CFBundleShortVersionString"]`/`["CFBundleVersion"]`) or that are specifically related to update flows (for example, `URLSession` request builders/`resume`, the code that evaluates `minVersion`, `UIApplication.open`, or the parsing logic that reads `results[0].version` from the iTunes lookup response). Also, hook any StoreKit presentation code (for example, `SKStoreProductViewController`). | ||
|
|
||
| ## Observation | ||
|
|
||
| The output should contain: | ||
|
|
||
| - a network traffic trace showing version values in requests and the corresponding backend responses for different versions, including any requests to `https://itunes.apple.com/lookup` and the parsed fields (for example, `results[0].version`) | ||
| - a method trace showing which APIs were called (for example, `URLSession` request execution, version retrieval from `Bundle`, iTunes lookup parsing, and any redirection via `UIApplication.open` or StoreKit) | ||
|
|
||
| ## Evaluation | ||
|
|
||
| The test case fails if the app does not implement enforced updating. For example, if it neither performs backend-gated version checks nor blocks usage when the backend (or the iTunes lookup result) requires an update or if it implements these checks incorrectly (see below). | ||
|
|
||
| **Additional Verification:** | ||
|
|
||
| Validate whether the backend indicates that an update is required but the app still allows you to continue using it (this may require manual testing): | ||
|
|
||
| - Try to dismiss any update prompts or navigate around them. | ||
| - Modify requests to present an older version (for example, change `version`/`build`), replay the request, and observe whether the backend response changes (for example, an error or a field indicating an update is required). | ||
| - If the app uses the iTunes lookup endpoint, stub or replay the lookup response to advertise a higher `results[0].version` and verify that the app enforces the update (for example, by blocking usage or redirecting to the App Store). |
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.
Also add https://support.google.com/googleplay/android-developer/answer/13812041