Suture عبارة عن أداة تحليل ثابتة من النقاط إلى درجة عالية من النقاط (لـ C) (لـ C) استنادًا إلى LLVM IR ومبنية على Dr. Checker (شكرًا جزيلاً لمبدعيها!) ، وهما أبرز ما:
نحن نسميها خياطة على أمل أن تكون دقيقة جراحياً ، مع التمكن من تجزئة وظائف SYSCALLS/الدخول المتعددة معًا لإنشاء تدفقات بيانات عالية الترتيب. لمزيد من التفاصيل ، يرجى الرجوع إلى ورقتنا: اكتشاف الثغرات الأمنية ذات النمط العالي في حبات OS في ACM CCS'21 .
أول استنساخ الريبو:
~$ git clone https://github.com/seclab-ucr/SUTURE.git suture
ثم قم بإعداد بيئة LLVM للخياطة:
~$ cd suture
~/suture$ python setup_suture.py -o ../suture_deps
الخيارات (لـ setup_suture.py ):
-b يحدد اسم فرع LLVM ليتم إعداده ل SUTURE ، وهو الافتراضيات إلى "الإصدار_90" (IE ، LLVM 9.0) في ريبو المرآة LLVM.-o يحدد المجلد لاستضافة جميع الأشياء المطلوبة بواسطة Suture (على سبيل المثال ، LLVM) ، استخدم أي مجلد تفضله. بناءً على أجهزتك ، قد يستغرق إعداد LLVM بعض الوقت. بعد الانتهاء من ذلك ، سيتم إنشاء ملف SRCIPT المسمى env.sh تحت مجلد Suture Root ، ويحتوي على أوامر لتعيين متغيرات البيئة المستخدمة بواسطة Suture.
مهم : تأكد من تنشيط هذا env.sh في كل مرة قبل بناء/استخدام خياطة (يمكنك أيضًا إضافة أوامرها الموجودة إلى .bashrc للتنشيط التلقائي عند تسجيل الدخول إلى Shell)!
~/suture$ source env.sh
بعد ذلك سنبني خياطة:
~/suture$ cd llvm_analysis
~/suture/llvm_analysis$ ./build.sh
عند بناء ناجح ، فإن الخياطة جاهزة للاستخدام.
يمكن استخدام خياطة لاكتشاف نقاط الضعف عالية الترتيب خارج الصندوق ، في هذا القسم نسير خلال هذه العملية مع مثال (على سبيل المثال ، المثال المحفز كما هو موضح في القسم 2.1 في ورقتنا).
لاكتشاف نقاط الضعف يتطلب خياطة نوعين من المدخلات: (1) وحدة البرنامج التي تم تجميعها إلى LLVM Bitcode (على سبيل المثال ، ملف .bc ) ، و (2) ملف تكوين للوحدة التي تُظهر وظائف الإدخال والوسائط التي يسيطر عليها المستخدم.
دعنا أولاً نقوم بإعداد LLVM bitcode للحصول على مثالنا المحفز:
~/suture$ cd benchmark
~/suture/benchmark$ ./gen.sh motivating_example
ملاحظة : من أجل الراحة ، نقدم gen.sh لتجميع A .c to .bc و .ll (LLVM bitcode القابل للقراءة البشرية) ، مع مستوى تحسين -O1 .
الآن يجب أن يكون لدينا divivating_example.bc ضمن نفس المجلد القياسي ، وهذا هو وحدة برنامج الإدخال للخياطة.
ثم يتعلق الأمر بملف التكوين ، قمنا بالفعل بإعداد واحد للمثال المحفز:
~/suture/benchmark$ cat conf_motivating_example
entry0 MY_IOCTL 1
entry1 NULL_ARG
entry2 NULL_ARG
Explanation : يصف كل سطر في ملف التكوين معلومات وظيفة الإدخال (على سبيل المثال ، الدالة ذات المستوى الأعلى مع المتصلين وعادة ما تكون بمثابة الواجهة الخارجية) في وحدة البرنامج ، فإنها تحتوي على ما يصل إلى 3 رموز منفصلة عن الفضاء:
entry_x MY_IOCTL 0_2 .لذلك كما هو موضح أعلاه ، يحدد Conf_motivating_example أن هناك ثلاث وظائف إدخال في divivating_example.c : الإدخال (المعلمة 1 يتم التحكم فيها بين المستخدمين) ، الإدخال 1 والإدخال 2 (لا توجد معلمات يتحكم فيها المستخدم). هذا يطابق رمز المثال المحفز.
بمجرد أن يكون رمز bitcode وملف تكوين الإدخال جاهزين ، يمكننا تشغيل Suture لاكتشاف نقاط الضعف:
~/suture$ ./run_nohup.sh benchmark/motivating_example.bc benchmark/conf_motivating_example
Explanation : Run_nohup.sh هو برنامج نصي بسيط يستدعى تمريرات LLVM المترجمة من خياطة:
~/suture$ ./run_nohup.sh [path/to/program.bc] [path/to/entry_func_config]
بمجرد البدء ، اعتمادًا على الأجهزة الفعلية وتعقيد البرنامج المستهدف ، يختلف الوقت المطلوب ل Suture لإنهاء التحليل واكتشاف الضعف كثيرًا. عادة ما ينتهي برنامج بسيط مثل مثالنا المحفز على الفور.
حدد ما إذا كان التحليل ينتهي : أثناء التنفيذ ، يستمر Suture في تسجيل الدخول إلى ملف ضمن نفس الدليل لملف التكوين ، لنفترض أن مسار ملف التكوين هو /مسار/إلى/conf_program ، سيكون ملف السجل / Path/TO/CONF_PROGRAM.LOG. يمكننا أن نقرر ما إذا كان التحليل ينتهي من خلال مراقبة السجل:
~/suture$ grep "Bug Detection Phase finished" benchmark/conf_motivating_example.log
ملف السجل المذكور أعلاه هو أيضًا ناتج Suture ، سيقوم Suture بتضمين نقاط الضعف المحتملة المكتشفة في ملف السجل ، والذي يمكن استخلاصه وتنظيمه في تقرير تحذير نهائي بعد انتهاء التحليل:
~/suture$ ./ext_warns.sh benchmark/conf_motivating_example.log
Explanation : Ext_warns.sh سوف تستخرج جميع التحذيرات (في JSON) المضمنة في ملف السجل المحدد ، وإعادة تنظيمها وطبأتها إلى تقارير التحذير النهائية. سيتم وضع تقارير التحذير في مجلد تحت نفس المسار من ملف السجل ، لنفترض أن ملف السجل هو /path/to/ conf_program.log ، سيكون مجلد تقرير التحذير /مسار/إلى/تحذير conf_program-yyyyy-mm-dd .
~/suture$ ls benchmark/warns-conf_motivating_example-2021-11-10/
all int_overflow taint_data_use taint_loopbound taint_ptr_def
يوجد في المجلد 5 تقارير تحذير ، وكلها تحتوي على جميع أنواع التحذيرات التي تم تجميعها معًا وفقًا لعلاقة تدفق البيانات الخاصة بهم ، في حين أن التقارير الأخرى تحتوي فقط على أنواع محددة من التحذيرات (على سبيل المثال ، تدفق عدد صحيح ، ومؤشر ملوث ، وما إلى ذلك) ، المزيد من التفاصيل حول كيفية العثور على تحذيرات جماعية في ورقتنا (القسم 4). عادة ما نستخدم التقرير الموحد فقط.
~/suture$ cat -n benchmark/warns-conf_motivating_example-2021-11-10/all
1 =========================GROUP 0 (2 - 2)=========================
2 #####Warned Insts#####
3 (u'motivating_example.c', 30, [u'IntegerOverflowDetector'])
4 ######################
5
6 ++++++++++++++++WARN 0 (2 - 2)++++++++++++++++
7 IntegerOverflowDetector says: motivating_example.c@30 (bar : %add = add i8 %0, -16, !dbg !31)
8 ********Trace 0(2)********
9 #####CTX##### entry0
10 entry0 (motivating_example.c@18)
11 #####INSTS#####
12 >>>>>>>>>>>>>>>>>>tag: 0x55b206570420 tf: 0x55b20695b1b0 (2)>>>>>>>>>>>>>>>>>>
13 motivating_example.c@18 ( %cond = icmp eq i32 %cmd, 0, !dbg !31)
14 motivating_example.c@21 ( store i8 %user_input, i8* getelementptr inbounds (%struct.data, %struct.data* @d, i64 0, i32 1, i64 0), align 4, !dbg !32, !tbaa !34)
15 #####CTX##### entry1 -> bar
16 entry1 (motivating_example.c@35)
17 ----> (motivating_example.c@35 : %call = tail call i32 @bar(i8* bitcast (%struct.data* @d to i8*)), !dbg !27)
18 bar (motivating_example.c@30)
19 #####INSTS#####
20 >>>>>>>>>>>>>>>>>>tag: 0x55b2065e7050 tf: 0x55b2068174f0 (1)>>>>>>>>>>>>>>>>>>
21 motivating_example.c@30 ( %0 = load i8, i8* %add.ptr, align 1, !dbg !31, !tbaa !32)
22 motivating_example.c@30 ( %add = add i8 %0, -16, !dbg !31)
23
Explanation : على مستوى عالٍ ، يحتوي تقرير التحذير على بعض مجموعات التحذير ، تحتوي كل مجموعة على العديد من التحذيرات ، ويحتوي كل تحذير على العديد من آثار taint التي تنشأ من مدخلات المستخدم وتغرق إلى نفس بيان البرنامج الحساس. بمعنى آخر ، يتم رفع تحذير واحد لبيان برنامج معين ونوع محدد (على سبيل المثال ، تدفق عدد صحيح) ، في حين أن المجموعة تحتوي على تحذيرات متعددة وثيقة الصلة من منظور تدفق البيانات (انظر القسم 4 في ورقتنا) ، وبالتالي قد يكون للمجموعة بيانات برنامج تحذير متعددة وتشمل أنواع تحذير مختلفة.
خذ تقرير التحذير أعلاه كمثال:
===GROUP No. (min_order - max_order)=== ، حيث يكون min_order هو الحد الأدنى من الترتيب (على سبيل المثال ، ببساطة وضع ، والترتيب هو أوقات دعوة وظيفة الدخول المطلوبة في مجموعة taint ، انظر القسم 3.2 في الورقة الخاصة بنا للحصول على تعريف أكثر رسمية.) max_order المتبعات هذه في هذه المجموعة.WARN No. محلي لمجموعته.***Trace No. (order)*** ، فإن تتبع taint دائمًا لديه ترتيب فريد يمكن حسابه (على سبيل المثال ، وليس النطاق).يحدد تقرير التحذير ضعفًا صحيحًا في التدفق الصحيح في المثال المحفز ، مع تجنب الإنذارات الخاطئة المحتملة التي قد تولدها أداة تحليل ثابتة أقل دقة ، يمكن العثور على التفاصيل في القسم 2.1 من ورقتنا.
يحتوي هذا الريبو أيضًا على بعض الأدوات/البرامج النصية الأخرى التي قد تجدها مفيدة.
~/suture$ python llvm_analysis/AnalysisHelpers/EntryPointIdentifier/entry_point_identifier.py /path/to/prog_module.bc
~/suture$ cat /path/to/prog_module.bc.all_entries
Explanation : يمكن لهذا البرنامج النصي تحديد بعض وظائف الإدخال الشائعة في وحدة برنامج تشغيل جهاز Linux (على سبيل المثال ، IOCTL () ، قراءة () ، الكتابة () ، إلخ) ، مما يساعد على بناء ملف تكوين الإدخال كمدخل إلى خياطة. يتم تنفيذ هذه الأداة في الغالب بواسطة Dr. Checker الأصلي استنادًا إلى بعض معارف مجال kernel (على سبيل المثال ، هياكل بيانات محددة مثل File_operations المستخدمة لتحديد نقاط إدخال برنامج التشغيل) ، ثم قمنا ببعض التحسينات (على سبيل المثال ، جعل الاستدلال أكثر قوة).
~/suture$ python flt_warns.py /path/to/warn_report [Regex] > /path/to/filtered_warn_report
Explanation : من تجربتنا ، غالبًا ما تشترك العديد من الإنذارات الخاطئة في تقرير التحذير في نفس تتبع الشجار الفرعي (انظر القسم 6.3 في ورقتنا). طالما أن مراجع التحذير يتفقد إنذارًا كاذبًا ويتعرف على تتبع فرعي يحفز FP ، وبطبيعة الحال ، يمكنها محاولة استبعاد جميع الإنذارات الخاطئة الأخرى التي تحتوي على نفس المسار الفرعي ، مما يقلل من معدل الإنذار الخاطئ المتصدر للمراجع. لهذا الغرض ، نقدم هذا flt_warns.py البسيط الذي يأخذ تقرير التحذير الأصلي والتعبير العادي للبيثون كمدخلات ، وسيتطابق بعد ذلك مع كل أثر taint في التقرير ، بمجرد مطابقة ، سيتم التعامل مع تتبع taint كإنذار خاطئ. سيقوم البرنامج النصي بإنشاء تقرير تحذير جديد تم ترشيحه باستثناء جميع آثار التلوث المتطابقة.
قد تكون مهتمًا باستخدام Suture كتحليل ثابت للأغراض العامة (على سبيل المثال ، الحصول على مجموعة من النقاط إلى/taint من المتغير في موقع برنامج معين) ، وهذا أمر مؤكد ، ولكن على عكس اكتشاف الضعف ، تحتاج إلى الحصول على اليدين القذرة والغوص في رمز الخياطة المراد التعرف عليه مع هياكل البيانات الرئيسية التي تستخدمها وبعض الوظائف المهمة. آمل أن تساعد النصائح التالية:
يتطور LLVM بسرعة كبيرة ، دون ضمان على التوافق المتخلف. من المحتمل جدًا أن تواجه بعض أخطاء التجميع عند محاولة بناء خياطة مع إصدار LLVM الأحدث (على سبيل المثال ،> 9.0). لكن لحسن الحظ ، عادة ما تكون أخطاء التجميع هذه سهلة حلها (على سبيل المثال ، غالبًا ما نحتاج فقط إلى استبدال واجهات برمجة تطبيقات LLVM القديمة بأحدث). لذا ، في الأساس ، لتكييف Suture مع إصدار LLVM الأحدث ، نحتاج أولاً إلى إعداد LLVM الأحدث في 0x0 (على سبيل المثال ، بحاجة إلى تعديل setup_suture.py لاستنساخ LLVM repo من مصدر نشط وتحديد اسم الفرع الأحدث) ، ثم حاول بناء suture ضدها ، حل أخطاء المواجهة.