
إثبات المفهوم لـ CVE-2024-38063 (تنفيذ التعليمات البرمجية عن بُعد في tcpip.sys)
هذا هو إثبات المفهوم (POC) (غير مستقر إلى حد ما) لـ CVE-2024-38063، وهي ثغرة تنفيذ عن بُعد (RCE) في tcpip.sys تم تصحيحها في 13 أغسطس 2024. لم أجد وأبلغ عن هذه الثغرة، بل Wei.
pip3 install scapy
قم بتعديل الحقول في السكربت:
iface <- إذا كان لديك عدة محولات، فأنت بحاجة لاختيار أي منها لإرسال الحزم. مثلاً "eth0" على لينكس أو "Hyper-V Virtual Ethernet Adapter" على ويندوز. إذا كنت ستستخدم واجهتك الافتراضية، اتركه فارغًا.ip_addr <- عنوان IP للنظام المستهدف (IPv6)num_tries & num_batches <- كم عدد دفعات الحزم المختلفة التي سيتم إرسالها. المزيد منها = المزيد من تلف الكومة (heap corruptions) الناتج + احتمال أكبر لتفعيل الثغرة.mac_addr <- اتركه فارغًا، إلا إذا اشتكى scapy من عدم العثور على عنوان MAC. انظر أدناه في استكشاف الأخطاء.قم بتشغيل السكربت:
python3 cve-2024-38063.py
أسهل طريقة لإعادة إنتاج الثغرة هي باستخدام bcdedit /set debug on على النظام المستهدف وإعادة تشغيل الجهاز/الآلة الافتراضية. هذا يجعل برنامج تشغيل محول الشبكة الافتراضي kdnic.sys، وهو سعيد جدًا بدمج الحزم (coalesce). إذا كنت تحاول إعادة إنتاج الثغرة على إعداد مختلف، ستحتاج إلى وضع النظام في حالة تسمح له بدمج الحزم التي أرسلتها. يمكنك قراءة قسم استكشاف الأخطاء أدناه لمزيد من التفاصيل.
يمكنك قراءة هذا التحليل الرائع للثغرة من قبل Marcus إذا كنت مهتمًا بالتفاصيل التقنية. التفاصيل التي كتبتها أدناه تهدف إلى أن تكون ملخصًا، بدلاً من تحليل تقني جاد.
NET_BUFFER الذي يحتوي على بيانات الحزمة المخزنة مؤقتًا. عند الإزاحة 0x30 لدينا أيضًا حقل الإزاحة الحالية (current-offset) الذي يشير إلى مدى تحليل الحزمة. في هذه المرحلة، ستكون قيمة الإزاحة بشكل عام 0x28، مما يشير إلى أنه تم تحليل رأس IPv6 ولكن لا شيء غير ذلك.tcpip!Ipv6pReceiveDestinationOptions، سيؤدي خطأ في التحليل إلى استدعاء tcpip!IppSendErrorList. تقوم هذه الدالة باستدعاء tcpip!IppSendError على كل كائن حزمة في القائمة المرتبطة (بدءًا من الكائن الحالي).tcpip!IppSendError لها آثار جانبية. فهي "تعيد" بيانات الحزمة المخزنة إلى البداية وتعيد تعيين حقل الإزاحة الحالية إلى الصفر.0x8C). وهذا يعني أن برنامج التشغيل سيستمر في تحليل رؤوس الامتداد للحزم الأخرى في القائمة المرتبطة، حتى لو تم "إرجاعها" في IppSendError.0x28.Ipv6pReceiveFragment. تقوم الدالة بتحليل رأس الامتداد الجزئي (fragment extension header) وتفترض أن حقل الإزاحة للحزمة سيكون على الأقل 0x28 عند حساب طول البيانات غير الرأسية (non-header data) في الحزمة بطرح 0x30 من قيمة الإزاحة الحالية. يتم تخزين هذه القيمة بعد ذلك في كائن إعادة التجميع (reassembly object) الذي يهدف إلى إعادة تجميع الحزمة المجزأة (fragmented packet).IppSendError. ستكون قيمة الإزاحة صفرًا وستزداد إلى 8 في مكان سابق ضمن Ipv6pReceiveFragment. عند حساب حجم البيانات غير الرأسية، ستنخفض القيمة (underflow) وتصبح مساوية لـ 0xffd8 (يتم الطرح بـ 16 بت).Ipv6pReassembleDatagram، حيث تُستخدم لحساب طول المخزن المؤقت للإخراج للحزمة المعاد تجميعها. ومع ذلك، تتم جميع الحسابات بـ 32 بت ويوجد فحص سلامة أن الطول الإجمالي لا يتجاوز 0xFFFF، وهو ما يحدث في هذه الحالة.Ipv6pReassemblyTimeout، حيث تُستخدم بنفس الطريقة. ولكن الحسابات هنا تتم بـ 16 بت ويحدث تجاوز عدد صحيح (integer overflow). يؤدي هذا إلى تجاوز سعة المخزن المؤقت (buffer overflow) عند نسخ البيانات إلى المخزن المؤقت لاحقًا.لتفعيل Ipv6pReassemblyTimeout، يجب أن يكون مُرسِل الجزء غير نشط لمدة دقيقة واحدة. استراتيجيتنا هي:
IppSendError، متبوعة بحزمة جزءIpv6pReceiveFragment وإنشاء كائن إعادة تجميع جديد بطول بيانات الجزء الذي يمثل قيمة 16 بت عاليةIpv6pReassemblyTimeoutIpv6pReassemblyTimeout وتفعيل تجاوز سعة كومة (heap-based buffer overflow)يتم إغراق الحزم في السكربت بحيث يكون هناك احتمال أكبر لدمجها. الحمولة الرئيسية بسيطة جدًا:
نقوم أيضًا بتعيين حقلي حد القفز (hop limit) وحقل تسمية التدفق (flow label) في رأس IPv6 يدويًا. تذكر أن بيانات الحزمة المخزنة قد تم إعادة تعيينها بسبب الثغرة. هذا يعني أنه عند معالجة حزمة الجزء، سيتم تفسير رأس IPv6 كبيانات رأس جزء. سيتم تفسير حقل حد القفز في رأس IPv6 كأحد بتات حقل المعرف في رأس الجزء. من خلال تغييره، نضمن تفعيل الثغرة لأجزاء متعددة مختلفة والتسبب في تلفيات متعددة، مما يزيد من فرصة التعطل (لأن هذا هو إثبات المفهوم في النهاية). سيتم تفسير حقل تسمية التدفق لرأس IP كحقول الإزاحة ومؤشر "المزيد" لرأس الجزء. من خلال ضبطه على 1، نشير إلى أن هناك المزيد من الرؤوس القادمة (وبالتالي القدرة على تفعيل Ipv6pReassemblyTimeout لاحقًا) وأن الإزاحة صفر (لأن هذه هي أول حزمة بهذا المعرف تصل).
Ipv6pReassemblyTimeout يتطلب أن تكون حزمة الجزء الأصلية مرسلة كأحادية الإرسال.