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

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
vsock_poc — التحقيق في الخلل وراء CVE-2021-26708 | Kitploit
أدوات/GitHubGitHub/jordan9001/vsock_poc
تحليل الثغرات الأمنيةالاستغلالمصممي الأخطاءالأوراق والأبحاثالتعلم والتعليماستغلال الملفات الثنائية
GitHubjordan9001/vsock_poc

vsock_poc

التحقيق في الخلل وراء CVE-2021-26708

عرض المستودع
282منذ 5 سنواتتمت المراجعة من قبل Kitploit

الأكثر شعبية

عرض الكل →

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

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

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

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

vsock_poc

التحقيق في الثغرة الكامنة خلف CVE-2021-26708


يحتوي هذا المستودع على شرح موجز حول CVE-2021-26708، وكيف يمكن تحويل هذه الثغرة إلى بدائية كتابة بعد التحرير (Use After Free). إن PoC هنا ليس استغلالًا كاملًا، بل مجرد بيئة الاختبار التي استخدمتها عند محاولة التحقيق في هذه الثغرة. يمكنها بنجاح استخدام مدخل من ذاكرة kmalloc-64 بعد تحريره، لكنها لا تحتوي على أي كود لتنسيق الذاكرة ووضع شيء ذي أهمية في الخانة.

هذه ثغرة ممتعة أبلغ عنها @a13xp0p0v. لفتت انتباهي لأن التصحيح كان بسيطًا للغاية، فقط منع الحصول على مرجع إلى vsk->transport خارج القفل (lock) في 5 مواضع مختلفة. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c518adafa39f37858697ac9309c6cf1805581446

فيما يلي شرح مختصر للعملية الانتقالية من التصحيح إلى بدائية استخدام بعد التحرير التي يمكن استخدامها للاستغلال. يجب أن يكون هذا الشرح مفيدًا للآخرين الذين يرغبون في استكشاف هذه الثغرة.

إعداد البيئة

قمت بتنزيل نواة لينكس 5.10.13، وتراجعت يدويًا عن التصحيح الموضح أعلاه. لمزيد من المعلومات حول بناء وتشغيل النواة، يعتبر ما يلي مرجعًا جيدًا.

https://fedoraproject.org/wiki/Building_a_custom_kernel

كما قمت بتعديل معاملات الإقلاع لتمكين تصحيح أخطاء النواة باستخدام kgdb. باستخدام gdb مع ملف vmlinux الذي بنيته سابقًا، كانت لدي جميع رموز النواة الرئيسية، ولكن ليس لأي وحدات نواة قابلة للتحميل. لم يتم تحميل الكود المرتبط بالثغرة افتراضيًا، ولكن سيتم تحميله في النواة عند استخدام عائلة PF_VSOCK (اعتمادًا على طريقة بناء نواتك).

للحصول على الرموز في kgdb للوحدات المحمّلة، تأكدت من استخدام مقبس vsock مرة واحدة على الأقل، ثم استخدمت sudo cat /proc/modules | grep vsock للحصول على العناوين الأساسية للوحدات المرتبطة. في gdb كنت أقوم بعد ذلك بشيء مثل (gdb) add-symbol-file ./net/vmw_vsock/vsock.ko 0xffffffffc0567000 لجعل gdb على علم بمكان رموز ملف ko في الذاكرة. كان vsock.ko و vmw_vsock_virtio_transport_common.ko هما الأكثر صلة.

اصطياد البدائية

من الممتع العمل backward من التصحيحات لأنه وعلى عكس الكثير من بحث الثغرات، أنت تعلم يقينًا أنك تبحث بالفعل في المكان الصحيح. في هذه الحالة، نعرف من التصحيح أن مرجعًا إلى الناقل (transport) يتم حفظه قبل الحصول على sock_lock. يمكننا أن نتوقع بأمان أن الثغرة ناتجة عن تغيير الناقل، ولكن يتم استخدام المرجع القديم.

