
أداة إثبات مفهوم (PoC) وfuzzer لتظليل GLSL لثغرة CVE-2026-9999 في الواجهة الخلفية ANGLE/Metal الخاصة بـ WebGL في متصفح Chrome، مع تحديد بصمة البناء، وتظليلات مُنسّقة، والتقاط آثار الانهيار.
| الحقل | القيمة |
|---|---|
| CVE | CVE-2026-9999 |
| البائع / المنتج | Google Chrome |
| المتأثر | Chrome < 148.0.7778.216، نظام macOS فقط [1] |
| تم الإصلاح في | 148.0.7778.216 [1] |
| التأثير | تنفيذ تعليمات برمجية عشوائية داخل صندوق الحماية (sandbox) عبر صفحة HTML مصمّمة بعناية [1] |
| شدة Chromium | عالية [1] |
| CVSS 3.1 (CISA-ADP) | 8.8 عالية — CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H [1] |
| تقييم CVSS من NVD (NIST) | لم يُقدَّم بعد [1] |
| CWE | CWE-269 — إدارة امتيازات غير سليمة (إثراء بواسطة CISA-ADP) [1] |
| SSVC من CISA (2026-05-29) | exploitation: none, automatable: no, technicalImpact: total [1] |
| النشر / آخر تعديل | 2026-05-28 / 2026-07-21 [1] |
| السبب الجذري | غير معلن — مشكلة Chromium 513364480 تظهر "Permissions Required" [1] |
الآثار المترتبة على سلسلة الهجوم: تنفيذ التعليمات البرمجية "داخل صندوق الحماية" [1] يعني أن المهاجم يحصل على السيطرة على عملية معزولة (على الأرجح عملية GPU). وللاستيلاء الكامل على المتصفح، يلزم إضافيًا هروب منفصل من صندوق الحماية ليس جزءًا من هذه الثغرة.
ما يلي استنتاج من السجلات العامة، وليس حقائق مؤكدة:
لذلك، يختبر هذا الإطار (harness) تلك الأنماط تحديدًا ثم يغيّر GLSL على نطاق واسع للبحث عن انهيار من جهة العارض (فقدان سياق WebGL = انهيار عملية GPU أو قتلها بواسطة المراقب watchdog).
| الملف | الغرض |
|---|---|
cve-2026-9999-poc.html | إطار PoC مكتفٍ ذاتيًا (بدون تبعيات): تحديد إصدار البناء، 8 shaders مختارة لضغط المترجم، مدمج Fuzzer للـ GLSL مع التقاط أثر الانهيار |
README.md | هذا الملف |
أرشيف Chrome for Testing من Google يوفر إصدارات مثبتة بواسطة رقم الإصدار لا يتم تحديثها تلقائيًا. ابحث عن أحدث بناء معرّض للخطر (كل ما هو أقل من 148.0.7778.216 متأثر [1]):
import json, urllib.request
data = json.load(urllib.request.urlopen(
"https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json"))
key = lambda v: tuple(int(x) for x in v.split('.'))
fix = (148, 0, 7778, 216)
cands = sorted((v["version"] for v in data["versions"]
if "chrome" in v.get("downloads", {}) and key(v["version"]) < fix), key=key)
print(cands[-5:]) # pick the last (newest vulnerable) entry
نزّل لمعمارية جهازك (uname -m):
# Apple Silicon
https://storage.googleapis.com/chrome-for-testing-public/<VERSION>/mac-arm64/chrome-mac-arm64.zip
# Intel
https://storage.googleapis.com/chrome-for-testing-public/<VERSION>/mac-x64/chrome-mac-x64.zip
فك الضغط إلى مجلد مختبر (مثل ~/lab/، وليس /Applications) وشغّل من هناك.
إذا كان إصدار معيّن مفقودًا من Chrome for Testing، استخدم أرشيف لقطات Chromium (commondatastorage.googleapis.com/chromium-browser-snapshots/Mac/ لمعمارية Intel، و .../Mac_Arm/ لمعمارية Apple Silicon)، المفهرس حسب موضع الالتزام (commit position) — اربط الإصدار المعرّض للخطر بموضع في الفرع عبر chromium-history، ثم اسحب أقرب لقطة. اللقطات أيضًا لا يتم تحديثها تلقائيًا.
أوقف عملاء تحديث Keystone وامنع googleupdate.googleapis.com، وإلا فسيقوم إصدار الاختبار بتصحيح نفسه بصمت بين عشية وضحاها. غير مطلوب لإصدارات Chrome for Testing.
بدون Metal، يعرض Chrome WebGL برمجيًا (SwiftShader) ولا يتم لمس خلفية ANGLE Metal أبدًا. في وحدة تحكم صفحة PoC، شغّل:
const c = document.createElement('canvas'), g = c.getContext('webgl2');
const x = g.getExtension('WEBGL_debug_renderer_info');
console.log(g.getParameter(x.UNMASKED_RENDERER_WEBGL));
// Good: contains "ANGLE Metal Renderer"
// Bad: contains "SwiftShader" -> the vulnerable path is NOT being exercised
يمكنك أيضًا التأكيد عبر chrome://gpu. عادةً ما تعمل أجهزة Parallels/VMware Fusion الافتراضية المزودة بمضاعفة GPU؛ أما إعدادات QEMU/UTM الأدنى فغالبًا ما تتراجع إلى SwiftShader.
cd <repo dir>
python3 -m http.server 8000
# then browse to http://localhost:8000/cve-2026-9999-poc.html
1) Run curated triggers. ثمانية shaders تضغط على أنماط المترجم الموصوفة في §2 (فهرسة ثوابت خارج النطاق OOB، تحديد حجم مصفوفة بتجاوز عدد صحيح، فهرسة مصفوفات ديناميكية، ضغط فك الحلقات، مصفوفات من مصفوفات، discard/swizzle، حالات ما قبل المعالج، كتل UBO ضخمة). راقب نتائج [!!] وأحداث فقدان السياق.2) Fuzz. يتم تجميع shaders GLSL معدّلة وربطها ورسمها وقراءتها في حلقة. راقب السجل بحثًا عن CONTEXT LOST.localStorage. استرجعه:
localStorage.getItem("cve20269999_poc_fs"); // crashing fragment shader
localStorage.getItem("cve20269999_crashes"); // crash event log
لقطة مباشرة لتشغيل مشبوه يمكن رؤيتها أيضًا في
chrome://gpuوفي وحدة تحكم macOS (تقارير انهيار عملية GPU).
WEBGL_context_lost ≠ ثغرة. مراقب GPU في Chrome يقتل shaders الطويلة (مُشغِّل loop-unroll-dos وتكرارات fuzz ذات أعداد حلقات ضخمة مصممة لتكون بطيئة). لتقليل الضوضاء: قلّل SH_ITER، أو تأكد من أن أي انهيار مرشّح يتكرر سريعًا (< 1 ثانية لكل تكرار).EXC_BAD_ACCESS) بدلًا من إنهاء المراقب.ابنِ نسخة معرّضة للخطر من Chromium مع AddressSanitizer:
fetch chromium
cd src
git checkout tags/148.0.7778.215 # last tag before the fix
gn gen out/asan --args='is_asan=true is_debug=false symbol_level=1 dcheck_always_on=true'
autoninja -C out/asan chrome
ثم شغّل الـ shader المصغّر المخالف مع تفعيل التحقق من واجهة Metal:
MTL_DEBUG_LAYER=1 out/asan/Chromium.app/Contents/MacOS/Chromium poc.html
سيعرض تتبع ASAN اسم دالة ANGLE/Metal المحددة ويؤكد ما إذا كان الانهيار يطابق مكوّن الثغرة [1].
(بعد ذلك: بمجرد ظهور التزام الإصلاح لـ 148.0.7778.216، قارن third_party/angle/src/libANGLE/renderer/metal/ لتحديد السبب الجذري الحقيقي واستبدل نهج fuzzing بمُشغِّل حتمي.)
exploitation: none [1].اختبر فقط على أجهزة تملكها أو مصرّح لك باختبارها صراحةً. يقوم الإطار عمدًا بتجميع shaders عدائية لتعطيل عملية الرسوميات — توقع قتل عملية GPU. أبقِ إصدار المتصفح المعرّض للخطر بعيدًا عن شبكات الإنتاج.
[1] NVD — CVE-2026-9999: https://nvd.nist.gov/vuln/detail/CVE-2026-9999 * إشعار البائع (مدونة إصدارات Chrome، تحديث القناة المستقرة): https://chromereleases.googleblog.com/2026/05/stable-channel-update-for-desktop_0877304591.html * مشكلة Chromium 513364480 (مقيدة الوصول): https://issues.chromium.org/issues/513364480