
CVE-2026-74943، استخدام بعد التحرير في Firefox RasterImage (أمني-عالي)
يحتوي هذا الدليل على هيكل إعادة إنتاج أمين لثغرة استخدام بعد التحرير عبر الخيوط (cross-thread use-after-free) في mozilla::image::RasterImage::OnSurfaceDiscarded. وهو مُصمَّم ليُشغَّل مقابل نسخة Firefox ضعيفة تم تنزيلها محليًا باستخدام بيانات صور اصطناعية فقط. ولا يمسّ أبدًا أي نظام حي أو تابع لطرف ثالث.
مستودع PoC المطابق: https://github.com/defineid/Revenant
التحليل المكتوب: writeup-rasterimage-uaf.html في هذه المجموعة.
تم تأكيد هذه الحقائق عبر تفكيك النسخة الضعيفة (libxul.so، Firefox 140.9.0esr) أثناء البحث الأصلي؛ ولقطة الشاشة الملتزمة assets/writeup-uaf-disasm.png هي ذلك التحليل. تأتي أسماء الدوال من ملف رموز Mozilla Breakpad الرسمي لتلك النسخة بالضبط؛ إذ إن libxul.so المُرفَق منزوع الرموز (stripped). ولم يُعَد تفكيكها في البيئة التي جمّعت حزمة PoC هذه (انظر حالة التحقق).
| الحقيقة | الدليل | المصدر |
|---|---|---|
الدالة الضعيفة هي RasterImage::OnSurfaceDiscarded(SurfaceKey const&) | FUNC 3eba200 16c 0 mozilla::image::RasterImage::OnSurfaceDiscarded(...) | خادم رموز Mozilla .sym |
قراءة بايت مبكرة عند this+0xC0 (التحليل المكتوب: mIsBeingDestroyed) | 3eba20a: cmp BYTE PTR [rdi+0xc0],0x0 حيث rdi = this | objdump -d libxul.so |
AddRef على عدّاد مراجع RasterImage عند this+0x40 | 3eba25a: lock inc QWORD PTR [rbx+0x40] (صادر مرتين)، rbx = this | objdump -d libxul.so |
يُخصَّص runnable بحجم 0x20 بايت ويلتقط this | 3eba264: mov edi,0x20 → call moz_xmalloc@plt؛ 3eba280: mov QWORD PTR [rax+0x10],rbx | objdump -d libxul.so |
يُرسَل الـ runnable، ثم يُحرَّر this | 3eba298: call QWORD PTR [rcx+0x28] (إرسال افتراضي)؛ 3eba29b: lock dec QWORD PTR [rbx+0x40] | objdump -d libxul.so |
وصول العدّاد إلى 0 يشغّل ~RasterImage ثم free | je 3eba345 → call 3ebbe90 <~RasterImage> → call free@plt | objdump + .sym |
الـ runnable المُرسَل يلتقط لامبدا OnSurfaceDiscarded::$_0 | FUNC 5279d90 ... RunnableFunction<...OnSurfaceDiscarded(...)::$_0>::Run() | خادم رموز Mozilla .sym |
| الحقل | القيمة |
|---|---|
| CVE | CVE-2026-74943 |
| المكوّن | Core / Graphics: ImageLib |
| الفئة | استخدام بعد التحرير (CWE-416) |
| الخطورة | sec-high (أمان ذاكرة يمكن الوصول إليه عبر الويب) |
| تم الإصلاح في | Firefox 154 · ESR 140.14 |
| العلّة | bugzilla.mozilla.org/show_bug.cgi?id=2057308 (مقيّد أمنيًا) |
تُخطر SurfaceCacheImpl::Remove الصورة المالكة بأن سطحًا مفكوك الترميز قد أُهمِل عبر استدعاء OnSurfaceDiscarded من خلال مؤشر ImageKey خام وغير مالك، على خيط decoder / ImageIO، أثناء إمساكه بقفل ذاكرة التخزين المؤقت للسطح (surface cache mutex). وفي النسخة الضعيفة، يقوم ذلك المعالج بما يلي:
this+0xC0 مبكرًا (cmp BYTE PTR [rdi+0xc0],0x0). يحدّد التحليل المكتوب هذا بأنه mIsBeingDestroyed، وهو تخفيف سابق.this عبر زيادة عدّاد مراجع RasterImage عند this+0x40 (lock inc QWORD PTR [rbx+0x40]). وهذا مجرد add-ref عادي، وليس add-ref-if-nonzero ذريًا.moz_xmalloc(0x20) كائن RunnableFunction يلتقط this (mov QWORD PTR [rax+0x10],rbx)، ويرسله إلى هدف حدث عام (call QWORD PTR [rcx+0x28])، ثم يحرّر المرجع المحلي (lock dec QWORD PTR [rbx+0x40]).ولأن قراءة العلم وزيادة العدّاد هما عمليتان منفصلتان تجاه عدّاد مراجع خالٍ من الأقفال (lock-free)، فقد تتجاوزان اللحظة التي يُسقط فيها الخيط الرئيسي المرجع الأخير. عندئذٍ يقوم خيط decoder بعمل AddRef من الصفر، فيُحيي كائنًا التزم مُدمِّره (destructor) بالفعل. وعندما ينتهي المُدمِّر ويقوم بـ free لكائن RasterImage، يعمل الـ runnable المُصطف لاحقًا على الخيط الرئيسي ويقرأ ذاكرة محرَّرة.
يوقف الإصلاح الإشارة المباشرة إلى الصورة: يلتقط OnSurfaceDiscarded مرجعًا
قويًا إلى ProgressTracker المُعدّ مرجعيًا بشكل منفصل، ويستعيد الصورة على
الخيط الرئيسي عبر المرجع الخلفي الضعيف الخاص بالمتتبع، ويرقّيه بعملية
add-ref-if-live ذرّية؛ وتُزال راية mIsBeingDestroyed.
تقود صفحة ويب عادية في عملية المحتوى ضغط ذاكرة التخزين المؤقت للأسطح (العديد من الأسطح المفكوكة القابلة للتجاهل) بينما تحرّر الإطار الذي يملك طلبات الصور. لا حاجة إلى نقرة أو إذن أو إضافة أو تغيير تفضيل. السباق بين إشعار التجاهل من خيط فك الترميز والتحرير النهائي للصورة نفسها من الخيط الرئيسي.
https://ftp.mozilla.org/pub/firefox/releases/140.9.0esr/.
يجعل بناء ASAN (Nightly asan أو بناء محلي بـ --enable-address-sanitizer)
الاستخدام بعد التحرير قابلًا للملاحظة كتقرير نظيف بدلًا من انهيار صامت
عابر.<canvas> في وقت التشغيل؛ ولا يحمّل شيئًا من الشبكة.افتح trigger.html في البناء المصاب بالثغرة، ويُفضّل من مسار file:// أو من
خادم محلي ثابت تتحكم به:
/path/to/firefox --new-instance --profile ./poc-profile ./trigger.html
بشكل افتراضي يشغّل السائق حلقة مهام دقيقة محكمة لتحقيق أقصى تداخل بين فك الترميز والتحرير. إضافة ?tick=N إلى عنوان URL تبدّله إلى حلقة setTimeout(N) مُفسِحة تعمل بجهد مماثل لكنها تتيح لحلقة الأحداث التنفس، وهو ما يسمح لسائق آلي بالتنقل بين الصفحات والتقاط لقطات شاشة أثناء تشغيلها. التُقط ملف trigger-running.png المضمّن بهذه الطريقة بالضبط، عبر تشغيل بناء 140.11.0esr المحلي من خلال Marionette مع ?tick=4: فهو يُظهر أداة الاختبار وهي تعمل مباشرةً (الدورات وعمليات التفكيك تتزايد). ذلك البناء مُرقَّع، لذا لا يحدث أي انهيار؛ الصورة تثبت فقط أن السائق يعمل. في الوضع بلا واجهة (headless) لا تُرسم الصور خارج الشاشة، لذا يبقى عدّاد "الصور المفكوكة الترميز" عند 0 هناك؛ أما البناء المُعرَّض للخطر بواجهة رسومية فيفكّ ترميزها وهو المكان الذي يُمارَس فيه التسابق.
اترك الصفحة تعمل. فهي تفكّ ترميز العديد من الصور الكبيرة المتميزة بشكل متكرر (لملء ذاكرة التخزين المؤقت للسطح وإجبار الإخلاء) بينما تفكّك شجرة DOM الفرعية التي تملكها (لدفع التحرير النهائي للصورة المالكة). هذا يعظّم التداخل بين "تجاهل السطح" على خيط فك الترميز و"التحرير الأخير" على الخيط الرئيسي. التسابقات احتمالية؛ اتركها تعمل.
heap-use-after-free يكون فيه إطار READ داخل
RasterImage::OnSurfaceDiscardedInternal / الـ runnable المُرسَل، مع إطار
freed في تفكيك RasterImage::Release. بدون ASAN قد يظهر ذلك كانهيار
متقطع في عملية المحتوى.ProgressTracker ويُسقط الإشعار عندما
يكون التدمير قد تمّ بالفعل.libxul.so المُعرَّض للخطر (140.9.0esr) وتأكدت كل حقيقة على مستوى
الثنائي في الجدول الأول أعلاه بايتًا ببايت مقابل ملف رموز Mozilla الرسمي؛
وملف assets/writeup-uaf-disasm.png المضمّن هو ذلك العمل. الادعاءات
البنيوية الثلاثة من التقرير (قراءة العلامة المبكرة this+0xC0؛ lock inc
لـ AddRef عند this+0x40؛ runnable من moz_xmalloc(0x20) يلتقط this،
ويُرسِل، ثم يُحرّر) كلها صحيحة.يستهدف هذا بناءً مُنزَّلًا محليًا ببيانات اصطناعية مولّدة ذاتيًا، من أجل تقرير عن CVE مُرقَّع بالفعل. لا يهاجم أي خدمة حية أو تابعة لطرف ثالث ولا يحتوي على أي بدائية استغلال تتجاوز تحريض العيب.