في هذا النوع من السيناريوهات، نأمل أن يكون الناقل نفسه كائنًا مخصصًا ديناميكيًا يمكن تحريره واستبداله بكائن آخر بين الحصول على المرجع وعقد القفل. لسوء الحظ، عندما نتتبع أعمار النواقل ذات الصلة المنفذة بواسطة الوحدات الأخرى، يبدو أنها جميعًا في ذاكرة عامة. لذا سنبحث على مستوى أعمق عن العناصر المستخدمة عندما تكون خارج النطاق.

التحرير الجزء 1

بالنظر في af_vsock.c، يمكننا العثور على موضعين حيث يتم تعديل vsk->transport. في vsock_assign_transport و vsock_deassign_transport. في vsock_assign_transport، نرى أنه إذا كان هناك ناقل موجود مختلف، فسيتم استدعاء vsock_deassign_transport قبل وضع الناقل الجديد. إذا نظرنا إلى الاحتمالات لاستدعاء vsk->transport->destruct(vsk) هنا، نرى أن كلاً من نواقل loopback و virtio ستقوم فقط بـ kfree لمعامل vsk->trans هنا. ممتاز! إذا تمكنا من إيجاد (1) مسار إلى هذا الاستدعاء يمكن أن يتسابق مع (2) دالة قابلة للاستغلال تستخدم مرجع ناقل من قبل أن يتم تدميره للوصول إلى vsk->trans، فستكون لدينا بدائيتنا.

بالنظر إلى مسار إلى vsock_deassign_transport، نراه يُستدعى من vsock_sk_destruct أو vsock_assign_transport. يتم تعيين vsock_sk_destruct كدالة sock->destruct، وبالتالي فإن الاستدعاءات إلى __sys_close، أو استدعاءات أخرى متاحة على طول مسار التدمير مثل sock_put، أو sock_close، أو vsock_release يمكن أن تنتهي هنا.

المسار الأكثر صلة إلى vsock_assign_transport هو عبر vsock_stream_connect، ولكنه يتطلب أن يكون المقبس في حالات محددة قليلة، وينتهي فقط باستدعاء vsock_deassign_transport إذا كان الناقل سيتغير. وسيستبدل معامل vsk->trans إذا لم ينتهِ بنا الأمر إلى ناقل جديد NULL.

الاستخدام

قبل أن نتعمق أكثر في تحديد المسار الصحيح للتحرير، نريد التأكد من وجود مسار صالح يستخدم عضو vsk->trans مع مرجع غير صالح إلى ناقل مُدمَّر. يمكننا التحقق بشكل منهجي من كل موضع يُستخدم فيه الناقل مع مرجع ربما يكون غير صالح. بتتبع تلك الثقوب، يمكننا العثور على المواضع التي يُستخدم فيها vsk->trans. يبدو أن أفضل مسار هو عبر vsock_stream_setsockopt هنا، عندما يقوم transport->notify_buffer_size بالكتابة إلى إزاحة داخل vsk->trans لكل من نواقل loopback و virtio مباشرة هنا. إذا كان trans محررًا بالفعل عند استخدامه هناك، نحصل على كتابة جميلة لقيمة u32 إلى إزاحة 0x28 في تخصيص kmalloc-64.

التسابق

اعتماد استخدام vsock_stream_setsockopt كبدائية يعتمد على تسابق حيث بين الحصول على مرجع الناقل، والحصول على sock_lock. تلك نافذة صغيرة، وهناك الكثير من التعليمات للوصول إلى هناك. لذا يمكننا هنا استخدام ميزة رائعة في لينكس تسمى userfaultfd لزيادة فرصنا. تتيح لنا هذه الآلية معالجة أخطاء الصفحات (pagefaults) في وضع المستخدم على مهلنا. انظر https://man7.org/linux/man-pages/man2/ioctl_userfaultfd.2.html و https://man7.org/linux/man-pages/man2/userfaultfd.2.html.

