
استغلال عن بُعد لنظام ملفات الشبكة في ويندوز لـ CVE-2022-30136
المؤلف: Ricardo Narvaja
لأغراض العرض التوضيحي فقط. الاستغلال الكامل يعمل على أنظمة Windows Server المعرضة للخطر.
اطّلع على الشرح تحليل CVE-2022-30136 "ثغرة نظام ملفات الشبكة في ويندوز".
أردت كتابة هذا المقال لتوضيح التحليل الذي أجريته أثناء تطوير استغلال Core Impact المعروف باسم "Windows Network File System Remote" والذي يستغل الثغرة CVE-2022-30136.
ثغرة تنفيذ التعليمات البرمجية عن بُعد في نظام ملفات الشبكة في ويندوز هي خطأ في حساب الحجم يحدث عند إنشاء استجابة الخادم في طلب COMPOUND REQUEST باستخدام الإصدار 4.1 من NFS.
يحسب الخادم حجمًا أصغر من اللازم لتخصيص الـ pool، ثم عند نسخ البيانات لإنشاء الاستجابة، يتجاوز سعة المخزن المؤقت.
يتم استدعاء الدالة Nfs4SvrXdrpGetEncodeOperationResultByteCount في nfssvr.sys لكل عملية وتُرجع حجمًا أصغر من اللازم (أقل بمقدار 4 بايت لكل عملية).
تم إصدار تصحيح للدالة Nfs4SvrXdrpGetEncodeOperationResultByteCount.
تُستدعى هذه الدالة أثناء كل عملية من عمليات طلب COMPOSE REQUEST بحيث تُرجع البايتات اللازمة لكل عملية بناءً على OPCODE. ثم يُضاف ذلك إلى الترويسة والأجزاء الأخرى من الاستجابة. بعد ذلك، تقوم بحساب الحجم النهائي للاستجابة بالكامل لتخصيصه ثم تنسخ عليه للرد.
في كل حالة، يمكننا ملاحظة أن قيمة الحجم المُرجَع لكل عملية أصغر بأربعة بايتات في النسخة المعرضة للخطر مقارنة بالنسخة المصححة.
قمت ببناء الـ POC لـ Windows Server 2019.
فيما يلي النسخة المعرضة للخطر من nfssvr.sys المستخدمة في هذا الـ POC، تليها النسخة المصححة لـ Windows Server 2019:

الصورة التالية تُظهر CASE 26 في الفرق:

في مثال CASE 26، يمكننا ملاحظة أن الثابت المُضاف إلى القيمة المحسوبة هو 0x2c في النسخة المعرضة للخطر، و0x30 في النسخة المصححة.
يمكن ملاحظة الأمر نفسه في كل حالة تقابل كل OPCODE. النسخة المعرضة للخطر تُرجع دائمًا حجمًا أصغر بأربعة بايتات من النسخة المصححة.
لن نعرض جميع الحالات لأن التصحيح مشابه لجميع الـ OPCODES.
الدالة الأم للدالة Nfs4SvrXdrpGetEncodeOperationResultByteCount هي Nfs4SvrXdrEncodeCompoundResults. وهي تقرأ عدد العمليات المرسلة في طلب COMPOUND REQUEST.
في هذا الـ POC تكون القيمة 0x34 (52 بالنظام العشري). عندما يتصل الـ POC بالخادم على المنفذ 2049 (المنفذ الافتراضي لـ NFS)، أحتاج إلى وضع نقطة توقف شرطية للتوقف.


في هذه الحالة، يتوقف عندما يكون number_of_operations=0x34.

يتم تخصيص الـ pool بالعلامة ARGS هنا.

سأقوم بعد ذلك بإنشاء بنية باسم TAG_ARGS_0x10e0 لعكس الحقول.

يقوم بنسخ number_of_operations إلى r13 والمرور في حلقة على الدالة المعرضة للخطر مرة واحدة لكل عملية، حتى يصل العداد إلى قيمة r13.

يُظهر أن أول package_OPCODE = 0x35، والذي يقابل SEQUENCE في أول عملية إلزامية في طلب COMPOUND REQUEST. في الصورة أدناه، يشير السهم إلى هذا الـ OPCODE في الحزمة الخاصة بي.

هنا يمكننا رؤية وسائط الدالة المعرضة للخطر.


داخل الدالة المعرضة للخطر، تقوم بقراءة الـ OPCODE والانتقال إلى CASE المقابلة.

يُطرح ثلاثة من قيمة الـ OPCODE الأصلية (53).

وتقفز إلى CASE 50، لتعيد 0x28 كحجم لازم لهذه العملية.


يمكننا أن نرى في الفرق كيف تُرجع النسخة المصححة 0x2c.

تُضاف هذه القيمة المُعادة إلى القيمة السابقة للحقول الأخرى في الاستجابة من أجل حساب حجم العمليات. في هذه الحالة، هذه القيمة هي 0X40c.

أدناه يمكننا رؤية القيم التي يتم جمعها:

عند الخروج من الحلقة، يتم حساب الحجم الإجمالي. في هذه الحالة، الحجم الإجمالي هو 0x1310.

