
CVE-2026-43499 استغلال GhostLock للحصول على صلاحيات الجذر على Chromecast مع Google TV (sabrina)
استغلال جذري (root) لجهاز Chromecast with Google TV (sabrina) عبر CVE-2026-43499 -- ثغرة use-after-free في النظام الفرعي futex PI (وراثة الأولوية) في نواة Linux.
يحقق صلاحيات root على جهاز ذي bootloader مقفل يعمل بنظام Android 14 مع نواة 5.15.170 (PGO+BOLT+LTO، clang 17).
يستغل GhostLock خطأً في remove_waiter() يُستدعى من مسار التراجع -EDEADLK داخل rt_mutex_start_proxy_lock(). تُفرِّغ الدالة current->pi_blocked_on (الخاصة بمُعيد الإدراج، وهو NULL أصلاً) بدلاً من الخاصية الخاصة بمهمة المنتظر. لا يُفرَّغ pi_blocked_on الخاص بالمنتظر أبداً، مما يترك مؤشراً معلقاً (dangling pointer) إلى rt_mutex_waiter محرَّر على مكدس النواة.
يؤدي استدعاء sched_setattr لاحق إلى rt_mutex_adjust_pi -> rt_mutex_adjust_prio_chain، الذي يتبع المؤشر المعلق ويمر عبر سلسلة PI على بيانات يتحكم بها المهاجم على صفحة heap مُستعادة -- مما يمنح بدائية كتابة عشوائية (arbitrary write) عبر rb_erase.
| المرحلة | التقنية |
|---|---|
| تسريب KASLR | perf_event_open مع PERF_SAMPLE_IP (مقيَّد بـ TID) — أدنى عنوان IP للنواة يقع في .entry.text (+0x10000)، و_text محاذى إلى 2MB وإزاحة KASLR من مضاعفات 2MB، لذا يستعيد min_ip & ~0x1fffff قيمة _text وقت التشغيل بدقة |
| تسريب بنية المهمة (task struct) | perf_event_open مع PERF_SAMPLE_REGS_INTR (مقيَّد بـ TID، نمط عناوين الخريطة الخطية) |
| التحقق من جدول الرموز | يستخرج perf-samples قيمة &init_user_ns من وسائط السجلات في security_capable() أثناء عاصفة setpriority(-20) ويطابقها مع kaslr_base + off_init_user_ns — يثبت أن تخطيط .data/.bss للنواة العاملة يطابق جدول الإزاحات قبل أي كتابة عمياء |
| تسريب mm_struct | KernelSnitch -- قناة جانبية توقيتية عبر تصادم futex hash |
| رشّ الـ heap | تنسيق إسقاط SLUB (memfd-close، فيضان CPU-partial) + استعادة صفحات من الرتبة 2 عبر io_uring_setup(256) |
| تراكب المكدس | AF_UNIX SOCK_SEQPACKET sendmsg -- تنسخ move_addr_to_kernel عنوان sockaddr بحجم 128 بايت إلى مكدس النواة، متراكبةً فوق حقول task/lock/prio الخاصة بالمنتظر المعلق |
| إطلاق المشي | sched_setattr مع سلّم nice تصاعدي (7 -> 14 -> 19) يُطلق مشي سلسلة PI، واحد لكل جولة تراكب |
| بدائية الكتابة | rb_erase الحالة 1: `{pc=(TARGET-8) |
| إيقاف SELinux (المشي 0) | صفر بحجم 8 بايت عند selinux_state يمسح enforcing وcheckreqprot وinitialized وpolicycap[0..4] — لا يرفض avc_denied() أبداً (enforcing=0) ويقصر security_compute_av() على السماح للكل (!initialized)، لذا لم يعد kernel-SID بعد التبديل (u:r:kernel) ذا أهمية |
| تبديل بيانات الاعتماد (المشيان 1+2) | task->cred = fake_cred وtask->real_cred = fake_cred (uid=0، صلاحيات FULL، user_namespace مزيف مكتفٍ ذاتياً على صفحة الرشّ؛ الكتابتان مطلوبتان — إذ يُطلق commit_creds() عند exec خطأ BUG_ON ما لم يكن cred == real_cred) |
| بطارية root | فحوص تعتمد على استدعاءات النظام الخام فقط (uid/SELinux//proc/1//dev/kmsg/wifi/packages//data/data/kallsyms) إلى /data/local/tmp/.ghostlock_out |
| صدفة root | execve("/system/bin/sh") — ينسخ commit_creds في مسار exec قيمة fake_cred إلى بيانات اعتماد slab نظيفة؛ مشروط بوصول جميع عمليات المسح المخطط لها |
rb_right = 0 مخزنًا صفريًا نظيفًا واحدًا بحجم 8 بايت في عنوان kernel عشوائي (دون مخزن جانبي، ودون إرجاعات مؤشر برية)؛ فتصفير أول qword من selinux_state يمنح permissive مزدوجًا (enforcing=0 + !initialized → allow-all)، مما يزيل العائق أمام كل إدخال/إخراج للملفات بعد الحصول على root رغم SID الخاص بالـ kernel&init_user_ns عبر perf من مسار security_capable() الحي ويتوقف إلى مسار cred-only ما لم يطابق kaslr_base + off_init_user_nsucounts = NULL -- يطابق cap_capable في التكرار الأول وينهي inc_rlimit_ucounts بعد حلقة واحدة، ما يزيل الحاجة إلى تسريب &init_user_nsPERF_SAMPLE_TID أن تُحتسب لقطات السجلات الخاصة بالخيط المستدعي فقط، مما يمنع خدمات النظام النشطة من الهيمنة على تصويت الوضع5.15.170-android14-11-gf4a1f03072af (aarch64، PGO+BOLT+LTO، clang 17.0.2)CONFIG_FUTEX_PI=y، CONFIG_IO_URING=y، perf_event_paranoid=-1، SELinux في وضع enforcing، panic_on_oops=1، بلا user namespacesexport ANDROID_NDK_HOME=/path/to/android-ndk
make -j$(nproc)
يتطلب Android NDK (تم اختباره باستخدام r27). ينتج ملفًا ثنائيًا aarch64 مرتبطًا بشكل ثابت.
adb push ghostlock /data/local/tmp/
adb shell "cd /data/local/tmp && ./ghostlock --cred"
يستغرق الاستغلال حوالي 25 ثانية (تسريبات KASLR/task/layout + رشّ الكومة + القوة الغاشمة عبر KernelSnitch + ثلاث جولات تراكب مدة كل منها 3 ثوانٍ). عند النجاح، يكتب بطارية الروت إلى /data/local/tmp/.ghostlock_out، والعلامة إلى /data/local/tmp/.ghostlock_root، وينفّذ /system/bin/sh بمعرّف مستخدم uid=0 ضمن نواة متساهلة.
مفاتيح ضبط البيئة:
GHOST_SELINUX=0 — تخطَّ كتابة SELinux، وشغّل المسار المُثبت الخاص بالاعتمادات فقط (الوضع 6)GHOST_SELINUX_FORCE=1 — فعّل كتابة SELinux حتى لو فشل التحقق من تخطيط رموز الجهازGHOST_EXEC=0 — اكتب البطارية ثم نفّذ exit(99) بدلاً من تنفيذ صدفةCRED_ATTEMPTS=n — عدد مرات إعادة المحاولة بالرشّ الكامل عندما تفشل جولة في استعادة السيطرة (الافتراضي 3)تم نقل هذا الاستغلال وتطويره بواسطة Claude Opus 4.6 (Anthropic) مع GLM-5.3 (Z.ai) كمستشار لاستغلال النواة.
kernel/futex/، kernel/locking/rtmutex.c، lib/rbtree.cنُشر هذا الاستغلال لأغراض البحث الأمني والتعليم. وهو يستهدف جهازًا يملكه الباحث. لا تستخدمه على أجهزة لا تملكها أو دون تصريح.
MIT