بهذا يمكننا أن يكون لدينا خيط (البوابة) سيحصل على sock_lock ثم يصل إلى ذاكرة مستخدم ويسبب خطأ صفحة. يمكننا إبقاء هذا الخيط متوقفًا (مع بقاء القفل محتفظًا به) طالما أردنا. الخيوط الأخرى التي تحاول الحصول على ذلك القفل ستبقى هناك حتى نطلق سراح البوابة ونحرر القفل. يمكننا محاذاة الخيط الذي سينتهي به الأمر إلى التدمير، والخيط الذي سيستخدم المرجع غير الصالح. كلاهما سينتظر على sock_lock، والآن لدينا فرصة كبيرة للفوز بالتسابق. إذا تم اختيار الخيط الذي يقوم بالتدمير للحصول على القفل بعد ذلك، فسيتم تنفيذ استدعاء setsockopt بعدها. سيستخدم مؤشر vsk->trans بعد أن تم تحريره (واستبداله).

إذا تم استدعاء setsockopt أولاً بدلاً من ذلك، فإننا نخسر التسابق، ولكن يمكننا محاولة العملية بأكملها مرة أخرى بأمان.

التحرير الجزء 2

عند محاولة بناء هذا، أمضيت وقتًا طويلاً في الاتجاه الخاطئ. حاولت استدعاء vsock_deassign_transport عبر close و timeouts، لكنني اصطدمت بالكثير من فحوصات عدد المراجع التي أخرت التدمير الفعلي حتى فات الأوان.

كملاحظة جانبية، قد يكون تصحيح أخطاء هذه المسارات صعبًا؛ كما يمكنك أن تتخيل، سيتم الوصول إلى نقطة توقف على استدعاء النظام close كثيرًا. حتى إذا استخدمت نقاط توقف شرطية للتوقف فقط في الخيط المناسب، ستبطأ الآلة إلى حد الزحف. مسار مثير للاهتمام حول هذا هو استخدام ebpf مع نقاط تتبع (tracepoints) التي ستستدعي فقط bpf_trace_printk إذا كانت الشروط صحيحة. ثم يمكن وضع نقطة توقف kgdb على bpf_trace_printk، والتي ستقربنا من الموضع الصحيح. هذا لا يعمل مع kprobes لأنك بالفعل داخل معالج نقطة توقف. أعتقد أن إضافة استدعاء bpf_trace_kgdb_break إلى ebpf يمكن أن يكون إضافة لطيفة إلى النواة.

عندما تحولت أخيرًا إلى النظر في مسار vsock_assign_transport، اجتمع الأمر بسرعة. من أجل تلبية المتطلبات، نتصل أولاً بـ VM_ADDR_CID_LOCAL، عندما لا يوجد خادم يستمع. سيعطينا هذا ناقل loopback، ولكن بعد ذلك عندما تنتهي مهلة اتصالنا أو يفشل، ستعود حالتنا إلى SS_UNCONNECTED. يسمح لنا هذا بإجراء اتصال آخر بعنوان أكبر من VM_ADDR_CID_HOST، مما سيؤدي إلى تغيير ناقلنا، وتدمير الناقل الموجود لدينا والتسبب في التحرير. من المهم أن نفعل هذا عندما لا يكون هناك في الواقع أي transport_g2h أو transport_h2g مسجّل، بحيث يكون ناقلنا الجديد NULL، ويبقى مرجعنا المحرر في vsk->trans.

الاستغلال

مع كل ذلك في مكانه، نحصل على استخدام-after-free موثوق يمكن استخدامه لتصعيد الامتيازات.

هذا المستودع يتعلق فقط بوصولنا إلى الاستخدام-after-free الأولي. لكن الآن لدينا بدائية لكتابة قيمة عند إزاحة في ذاكرة kmalloc-64 حيث تم تخصيص virtio_vsock_sock سابقًا. قررت إيقاف الشرح عند ذلك لأنه، ماذا، هل يجب أن أفعل كل شيء هنا؟

تنزيل الأداة