يمكننا تخمين الفرق بين النسخة المعرضة للخطر والنسخة المصححة عن طريق حساب الحجم باستخدام المعادلة: number_of_operations * 4.
في هذه الحالة، سيكون التخصيص في النسخة المصححة أكبر بمقدار 0x34 * 4 = 0x68 من النسخة المعرضة للخطر.

بعد ذلك تضيف 0x24. يتم حساب هذه القيمة بطريقة مماثلة في كل من النسختين المعرضة للخطر والمصححة.

ثم تضيف الثابت 0xf في كلتا الحالتين.

حتى هذه النقطة، بلغ الحجم في هذا المثال 0x1340.

بعد ذلك تصل إلى rpcxdr_OncRpcBufMgrpAllocate.

ثم تنتقل إلى r15.


تطرح واحدًا وتضيف أربعة. ثم تقارن مع 0x800.
يُستخدم هذا الحجم المحسوب بشكل خاطئ فقط إذا كان أكبر من 0x800. لهذا السبب، فقط طلب COMPOUND REQUEST هو ما سيُطلق العلة.

أولاً تقوم بتخصيص pool بحجم = 0x80 وبالعلامة XdBD.

أخيرًا، تقوم بتخصيص pool الخاص بالرد هنا بحجم 0x1398، مع إضافة بعض القيم الثابتة.

ثم تخصص 0x13a0 (بما في ذلك العلامة XdBP والترويسة).

من هناك، تقوم بتخزين عنوان الـ pool المخصص الجديد في الحقل: tag_XdBD_0x80.p_TAG_XDBP_0x13a0.

يشير هذا إلى عنوان الرد الذي تنسخ إليه دائمًا.

بعد ذلك ستبدأ في بناء ترويسة الرد.

فيما يلي مثال على كيفية حفظ البيانات في محتوى مؤشر مؤقت وإضافة أربعة إليه.


أدناه يمكننا رؤية كيف تنسخ إلى محتويات عنوان الرد.

هذا يكتب أول dword ويزيد المؤشر بمقدار أربعة.

بعد ذلك يكتب ثاني dword ويضيف أربعة.


بعد الخروج من الدالة، يتم كتابة الترويسة بالكامل.

بعد ذلك تعود إلى nfssvr.sys لمواصلة كتابة الرد.

ستستمر في فك الترميز والكتابة في الرد، مع إضافة أربعة إلى المؤشر المؤقت.

عند اكتمال الترويسة، تصل إلى هذه الحلقة لكتابة جميع العمليات. تبدأ بأول OPCODE وهو 0x35.


يمكننا رؤية أنها تكتب 0x428 من بداية الـ pool.

الآن يشير المؤشر إلى ما بعد العلامة.


بوضع نقطة توقف هنا، يمكننا رؤية كيفية كتابة جميع العمليات.


بعد الخروج من الحلقة، يتم نسخ جميع العمليات.

لنفحص نهاية الـ pool.

هناك يمكننا رؤية الكتابة بعد الحد.

التخصيص أصغر من البيانات المنسوخة، مما يؤدي إلى تجاوز سعة الـ pool.
هذا يؤدي إلى ظهور شاشة الموت الزرقاء (BSOD) على الجهاز المستهدف. ولكن السؤال هو: هل يمكننا تحقيق تنفيذ التعليمات البرمجية عن بُعد، أو استغلال من نوع Write what where؟
جربت عددًا من تركيبات الـ opcodes للحصول على رد ببيانات خاضعة للتحكم في البايتات المتجاوزة. لسوء الحظ، لم أوفق.
العلامة القصوى (التي أتحكم بها) يمكن وضعها فقط في البداية ويبلغ حجمها الأقصى 0x400.

جميع الـ opcodes الأخرى التي جربتها لا ترد ببيانات خاضعة للتحكم. وبالتالي، لا أعتقد أنه من الممكن، أو على الأقل أنه من الصعب للغاية، الحصول على RCE أو رفع صلاحيات باستخدام هذه العلة. ومع ذلك، قد يظل ذلك ممكنًا، حيث أنني لم أجرب جميع التركيبات من بين العدد الكبير من الاحتمالات الموجودة.
من أجل بناء الـ POC، جربت استخدام عميل باسم "NFS CLIENT". إنه يدعم NFS 4.1 وقد تمكنت من تجربة opcodes مختلفة من خلال نسخ الملفات وتعديلها وإنشاء المجلدات وما إلى ذلك.

في هذا البناء، تمكنت من إنشاء حزمة COMPOUND نموذجية وضبط الحجم ومعرف العميل ومعرف الجلسة وما إلى ذلك.

بعد ذلك، أرسلت EXCHANGE_ID للحصول على معرف العميل، مستخدمًا إياه لإرسال CREATE_SESSION وأخيرًا طلب COMPOUND REQUEST الكبير.

عند هذه النقطة، تكون العلة قد تم استغلالها، مما يؤدي إلى تنفيذ التعليمات البرمجية عن بُعد والسماح بهجوم حجب الخدمة (DoS).
نأمل أن تجد هذا مفيدًا، وإذا كان لديك أي استفسار يمكنك التواصل معنا على [email protected].
استمتع!