فازینگ جعبهخاکستری هدایت شده مبتنی بر پوشش (Coverage-Guided Greybox Fuzzing) به یکی از رایجترین تکنیکهای کشف باگهای (Bug) نرمافزاری تبدیل شده است. معیار پوشش (Coverage Metric) که نحوه انتخاب بذرهای (Seed) جدید توسط فازر را تعیین میکند، پارامتر اساسی فازینگ است و میتواند به طور قابلتوجهی بر نتایج تأثیر بگذارد.
هرچند پژوهشهای متعددی درباره اثربخشی معیارهای پوشش مختلف بر آزمون نرمافزار انجام شده، اما اطلاعات اندکی درباره تأثیر عملی این معیارها بر نتایج فازینگ در دسترس است. مهمتر آنکه، هنوز مشخص نیست آیا معیار پوششی وجود دارد که نسبت به تمامی معیارهای دیگر برتری داشته باشد یا خیر.
در این مقاله، اولین مطالعه نظاممند درباره تأثیر معیارهای پوشش مختلف در فازینگ را گزارش میدهیم. برای این منظور، ابتدا مفهوم حساسیت (Sensitivity) را بهصورت رسمی تعریف و مورد بحث قرار میدهیم که میتواند برای مقایسه نظری معیارهای پوشش استفاده شود. سپس چندین معیار پوشش و گونههای مختلف آنها را معرفی میکنیم.
این مطالعه را روی مجموعهدادههای DARPA CGC ،LAVA-M و ۲۲۱ باینری دنیای واقعی انجام دادیم. نتایج نشان میدهد که از آنجا که هر نمونه فازینگ منابع محدودی (زمان و قدرت پردازش) دارد، (۱) هر معیار پوشش شایستگی منحصربهفردی در کشف انواع خاصی از شاخهها (Branch) دارد و (۲) هیچ معیار پوششی جامعی وجود ندارد که همه معیارهای دیگر را شکست دهد.
ما همچنین ترکیب معیارهای مختلف را از طریق بذرگذاری متقاطع (Cross-Seeding) بررسی کردیم. نتایج بسیار امیدوارکننده است: رویکرد مبتنی بر فازینگ خالص (Pure Fuzzing) ما میتواند حداقل به همان تعداد باینریهای مجموعهداده CGC که رویکرد ترکیبی قبلی Driller ترکیب فازینگ و اجرای کانکولیک (Concolic Execution) از عهده آن برمیآید، منجر به کرش شود، در حالی که از منابع محاسباتی بسیار کمتری استفاده میکند.
۱. مقدمه (Introduction)
فازینگ جعبهخاکستری (Greybox Fuzzing) یک تکنیک پیشرفته آزمون برنامه است که بهطور گسترده توسط شرکتهای بزرگ مانند گوگل [۴۵] و ادوبی [۴۷] و همچنین استارتآپهای کوچک مانند [۴۸] Trail of Bits پذیرفته شده است. در چالش بزرگ سایبری DARPA (CGC)، فازینگ جعبهخاکستری در مقایسه با رویکردهای جایگزین مانند اجرای نمادین (Symbolic Execution) و تحلیل ایستا (Static Analysis) مؤثرتر عمل کرده است [۸، ۱۵، ۳۴، ۳۷، ۳۹]. فازینگ جعبهخاکستری (greybox fuzzing) عموماً شامل سه مرحله اصلی است:
- زمانبندی بذر (Seed Scheduling)
- جهش بذر (Seed Mutation)
- انتخاب بذر (Seed Selection)
زمانبند بذر، بذر بعدی را از میان مجموعه ورودیهای بذر (Seed Inputs) انتخاب میکند. سپس در مرحله جهش بذر، با اعمال جهش (Mutation) و تقاطع (Crossover) روی بذرهای انتخاب شده، موارد آزمون (Test Case) بیشتری تولید میشود. در نهایت، موارد آزمون باکیفیت بهعنوان بذر جدید انتخاب میشوند تا چرخه ادامه یابد.
در میان این مراحل، انتخاب بذر (Seed Selection) مهمترین بخش است؛ زیرا وجه تمایز فازینگ جعبهخاکستری از فازینگ جعبهسیاه (Blackbox Fuzzing) است و هدف فازر (Fuzzer) را تعیین میکند.به عنوان مثال هنگامی که هدف بهبود پوشش (Coverage) باشد، از یک معیار پوشش برای ارزیابی کیفیت مورد آزمون استفاده میشود. زمانی که هدف رسیدن به یک نقطه کد (Code Point) خاص باشد، از فاصله (Distance) بهعنوان معیار ارزیابی استفاده میشود [۲].
شایان توجه است که اگرچه مطالعات پیشین [14، 17] نشان دادهاند که پوشش بهتر مجموعه آزمون (test suite coverage) به طور مستقیم با کیفیت بالاتر نرمافزارِ مورد آزمون مرتبط نیست، اما این مشاهده که بخشهای کدی که کمتر مورد آزمون قرار گرفتهاند، احتمال بیشتری برای داشتن باگ (bug) دارند، همچنان معتبر است. به همین دلیل، فازینگ جعبهخاکستری هدایت شده مبتنی بر پوشش (coverage-guided greybox fuzzing) همچنان یکی از مؤثرترین روشها در کاربردهای عملی به شمار میرود.
اگرچه تکنیکهای مختلفی برای بهبود فازینگ جعبهخاکستری در مرحله زمانبندی اولیه [۲، ۳، ۲۷، ۲۹] و مرحله جهش اولیه [۲۱، ۲۸، ۲۹، ۳۷، ۵۴] پیشنهاد شده است، اما تلاشهای بسیار کمی بر بهبود انتخاب بذر(Seed Selection) تمرکز دارند.]HonggFuzz ۴۰] فقط تعداد بلوکهای پایه(Basic Blocks) بازدید شده را شمارش میکند. AFL [۳۸] از نسخه بهبودیافته پوشش شاخه (Branch Coverage) استفاده میکند که علاوه بر ثبت شاخههای بازدیدشده، تعداد دفعات بازدید (Hit Count) هر شاخه را نیز در نظر میگیرد. Angora [۷] پوشش شاخه را با افزودن حساسیت به زمینه (Context Sensitivity) گسترش میدهد. مهمتر از همه، بسیاری از پرسشهای اساسی درباره معیارهای پوشش (Coverage Metrics) همچنان بیپاسخ ماندهاند.
نخست: چگونه میتوان تفاوتهای بین معیارهای پوشش مختلف را بهطور یکنواخت و نظاممند تعریف کرد؟ معیارهای پوشش را میتوان به دو دسته اصلی طبقهبندی کرد: پوشش کد (Code Coverage) و پوشش داده (Data Coverage) معیارهای پوشش کد، یکتایی (Uniqueness) موارد آزمون را در سطح کد ارزیابی میکنند، از جمله پوشش خطی (Line Coverage)، پوشش بلوک پایه (Basic Block Coverage)، پوشش شاخه/لبه (Branch/Edge Coverage) و پوشش مسیر .(Path Coverage) از سوی دیگر، معیارهای پوشش داده سعی میکنند موارد آزمون را از دیدگاه دسترسی به دادهها (مانند آدرسهای حافظه، نوع دسترسی (خواندن یا نوشتن) و توالیهای دسترسی متمایز کنند. هرچند بسیاری از معیارهای جدید بهصورت جداگانه در کارهای اخیر پیشنهاد شدهاند، اما هیچ روش نظاممند و یکسانی برای توصیف تفاوتهای بین آنها وجود ندارد. ظاهراً، معیارهای پوشش مختلف، قابلیت بسیار متمایزی در تمایز موارد آزمون دارند که ما آن را حساسیت (Sensitivity) مینامیم. بهعنوان مثال، پوشش بلوک پایه نمیتواند تفاوت بین بازدیدها از یک بلوک را از بلوکهای قبلی مختلف تشخیص دهد، در حالی که پوشش شاخهای میتواند. بنابراین، پوشش شاخهای حساستر از پوشش بلوک پایه است. تعریف نظامند و رسمی از حساسیت ضروری است؛ زیرا نه تنها تفاوتهای بین معیارهای فعلی را نشان میدهد، بلکه تحقیقات آینده را برای پیشنهاد معیارهای بهتر هدایت میکند.
دوم: آیا معیار پوشش بهینهای (Optimal Coverage Metric) وجود دارد که در فازینگ هدایتشده با پوشش، از همه معیارهای دیگر بهتر عمل کند؟ اگرچه حساسیت راهی برای مقایسه توانایی دو معیار در کشف ورودیهای جالب (Interesting Inputs) فراهم میکند، اما یک معیار حساستر همیشه منجر به عملکرد بهتر فازینگ نمیشود.
بهطور خاص، فازینگ را میتوان به عنوان مسئله باندیت چنداهرمی (Multi-Armed Bandit – MAB) [۵۱] مدلسازی کرد که در آن هر مرحله (انتخاب بذر، زمانبندی و جهش) چندین انتخاب دارد و هدف نهایی یافتن باگهای بیشتر با بودجه زمانی محدود است. یک معیار حساستر ممکن است ورودیهای بیشتری را بهعنوان بذر انتخاب کند، اما فازر ممکن است بودجه زمانی کافی برای زمانبندی همه بذرها یا جهش کافی آنها نداشته باشد. جزئیات پیادهسازی (مانند نحوه اندازهگیری واقعی پوشش) نیز میتواند این مشکل را پیچیدهتر کند. برای مثال، مطالعه قبلی [۱۲] نشان داده است که تصادم یا برخوردهای هش (Hash Collisions) میتواند حساسیت واقعی یک معیار پوشش را کاهش دهد. بنابراین، یک ارزیابی نظاممند برای درک بهتر رابطه بین حساسیت و عملکرد فازینگ ضروری است.
سوم: آیا ترکیب معیارهای مختلف در طول فازینگ ایده خوبی است؟ بهصورت فرضی، اگر معیارهای پوشش مختلف مزایای خاص خود را در طول فرآیند داشته باشند، ترکیب آنها منطقی خواهد بود تا هر معیار بهطور متفاوتی مشارکت کند. این پرسش نیز بسیار مهم است زیرا تفکر متفاوتی را برمیانگیزد و ممکن است منجر به استراتژیهای نوین برای بهبود فازینگ شود.
برای پاسخ به پرسشهای فوق، ما اولین مطالعه نظاممند درباره تأثیر معیارهای پوشش بر عملکرد فازینگ هدایتشده با پوشش را انجام دادیم. بهطور خاص، مفهوم حساسیت را برای تمایز معیارهای پوشش مختلف بهصورت رسمی تعریف و مورد بحث قرار دادیم.
بر اساس سطوح مختلف حساسیت، چندین معیار پوشش نمونه مانند پوشش شاخه پایه (Basic Branch Coverage)، پوشش شاخه حساس به متن (Context-Sensitive Branch Coverage)، پوشش شاخه n-gram و پوشش شاخه آگاه از دسترسی به حافظه (Memory-Access-Aware Branch Coverage) و گونههای مختلف آنها را معرفی کردیم. در نهایت، شش معیار پوشش را در ابزار فازینگ جعبهخاکستری پرکاربرد AFL [38] پیادهسازی کردیم و آنها را با مجموعهدادههای بزرگ، شامل LAVA-M [۴۲]، DARPA CGC [۴] و باینریهای دنیای واقعی ارزیابی کردیم.
یافتههای حائز اهمیت:
- معیارهای مختلف پوشش معمولاً به کشف مجموعههای متفاوتی از باگها (Bug) منجر میشوند. علاوه بر این، در مراحل مختلف فرایند کامل فازینگ، ممکن است بهترین عملکرد بین این معیارها متغیر باشد. در نتیجه، هیچ معیار پوشش جامعی وجود ندارد که بتواند بهطور مطلق بر سایرین برتری داشته باشد.
- با این حال، ترکیب این معیارهای مختلف میتواند به کشف تعداد بیشتری باگ و نیز تسریع در فرایند کشف آنها کمک کند. نکته قابل توجه این است که، با استفاده از منابع محاسباتی کمتر، ترکیب فازرهایی با معیارهای پوشش متفاوت قادر است در مجموعهداده CGC حداقل به همان تعداد باگ دست یابد که در فازر ترکیبی Driller نسخهی تقویت شده AFL با اجرای کانکولیک (concolic execution) گزارش کرده است [35].
به منظور تسهیل تحقیقات بیشتر در این حوزه، کد منبع و مجموعهداده در آدرس https://github.com/bitsecurerlab/afl-sensitive در دسترس قرار گرفته است.
۲. پیشینه (Background)
در این بخش، اطلاعات پیشینهای در مورد فازینگ جعبهخاکستری هدایتشده با پوشش، با تمرکز ویژه بر انتخاب بذر (Seed Selection)، ارائه میدهیم.
۲.۱ فازینگ جعبهخاکستری هدایتشده با پوشش (Coverage-Guided Greybox Fuzzing)
فازینگ جعبه خاکستری هدایت شده بر اساس پوشش (Coverage-Guided Greybox Fuzzing)، ورودیها (یا موارد آزمون (Test Case)) را به صورت تدریجی و از طریق یک حلقه بازخوردی (Feedback Loop) تولید میکند. به طور مشخص، همانطور که در شکل ۱ نشان داده شده است، این فرایند شامل سه مرحله اصلی است:
- زمانبندی بذر (Seed Scheduling): یک بذر از مجموعه بذرها بر اساس معیارهای زمانبندی انتخاب میشود.
- جهش بذر (Seed Mutation): در یک بازه زمانی محدود، با اعمال انواع مختلف جهش (Mutation) روی بذر انتخاب شده، موارد آزمون جدید تولید میشوند.
- انتخاب بذر (Seed Selection): هر مورد آزمون (Test Case) تولید شده به برنامه تحت آزمون داده میشود و بر اساس معیار پوشش ارزیابی میگردد. چنانچه مورد آزمون منجر به پوشش جدید (New Coverage) شود، به عنوان یک بذر (Seed) جدید در مجموعه بذرها اضافه خواهد شد.
با ادامه یافتن این حلقه بازخوردی، پوشش کد بهتدریج افزایش مییابد و در نهایت احتمال کشف موارد آزمونی که بتوانند باعث وقوع باگ شوند افزایش خواهد یافت.
۲.۲ انتخاب بذر (Seed Selection)
استراتژی انتخاب بذر، روند و سرعت تکامل فرآیند فازینگ را تعیین میکند. اساساً، یک بذر خوب باید دو مشکل اساسی را حل کند:
(۱) نحوه جمعآوری اطلاعات پوشش (Coverage Information Collection)
(۲) نحوه اندازهگیری کیفیت موارد آزمون (Test Case Measurement)
جمعآوری اطلاعات پوشش (Coverage Information Collection)، ابزار AFL برای جمعآوری و محاسبه پوشش کد (Coverage)، برنامه تحت آزمون را ابزارگذاری (Instrument) میکند. برای این ابزارگذاری دو رویکرد وجود دارد. (۱) هنگامی که کد منبع برنامه تحت آزمون در دسترس باشد، از نسخهای تغییریافته از کامپایلر Clang استفاده میشود تا منطق محاسبه پوشش در سطح زبان اسمبلی (Assembly Level) یا در سطح نمایش میانی (Intermediate Representation – IR) به فایل اجرایی کامپایلشده افزوده شود (بهترتیب در حالت عادی (Normal Mode) و حالت سریع (Fast Mode)). (۲) در صورتی که کد منبع در دسترس نباشد، از نسخهای تغییریافته از QEMU در حالت کاربر (User-mode) برای اجرای مستقیم کد باینری (Binary) برنامه تحت آزمون استفاده میشود و منطق محاسبه پوشش در مرحله ترجمه باینری (Binary Translation) به برنامه تزریق میشود. VUzzer [29] از PIN [41] برای انجام ابزارگذاری باینری (Binary Instrumentation) و جمعآوری اطلاعات مورد نیاز استفاده میکند. HonggFuzz [40] و kAFL [31] نیز از رهگیریهای سختافزاری انشعاب (Hardware Branch Tracers)، نظیر Intel Processor Trace (PT)، برای جمعآوری اطلاعات پوشش بهره میبرند. همچنین، DigTool [25] از یک هایپروایزر (Hypervisor) برای جمعآوری اطلاعات پوشش از هستههای سیستمعامل (OS Kernels) استفاده میکند.
اندازهگیری کیفیت موارد آزمون (Test Case Measurement). کیفیت موارد آزمون با استفاده از معیارهای پوشش اندازهگیری میشود. HonggFuzz [۴۰] و VUzzer [۲۹] از پوشش بلوک پایه (Basic Block Coverage) استفاده میکنند. AFL] ۳۸] از نسخه بهبودیافته پوشش شاخه (Branch Coverage) بهره میبرد که بازدیدهای بلوک را از بلوکهای قبلی متمایز میکند. LibFuzzer ]۴۳] میتواند از پوشش بلوک یا شاخه استفاده کند. [۷] Angora پوشش شاخه را با افزودن زمینه فراخوانی (Call Context) گسترش میدهد. جنبه مهم دیگر، نحوه اندازهگیری واقعی این معیارها است. فازرها معمولاً پیادهسازیهای ساده را برای بهبود توان عملیاتی (Throughput) ترجیح میدهند. برای مثال، AFL یک شاخه را با تابع هش ساده شناسایی میکند (معادله ۱). متأسفانه، این تقریب میتواند حساسیت مؤثر معیار پوشش را به دلیل برخوردهای هش (Hash Collisions) کاهش دهد [۱۲].
۳. معیارهای حساسیت و پوشش (Sensitivity and Coverage Metrics)
به طور خاص، ما مفهوم «حساسیت» (sensitivity) را به صورت رسمی تعریف و بررسی کردیم تا بتوانیم معیارهای پوشش مختلف را از یکدیگر متمایز کنیم. ما بر اساس سطوح مختلف حساسیت، چندین معیار پوشش نماینده را معرفی میکنیم.
۳.۱ تعریف رسمی حساسیت هنگام مقایسه معیارهای پوشش مختلف (Formal Definition of Sensitivity)
یک پرسش اصلی این است که «آیا معیار A بهتر از معیار B است؟» برای پاسخ به این پرسش، باید به نحوه کشف یک باگ توسط فازر جعبهخاکستری مبتنی بر جهش (mutation-based greybox fuzzer) توجه کنیم. در فازینگ جعبهخاکستری مبتنی بر جهش، از طریق زنجیرهای از موارد آزمون جهشیافته (Mutated Test Cases) به یک مورد ورودیِ ایجادکنندهی باگ (Bug-Triggering Input) دست پیدا میکنیم. در این فرآیند، اگر یک مورد آزمون میانی توسط معیار پوشش «غیرجذاب» (Uninteresting) تلقی شود، زنجیره شکسته میشود و ممکن است به ورودیِ ایجادکنندهی باگ (Bug-Triggering Input) نرسیم. بر اساس این مشاهده، حساسیت را بهعنوان توانایی یک معیار پوشش در حفظ چنین زنجیرههای جهشی تعریف میکنیم. برای توصیف رسمی این مفهوم، ابتدا یک معیار پوشش را به عنوان تابع زیر تعریف میکنیم:
C: (P × I) → M
که هنگام اجرای برنامه P ∈ P با ورودی I ∈ I، اندازهگیری M ∈ M را تولید میکند. با توجه به دو معیار پوشش Ci و Cj،Ci حساستر از Cj است (Ci ≻ Cj) اگر:
شرط اول به این معنی است که اگر دو ورودی با Ci پوشش یکسانی تولید کنند، باید با Cj نیز پوشش یکسانی تولید کنند (یعنی Cj همیشه متمایزتر از Ci نیست). شرط دوم به این معنی است که حداقل در یک برنامه، دو ورودی وجود دارند که با Cj پوشش یکسانی دارند اما با Ci پوشش متفاوتی تولید میکنند (یعنی Ci میتواند متمایزتر باشد).
۳.۲ معیارهای پوشش (Coverage Metrics)
در این زیربخش، چندین معیار پوشش و اندازهگیری تقریبی آنها را معرفی میکنیم و سپس حساسیت آنها را مقایسه میکنیم.
پوشش شاخهای (Branch Coverage). پوشش شاخهای پیشرفت ساده اما مؤثری نسبت به پوشش بلوک پایه (Basic Block Coverage) است. پوشش بلوک پایه فقط مشخص میکند کدام بلوک کد بازدید شده است، اما پوشش شاخهای با در نظر گرفتن بلوک قبلی (Prev Block)، بازدیدهای همان بلوک را از پیشینیان مختلف متمایز میکند. شاخه در اینجا به معنای لبهای از یک بلوک کد به بلوک دیگر است. در عمل، پوشش شاخه معمولاً با هش کردن جفت (cur_block, prev_block) در نقشه شمارش اجراها (Hit Count Map) اندازهگیری میشود. AFL یک شاخه را بهصورت زیر شناسایی میکند:
اگرچه پوشش شاخه به طور گسترده در فازرهای جریان اصلی استفاده میشود، حساسیت آن نسبتاً پایین است. برای مثال، در تابعی که مرتباً فراخوانی میشود مانند (strcmp)، پوشش شاخه قادر به تشخیص بازدیدها در زمینههای فراخوانی مختلف نیست.
پوشش شاخه N-Gram (N-Gram Branch Coverage). پس از آنکه در پوشش شاخهای، یک بلوک پایهی قبلی نیز در نظر گرفته شد، طبیعی است که تعداد بیشتری از بلوکهای پایهی قبلی را بهعنوان سابقه (History) در کنار بلوک پایهی فعلی لحاظ کنیم. ما این معیار پوشش را پوشش شاخهای N-Gram مینامیم؛ در اینجا n یک پارامتر قابل تنظیم است که مشخص میکند چند شاخهی متوالی بهعنوان یک واحد در نظر گرفته شوند و هرگونه تغییر در آنها بهصورت مجزا تشخیص داده شود. زمانی که n = 0 باشد، پوشش شاخهای N-Gram به پوشش بلوک (Block Coverage) تقلیل پیدا میکند. در نقطهی مقابل، هنگامی که n → ∞ باشد، پوشش شاخهای N-Gram معادل پوشش مسیر (Path Coverage) خواهد بود، زیرا تمام شاخههای قبلی را بهعنوان زمینه (Context) در نظر میگیرد و هر تغییری در مسیر اجرای برنامه را بهعنوان یک حالت متفاوت تشخیص میدهد. در حالت ایدهآل، پوشش شاخهای N-Gram باید بهصورت یک تاپل (block₁, …, blockₙ₊₁) اندازهگیری شود. با این حال، برای افزایش کارایی، پیشنهاد میکنیم این تاپل به صورت یک کلید در جدول hit_count هش شود (prev_block_trans << 1) ⊕ curr_block_trans که در آن:
به عبارت دیگر، ما n−1 انتقال (Transition) قبلی بین بلوکها را (که مطابق معادله ۱ محاسبه شدهاند) ثبت میکنیم، سپس همهی آنها را با عملگر XOR با یکدیگر ترکیب میکنیم، نتیجه را یک بیت به چپ شیفت (Left Shift) میدهیم و در نهایت آن را با انتقال بلوک جاری دوباره XOR میکنیم. در اینجا یک پرسش جالب مطرح میشود: بهترین مقدار برای n چیست؟ اگر n بیش از حد کوچک باشد، این معیار تفاوت چندانی با پوشش شاخهای (Branch Coverage) نخواهد داشت. از سوی دیگر، اگرn بیش از حد بزرگ انتخاب شود، ممکن است باعث انفجار بذرها (Seed Explosion) شود؛ پدیدهای مشابه انفجار مسیرها (Path Explosion). در این حالت، به دلیل افزایش بسیار زیاد تعداد بذرها (Seeds)، روند فازینگ (Fuzzing) نیز به مراتب کندتر خواهد شد. برای پاسخ تجربی به این پرسش، ماAFLFast را بهگونهای تغییر دادهایم که از پوشش شاخهای N-Gram پشتیبانی کند؛ بهطوریکه مقدارn بهترتیب برابر ۲، ۴ و ۸ در نظر گرفته شده است. نتایج ارزیابی این تنظیمات در بخش ۴ ارائه خواهد شد.
پوشش شاخهای حساس به زمینه (Context-Sensitive Branch Coverage). یک تابع (Function) از نظر سطح دانهبندی (Granularity) کد، بین یک بلوک پایه (Basic Block) و یک مسیر اجرا (Path) قرار میگیرد. بنابراین، زمینه یا بافت فراخوانی (Calling Context) نیز بخش مهمی از اطلاعاتی است که میتوان آن را در معیار پوشش وارد کرد. این کار به فازر (Fuzzer) امکان میدهد اجرای یک قطعه کد یکسان را که در زمینههای فراخوانی متفاوت و در نتیجه با دادههای متفاوت اجرا شده است، از یکدیگر متمایز کند. ما این معیار پوشش را «پوشش حساس به زمینه» (Context-Sensitive Coverage Metric) مینامیم. در حالت ایدهآل، معیار پوشش شاخهای حساس به زمینه باید بهصورت یک تاپل (call_stack, prev_block, curr_block) اندازهگیری شود که در آنcall_stack پشتهی فراخوانی توابع،prev_block بلوک قبلی و curr_block بلوک جاری را نشان میدهند. با این حال، برای افزایش کارایی، ما زمینهی فراخوانی (call_ctx) را بهصورت دنبالهای از مکانهای برنامه که فراخوانی توابع در آنها انجام شده است، به ترتیب وقوع تعریف میکنیم:
در این صورت، زوج کلید–مقدار (Key–Value Pair) که در نقشه بیت (Bitmap) ذخیره میشود، به صورت call_ctx ⊕ block_trans محاسبه خواهد شد. در ابتدا، مقدار زمینه فراخوانی (call_ctx) روی صفر تنظیم میشود. سپس در طول اجرای برنامه، هنگام مواجهه با یک دستورالعمل فراخوانی (call)، مقدار فعلی call_ctx را با آدرس دستورالعمل بلافاصله پس از فراخوانی، با عملگر XOR ترکیب کرده و نتیجه را در call_ctx ذخیره میکنیم. به طور مشابه، هنگام مواجهه با دستورالعمل بازگشت (ret)، مقدار فعلی call_ctx را با آدرس بازگشت XOR میکنیم. به این ترتیب، یک مقدار کوچک call_ctx به طور مؤثر، توالی فراخوانیهای تابع انجامشده را ثبت میکند و فراخوانیهایی را که به پایان رسیدهاند، حذف مینماید.
پوشش شاخه آگاه از دسترسی به حافظه (Memory-Access-Aware Branch Coverage). علاوه بر اطلاعات جریان کنترل (Control Flow) که در معیارهای قبلی مورد استفاده قرار گرفت، اطلاعات جریان داده (Data Flow) نیز شایسته توجه ویژه است. با توجه به این شهود که هدف اصلی فازینگ، کشف آسیبپذیریهای فساد حافظه (Memory Corruption) است، ثبت اطلاعات دسترسی به حافظه میتواند به طور قابلتوجهی در اندازهگیری کیفیت پوشش کمک کند. اساساً، فساد حافظه اغلب با رفتارهای نادرست دسترسی به حافظه همراه است. بنابراین، منطقی است که بذرهایی (Seed) را انتخاب کنیم که الگوهای دسترسی به حافظه متمایزی را نشان میدهند. بهطور کلی، معیار پوشش آگاه از دسترسی به حافظه حساستر از پوشش شاخه معمولی (Branch Coverage) است. زیرا اگر یک مورد آزمون جدید به شاخهای برسد که قبلاً توسط موارد آزمون قبلی پوشش داده شده باشد، اما حداقل به یک مکان حافظه جدید دسترسی پیدا کند، این مورد آزمون همچنان در این معیار «جالب» (Interesting) تلقی شده و بهعنوان بذر جدید نگه داشته میشود. روشهای متعددی برای ثبت الگوهای دسترسی به حافظه وجود دارد. در این مقاله، ما یکی از گزینههای طراحی را بررسی میکنیم. عملیات دسترسی به حافظه برنامه تحت آزمون را ابزارگذاری (Instrument) میکنیم و هر دسترسی را بهصورت یک چندتایی (type, addr, block_trans) تعریف میکنیم. در این چندتایی، type نوع دسترسی (خواندن یا نوشتن)، addr آدرس حافظه مورد دسترسی، و block_trans شاخهای است که این دسترسی پس از آن انجام شده است. به منظور بهبود کارایی، پیشنهاد میکنیم کلید هش از طریق محاسبه (block_trans ⊕ mem_ac_ptn) به دست آید.
توجه داشته باشید که عملیات خواندن (Read) از عملیات نوشتن (Write) با تخصیص کلیدهای آنها به دو نیمه مجزا از نگاشت (Map) از یکدیگر متمایز میشوند. از آنجا که خرابی حافظه (Memory Corruption) عمدتاً در اثر عملیات نوشتن در حافظه رخ میدهد، بررسی گونهای از پوشش دسترسی به حافظه با عنوان «پوشش شاخه آگاه از نوشتن در حافظه» (Memory-Write-Aware Branch Coverage) منطقی است. در این روش، تنها عملیاتهای نوشتن در حافظه ابزارگذاری (Instrument) و ثبت میشوند و عملیاتهای خواندن ثبت نمیشوند. در نتیجه، این معیار حساسیت کمتری نسبت به پوشش کامل دسترسی به حافظه دارد.
۳.۳: شبکه حساسیت (Sensitivity Lattice)
بدیهی است که این رابطه، یک ترتیب جزئی (Partial Order) است؛ زیرا نامتقارن است (اگر Ci ≻ Cj باشد، به هیچ وجه Cj ≻ Ci نیست)، متعدی است (اگر Ci ≻ Cj و Cj ≻ Ck باشد، آنگاه Ci ≻ Ck) و غیرانعکاسی است (Ci ≻ Ci امکانپذیر نیست). با این حال، یک ترتیب کامل (Total Order) نیست، زیرا ممکن است دو معیار پوشش وجود داشته باشند که قابل مقایسه مستقیم با یکدیگر نباشند.
با توجه به موارد فوق، میتوانیم شبکه حساسیت معیارهای پوشش مورد بحث را رسم کنیم. شکل ۲ این شبکه را نشان میدهد. پوشش بلوک پایه (Basic Block Coverage) در مقایسه با سایر معیارها، کمترین سطح حساسیت را دارد و بنابراین در بالاترین سطح شبکه قرار میگیرد. بلافاصله زیر آن، پوشش شاخه (Branch Coverage) قرار دارد که حساستر از پوشش بلوک پایه است.زیر پوشش شاخه، سه معیار پوشش قرار دارند که هر کدام اطلاعات اضافی متفاوتی را به پوشش شاخه اضافه میکنند. با این حال، بین این سه معیار مقایسه مستقیم وجود ندارد، زیرا هر کدام پوشش شاخه را در ابعاد متفاوتی گسترش میدهند:
- پوشش شاخه حساس به متن (Context-Sensitive Branch Coverage) شامل اطلاعات زمینه فراخوانی است،
- پوشش شاخه N-Gram انتقال بلوکهای قبلی n-1 را ادغام میکند،
- پوشش شاخه آگاه از دسترسی به حافظه (Memory-Access-Aware Branch Coverage) شامل اطلاعات دسترسی به حافظه است.
برای هر دو معیار، همیشه میتوانیم برنامه و دو ورودی بسازیم بهگونهای که برای یکی از معیارها پوشش یکسانی تولید شود، اما برای معیار دیگر پوشش متفاوتی ایجاد شود. در پوشش شاخه N-Gram ، اگر i > j باشد، آنگاه i-gram حساستر از j-gram است. در نهایت، پوشش مسیر (Path Coverage) حساستر از پوشش شاخه N-Gram و پوشش شاخه حساس به متن است. نکته جالب اینجاست که نمیتوانیم پوشش مسیر را با پوشش شاخه آگاه از دسترسی به حافظه یا پوشش شاخه آگاه از نوشتن در حافظه مقایسه کنیم. پوشش مسیر لزوماً حساستر نیست، زیرا ممکن است دو ورودی مسیر یکسانی را طی کنند اما الگوهای دسترسی به حافظه متفاوتی نشان دهند.
شایان ذکر است که معیارهای پوشش ارائه شده در این مقاله تنها نمونههایی هستند و به هیچ وجه کامل و جامع نیستند. امیدواریم این مطالعه بتواند تحقیقات بیشتری را در زمینه توسعه معیارهای پوشش جدید و درک عمیقتر تأثیر آنها بر عملکرد فازینگ برانگیزد.
۴. ارزیابی (Evaluation)
برای پاسخ به سؤالات تحقیقاتی مطرحشده در بخش ۱، تمام معیارهای پوشش معرفیشده در بخش ۳ (بهجز پوشش شاخه پایه که قبلاً در AFL پیادهسازی شده بود) را پیادهسازی کردیم. سپس آزمایشهای گستردهای را برای ارزیابی عملکرد این معیارهای پوشش مختلف انجام دادیم. علاوه بر این، برای درک بهتر اینکه چگونه ترکیب معیارهای پوشش مختلف بر عملکرد فازینگ تأثیر میگذارد، رویکرد بذرگذاری متقاطع (Cross-Seeding) را نیز بررسی و ارزیابی کردیم.
جدول ۱: کاربردهای دنیای واقعی مورد استفاده در ارزیابی:
۴.۱ پیادهسازی (Implementation)
در این مطالعه، با توجه به اینکه هدف اصلی ما فازینگ فایلهای باینری بدون دسترسی به کد منبع است، ابزارگذاری (Instrumentation) خود را بر پایه QEMU در حالت کاربر (User-Mode QEMU) پیادهسازی کردیم.برای مثال،
- در پوشش شاخه حساس به متن (Context-Sensitive Branch Coverage)، دستورالعملهای فراخوانی (call) و بازگشت (ret) را برای محاسبه زمینه فراخوانی (call_ctx) ابزارگذاری کردیم.
- در پوشش شاخه آگاه از دسترسی به حافظه (Memory-Access-Aware Branch Coverage)، عملیات خواندن و نوشتن حافظه را ابزار دقیق کردیم.
- برای پوشش شاخه N-Gram، از یک بافر حلقوی (Circular Buffer) برای ذخیره آخرین n انتقال بلوک استفاده کردیم تا محاسبه N-Gram بهصورت کارآمد انجام شود.
برای راحتی ارجاع در ادامه مقاله، از اختصارات زیر استفاده میکنیم:
- Bc: پوشش شاخه پایه (Branch Coverage) موجود درAFL
- Ct: پوشش شاخه حساس به متن (Context-Sensitive Branch Coverage)
- Mw: پوشش شاخه آگاه از نوشتن در حافظه (Memory-Write-Aware Branch Coverage)
- Ma: پوشش شاخه آگاه از دسترسی به حافظه (Memory-Access-Aware Branch Coverage)
برای پوشش شاخه N-Gram نیز سه نسخه پیادهسازی کردیم: 2-gram ، 4-gram و 8-gram که به ترتیب با اختصارات n2، n4 و n8 از آنها یاد میکنیم. علاوه بر این، از زمانبندی اولیه AFLFast [۳] در پیادهسازی خود بهره بردیم. از آنجا که AFLFast تمایل دارد زمان فازینگ بیشتری را به بذرهای (Seed) تازه تولید شده اختصاص دهد، تأثیر معیارهای پوشش مختلف بر عملکرد کلی فازینگ برجستهتر خواهد بود.
۴.۲ مجموعهدادهها (Datasets)
ما فایلهای باینری را از چالش بزرگ سایبری DARPA (DARPA Cyber Grand Challenge – CGC) [۴] جمعآوری کردیم. این مجموعه شامل ۱۳۱ فایل باینری از رویداد واجد شرایط CGC (CQE) و ۷۴ فایل باینری از رویداد نهایی CGC (CFE) است که در مجموع ۲۰۵ فایل باینری را تشکیل میدهد.این فایلهای باینری توسط متخصصان امنیتی با دقت بالا ساخته شدهاند تا از تکنیکهای متنوعی (مانند پروتکلهای پیچیده ورودی/خروجی و جمعآزماهای ورودی) استفاده کنند و آسیبپذیریها را به روشهای مختلف (مانند سرریز بافر، سرریز عدد صحیح و استفاده پس از آزادسازی) جاسازی نمایند. هدف از طراحی چنین باینریهایی، ارزیابی جامع تکنیکهای مختلف کشف آسیبپذیری است.
علاوه بر این، مجموعهداده LAVA-M [۱۱و ۴۲] را نیز انتخاب کردیم. این مجموعه شامل چهار برنامه از مجموعه GNU coreutils یعنی base64، md5sum، uniq و who است. هر یک از این برنامهها با تعداد زیادی آسیبپذیری مصنوعی تزریقشده همراه هستند. ما این آسیبپذیریهای تزریقشده را بهعنوان دادههای پایه (Ground Truth) در نظر گرفته و از آنها برای ارزیابی عملکرد معیارهای پوشش مختلف استفاده میکنیم. علاوه بر دو مجموعهداده فوق، موفق به جمعآوری ۱۲ برنامه کاربردی دنیای واقعی با آخرین نسخههایشان شدیم (جدول ۱). عملکرد معیارهای پوشش مختلف را در شرایط واقعی با استفاده از این برنامهها نیز ارزیابی کردیم.
۴.۳ تنظیمات آزمایش (Experimental Setup)
آزمایشهای ما روی یک کلاستر خصوصی (private cluster) متشکل از چندین ماشینهای مجازی (virtual machines) انجام شده است. هر ماشین مجازی دارای سیستمعامل Ubuntu 14.04.1 بوده و به یک پردازنده Intel Xeon با فرکانس 2.3 گیگاهرتز (24 هسته) و 30 گیگابایت حافظه RAM مجهز است. از آنجا که فازینگ یک فرایند تصادفی است، مطابق توصیههای موجود در [20]، هر ارزیابی چندین بار و برای مدتزمان کافی اجرا شده است. آزمایشها عمدتاً بر روی مجموعهداده CGC متمرکز بودهاند. بهطور مشخص، هر معیار پوشش برای هر باینری از این مجموعهداده، با استفاده از دو نمونه فاز و به مدت ۶ ساعت اجرا شده است (که معادل یک اجرای ۱۲ ساعته برای یک نمونه در نظر گرفته میشود).
این مدت زمان به این دلیل انتخاب شده است که تقریباً تمام باگهای کشف شده توسط فازر در CQE و CFE در ۶ ساعت ابتدایی گزارش شدهاند. علاوه بر این، برای در نظر گرفتن اثر تصادفی بودن فازینگ، هر آزمایش ۱۰ بار تکرار شده است. مجموع زمان اجرای ارزیابیها حدود ۶۰ روز بوده است. برای باینریهایی که دارای ورودی اولیه (initial inputs) هستند، از همان ورودیها به عنوان بذر اولیه (initial seeds) استفاده شده است؛ در غیر این صورت، از بذر خالی (empty seed) استفاده شده است. در مورد مجموعهداده LAVA-M، هر معیار پوشش به صورت جداگانه برای مدت ۲۴ ساعت و در سه تکرار آزمایش شده است. در این حالت از ورودیهای اولیه ارائه شده در معیار و همچنین دیکشنریهایی (dictionaries) از ثابتهای (constants) استخراج شده از باینری مطابق پیشنهاد [44] استفاده شده است. برای مجموعهداده دنیای واقعی، هر معیار پوشش به مدت ۴۸ ساعت، با دو نمونه فازر و در شش تکرار ارزیابی شده است. در این بخش، در صورت امکان از ورودیهای نمونه ارائه شده توسط AFL به عنوان بذر استفاده شده و در غیر این صورت از بذر خالی استفاده شده است.
۴.۴ معیارهای ارزیابی (Evaluation Metrics)
برای پاسخ به این پرسش که آیا معیار پوشش بهینهای وجود دارد، سه معیار کمی برای ارزیابی عملکرد معیارهای پوشش پیشنهاد میکنیم:
- کرشها/باگهای منحصربهفرد (Unique Crashes/Bugs) : کرش منحصربهفرد به این معناست که یک باگ بالقوه در فایل باینری کشف شده است. در مجموعهداده CGC، هر باینری طوری طراحی شده که تنها یک آسیبپذیری داشته باشد و کرش تکراری تولید نکند. در LAVA-M، به هر باگ یک شناسه منحصربهفرد اختصاص داده شده است. در برنامههای دنیای واقعی نیز از هش هر کرش برای تشخیص تکراری بودن استفاده میکنیم.
- زمان کرش(Time-to-Crash): این معیار نشان میدهد که یک فایل باینری خاص با چه سرعتی توسط فازر کرش میشود. از آنجا که هر باینری CGC معمولاً فقط یک آسیبپذیری دارد، این معیار برای سنجش کارایی فازینگ با معیارهای پوشش مختلف بسیار مناسب است.
- تعداد بذرها (Number of Seeds): هرچه معیار پوشش حساستر باشد، احتمال تبدیل یک مورد آزمون به بذر جدید بیشتر است و در نتیجه تعداد بذرهای منحصربهفرد افزایش مییابد. بنابراین، این معیار حساسیت عملی هر معیار پوشش را بهصورت کمی نشان میدهد.
۴.۵ مقایسه باگهای منحصربهفرد (Unique Bug Comparison)
بهطور کلی، معیار پایه bc بهطور متوسط حدود ۸۹ باینری و در بهترین حالت ۹۱ باینری را از کار انداخت. بهجز ma و mw، سایر معیارهای حساستر (ct، n2، n4 و n8) عملکرد بهتری نسبت به bc نشان دادند. این نتیجه رضایتبخش است و تأیید میکند که حساسیت نقش مهمی در کشف کرشها (باگها) دارد. با این حال، همانطور که ma و mw نشان میدهند، حساسیت بیش از حد نیز میتواند تأثیر منفی بر عملکرد فازینگ داشته باشد. دلیل اصلی این است که معیارهای حساستر، موارد آزمایشی بیشتری را بهعنوان جالب ارزیابی میکنند (بخش ۴.۷). هنگامی که بودجه زمانی محدود است، هر بذر (Seed) زمان کمتری برای جهش دریافت میکند یا فرصت کافی برای اجرای تمام برنامهریزیها ندارد.
در ادامه، توانایی هر معیار پوشش را در کشف باگ/کرشهای منحصربهفرد بررسی کردیم — یعنی آیا باگی وجود دارد که فقط توسط یک معیار یا زیرمجموعهای از معیارها کشف شود و توسط بقیه کشف نشود؟ برای پاسخ به این پرسش، مقایسه زوجی روی باینریهای کرششده انجام دادیم (جدول ۲). برای هر جفت معیار پوشش i (در سطر) و j (در ستون)، ابتدا تعداد باینریهایی را شمارش کردیم که فقط توسط i کرش شدهاند اما توسط j نه (با علامت “/” مشخص شده است).
جدول ۲: مقایسههای دوتایی (ردیف در برابر ستون) از نظر تعداد باینریهای منحصربهفرد مجموعه CGC که دچار کرش شدهاند:
جدول ۳: تعداد باگهای منحصربهفرد کشفشده توسط معیارهای مختلف پوشش در مجموعهداده LAVA-M:
از آنجا که تفاوتهای مشاهدهشده ممکن است ناشی از تصادفی بودن فازینگ باشد، آزمایش دوم را با تمرکز بیشتر بر روی تأثیر حساسیت به انجام رساندیم. بهطور مشخص، در طول فرآیند فازینگ، زنجیرهی بذرهایی (Seed) را که در نهایت به تولید هر نمونه آزمایشی منجر به کرش (Crashing Test Case) شده بودند، ثبت کردیم. هر زنجیره از بذر اولیه آغاز شده و به نمونه آزمایشی کرشکننده ختم میشود.
سپس، برای هر جفت از معیارهای پوشش (i، j) بررسی کردیم که آیا هر بذر موجود در زنجیرهای که توسط معیار i انتخاب شده است، بدون انجام هیچگونه جهش (Mutation) اضافی ــ یعنی بدون ادامهی فرآیند فازینگ ــ توسط معیار j نیز بهعنوان بذر انتخاب میشد یا خیر. در این ارزیابی، اثرات ناشی از حساسیت اضافی (مانند استفاده از hit_count غیردودویی) و همچنین عدم حساسیت ناشی از تصادم یا برخورد هش (Hash Collision) که در پیادهسازی وجود داشتند نیز حذف شدند. نتیجهی این بررسی بهصورت عددی که قبل از علامت «/» در هر خانه از جدول ۲ آمده است، گزارش شده است.
برای مثال:
- ورودی (ct, bc) نشان میدهد که ۱۳ فایل باینری توسط ct کرش شدهاند اما توسط bc نه؛ از این تعداد، ۹ مورد حداقل یک بذر در زنجیره کرش دارند که توسط bc حذف میشوند.
- ورودی (bc, ct) نشان میدهد که ۶ فایل باینری توسط bc کرش شدهاند اما توسط ct نه، و هیچکدام از بذرهای کلیدی در زنجیره توسط ct حذف نشدهاند.
علاوه بر این:
- ورودی (all, k) تعداد فایلهای باینری را نشان میدهد که توسط حداقل یکی از معیارهای دیگر کرش شدهاند اما توسط k کرش نشدهاند.
- ورودی (k, others) تعداد فایلهایی را نشان میدهد که فقط توسط k کرش شدهاند و توسط هیچ معیار دیگری کرش نشدهاند.
- ورودی (all, others) تعداد کل فایلهای باینری را نشان میدهد که توسط حداقل یکی از هفت معیار پوشش کرش شدهاند.
نتایج نشان میدهد که تفاوت بین معیارهای پوشش قابلتوجه است. مهمتر آنکه، هیچ معیار پوششی وجود ندارد که همه را شکست دهد. حتی معیاری که کمترین تعداد کل باینریهای کرششده را دارد، باینریهای منحصربهفردی (بهترتیب ۲، ۲، ۴، ۴ و ۲ باینری فراتر از bc، و ۳، ۲، ۴ و ۲ باینری فراتر از ct، mw، n2، n4 و n8) کشف کرده است که حداقل یکی از بذرهای کلیدی در زنجیره کرش آنها توسط معیارهای دیگر حذف میشود.به عبارت دیگر، هر معیار پوشش میتواند سهم منحصربهفرد خود را در کشف باگ داشته باشد. این مشاهده ما را بیش از پیش به مطالعه ترکیب معیارهای پوشش مختلف ترغیب میکند. در بخش ۴.۸ بهطور مفصل به این موضوع میپردازیم.
جدول ۳ مجموعه داده LAVA-M، باگهای یا باگهای موجود در مجموعه داده LAVA-M را بر اساس معیارهای پوشش مختلف خلاصه میکند، در حالی که ستون آخر، تعداد باگهای فهرست شده توسط نویسندگان LAVA را نشان میدهد.در مقایسه با مجموعه داده CGC، مجموعه داده LAVA-M برای هدف ما چندان مناسب نیست. به طور خاص، اکثر باگهای تزریق شده توسط عدد جادویی (Magic number) محافظت میشوند که حل آن با جهش تصادفی بسیار دشوار است و نمیتواند قابلیتهای منحصر به فرد معیارهای پوشش مختلف را منعکس کند. اگرچه ما پیشنهادات [۴۴] را دنبال کردهایم و از فرهنگ لغتهای ثابت استفاده کردهایم.
جدول ۴: تعدادی از کرشهای منحصر به فرد یافتشده توسط معیارهای مختلف پوشش در مجموعه داده واقعی:
با وجود استخراج اعداد جادویی (magic numbers) از فایلهای باینری، همچنان نمیتوانیم تفاوتهای ناشی از عدم توانایی در حل این اعداد را کاملاً رد کنیم. برای برنامههای binarybase64، md5sum و uniq، تفاوت عملکرد بین معیارهای پوشش مختلف ناچیز است به جز (mainmd5sum و mwinuniq) با این حال، در برنامه binarywho مشاهده میشود که علاوه بر عملکرد ضعیف در مجموعه داده CGC، این برنامه باگهای منحصر به فرد بسیار بیشتری نسبت به سه معیار دیگر شناسایی میکند. در مجموعه دادههای دنیای واقعی نیز کرشهای متعددی برای فایلهای باینری شناسایی شد. برای جمعآوری و شناسایی کرشهای منحصر به فرد، از ابزار متنباز afl-collect [۴۹] استفاده کردیم. در مجموع، موفق به یافتن باگهای منحصر به فرد در ۵ فایل باینری دنیای واقعی شدیم که جزئیات آنها در جدول ۴ آمده است. شایان ذکر است که برای فایلهای باینری jdump، size و nm، تنها معیارهای پوشش پیشنهادی جدید ما قادر به کشف باگهای منحصر به فرد بودند.
۴.۶ مقایسه زمان تا اولین کرش (Time-to-Crash)
با توجه به اینکه اکثر باینریهای مجموعه داده CGC تنها حاوی یک باگهای هستند، زمان تا اولین کرش (TFC) را برای معیارهای پوشش مختلف طی ده دور آزمایش مستقل اندازهگیری کردیم. نمودار انباشته با سطح اطمینان ۹۵٪ از تعداد کرشهای باینری در طول زمان در شکل ۴ نمایش داده شده است. محور افقی زمان (به ثانیه) و محور عمودی تعداد انباشته کرشهای باینری را نشان میدهد.
همانطور که مشاهده میشود، معیار n4 در ساعت اول (۳۶۰۰ ثانیه) کرشهای بیشتری نسبت به سایر معیارها پیدا میکند، در حالی که maper ضعیفترین عملکرد را دارد. همچنین، تقریباً همه معیارهای پوشش پیشنهادی (به جز ma و mw) در مقایسه با AFL اصلی (bc) قادر به یافتن کرشها با سرعت بیشتری هستند. هرچند n4 بیشترین تعداد کرش کلی را پیدا نمیکند، اما در مجموع بهترین عملکرد را در مرحله اولیه (۳۰ تا ۹۰ دقیقه) دارد. پس از ۹۰ دقیقه، معیار ct از آن پیشی گرفته و به یکی از بهترین معیارها تبدیل میشود. برای جزئیات زمان صرفشده توسط هر معیار برای کرش در فایلهای باینری تکی، به شکل ۱۱ در پیوست مراجعه کنید.
شکل ۵ نیز تعداد باگهای منحصر به فرد یافت شده در طول زمان توسط معیارهای مختلف پوشش را در چهار فایل باینری مجموعه داده LAVA-M نشان میدهد. نتایج حاکی از آن است که معیارهای پوشش پیشنهادی جدید در همه چهار فایل عملکرد بهتری نسبت به معیارهای پایه دارند. هرچند در برخی موارد ممکن است در ابتدا کندتر عمل کنند، اما در نهایت همان تعداد باگهای منحصر به فرد (یا حتی بیشتر) را در فایلهای base64 و uniq کشف میکنند. علاوه بر این، معیارهای ct و n8 بهطور پایدار و قابل اعتماد در هر چهار فایل عملکرد بسیار خوبی دارند و n8 بهطور کلی عملکرد بهتری نشان میدهد.
معیار n4 عملکرد بسیار خوبی دارد و در باینریای که بیشترین تعداد باگ منحصر به فرد را پیدا میکند، بهطور قابلتوجهی سریعتر از سایر معیارها عمل مینماید.
مجموعه داده دنیای واقعی. بهطور مشابه، شکل ۶ تعداد باگهای منحصر به فرد کشفشده در طول زمان توسط معیارهای پوشش مختلف را در پنج فایل باینری دنیای واقعی نشان میدهد. مشاهده میشود که معیار info2cap به استثنای موارد خاص، یا باگهای منحصر به فرد را بسیار کندتر از سایر معیارها پیدا میکند یا اصلاً هیچ باگی کشف نمیکند. علاوه بر این، هیچ روند کلی و جهانی در مورد اینکه کدام معیار پوشش سریعترین معیار برای یافتن باگها در بین این پنج باینری است، وجود ندارد.
۴.۷ مقایسه تعداد بذرها (Seed Count)
در مجموعه داده CGC، تعداد بذرهای (Seed) انتخابشده برای هر باینری را با استفاده از معیارهای پوشش مختلف جمعآوری کردیم و میانگین آن را با سطح اطمینان ۹۵٪ طی ده اجرای مستقل گزارش میدهیم. شکل ۷ توزیع تجمعی تعداد بذرهای تولیدشده را نشان میدهد. هرچه منحنی به سمت بالا و چپ نزدیکتر باشد، نشاندهنده تولید تعداد کمتری بذر برای باینریهای تحت آزمایش با آن معیار پوشش است. از نتایج چندین مشاهده مهم به دست آمد:
- معیار m بهطور قابلتوجهی حساستر از سایر معیارها بود و تعداد بذرهای بسیار بیشتری (چندین مرتبه) نسبت به بقیه انتخاب میکرد. هرچند بسیاری از این بذرها پایه جهشهای معنادار و منجر به کرش نهایی میشوند، اما حجم بالای آنها عملکرد فازر را مختل میکند؛ زیرا تفاوت بین اکثر بذرها آنقدر زیاد است که احتمال ایجاد باگ جدید از آنها بسیار کم است.
- در پوشش شاخه n-gram، با افزایش n از ۱(bc) به ۸، تعداد بذرهای انتخاب شده نیز بهطور متناسب افزایش مییابد. با این حال، خطوط مربوط به bc و n2 بسیار به یکدیگر نزدیک هستند.
- این پدیده کاملاً با انتظار ما همخوانی دارد، بهویژه ترتیب n8 > n4 > n2 > bc.
- در حالی که از نظر تئوری نمیتوان معیارهای N-Gram را مستقیماً از لحاظ حساسیت با یکدیگر مقایسه کرد، مشاهده میشود که توزیع تعداد بذر برای معیارهای دیگر بین n4 و n8 قرار میگیرد (حداقل در مجموعه داده CGC) .
جدول ۵: تعداد بذرهای (Seed) تولید شده توسط معیارهای مختلف پوشش در مجموعهداده LAVA-M:
همانطور که مشاهده میشود، مشاهدات بهدستآمده از مجموعه داده CGC عمدتاً در این مجموعه داده نیز برقرار هستند، هرچند برخی دادههای پرت (outliers) وجود دارد. برای مثال، در تعدادی از فایلهای باینری، تعداد بذرهای اولیه کمتر از معیار پایه (bc) است. با این حال، با توجه به مقیاس کوچک این مجموعه داده، این تفاوتها از نظر آماری معنادار نیستند.
جدول ۶: تعداد بذرهای (Seed) تولید شده توسط معیارهای مختلف پوشش در مجموعهداده دنیای واقعی (Real-World Dataset):
مشاهدات بهدستآمده از مجموعه دادههای CGC و LAVA-M عمدتاً در این مجموعه نیز برقرار هستند، هرچند با برخی استثنائات. بهطور خاص، دیگر توزیع تعداد بذرهای بین n4 و n8 به صورت کلی مشاهده نمیشود.
۴.۸ ترکیب معیارهای پوشش (Combination of Coverage Criteria)
بر اساس نتایج ارزیابی فوق، مشاهده میکنیم که هر معیار پوشش (Coverage Metric) از نظر تعداد کرشهای (Crash) کشف شده و زمان لازم برای کشف کرشها ویژگیهای منحصربهفرد خود را دارد. این مشاهده ما را به این پرسش سوق میدهد که آیا ترکیب فازرهایی که از معیارهای پوشش متفاوت استفاده میکنند میتواند منجر به کشف تعداد بیشتری کرش و همچنین کشف سریعتر آنها شود. برای پاسخ به این پرسش، دو روش ترکیب را بررسی میکنیم:
- فازرهایی که از معیارهای پوشش متفاوت استفاده میکنند، بهصورت موازی (Parallel) اجرا شده و در بازههای زمانی مشخص، بذرها (Seeds) را میان تمامی معیارها همگامسازی (Synchronize) میکنند؛ روشی که از آن با عنوان بذرگذاری متقاطع (Cross-Seeding) یاد میشود.
- فازرهایی که از معیارهای پوشش متفاوت استفاده میکنند، بهصورت موازی اما کاملاً مستقل از یکدیگر اجرا میشوند. این حالت بهعنوان مبنای مقایسه (Baseline) در نظر گرفته میشود تا مشخص شود که آیا بذرگذاری متقاطع (Cross-Seeding) واقعاً موجب بهبود عملکرد میشود یا خیر.
برای بررسی گزینههای ترکیبی، سه پیکربندی مختلف از ۱۴ نمونه فازر ایجاد کردیم:
- همه ۱۴ نمونه فازر با معیار پایه (bc) و همگامسازی بذر (Seed).
- دو نمونه فازر برای هر یک از ۷ معیار پوشش مختلف، با همگامسازی بذر فقط درون همان معیار.
- سه نمونه فازر برای هر یک از ۷ معیار پوشش مختلف، با همگامسازی بذر در تمام معیارها یعنی بذرگذاری متقاطع (Cross-Seeding).
در مجموعه داده CGC، هر سه پیکربندی را به مدت شش ساعت و به صورت سه بار اجرا کردیم تا نتیجه میانه بهدست آید. شکل ۸ تعداد فایلهای باینری ازکارافتاده در طول زمان را برای سه پیکربندی نشان میدهد. مشاهدات کلیدی به شرح زیر است:
اول، هر دو رویکرد ترکیبی با و بدون بذرگذاری متقاطع (Cross-Seeding) با حاشیهای قابلتوجه نسبت به خط پایه، عملکرد بهتری از نظر تعداد فایلهای باینری خرابشده و زمان رسیدن به کرش دارند. پیکربندی بدون بذرگذاری متقاطع (Cross-Seeding) توانست ۷۸ فایل باینری CQE، ۳۱ فایل باینری CFE و در مجموع ۱۰۹ فایل باینری را از کار بیندازد. پیکربندی با بذرگذاری متقاطع (Cross-Seeding) نیز ۷۷ فایل باینری CQE، ۳۳ فایل باینری CFE و در مجموع ۱۱۰ فایل باینری را خراب کرد. در حالی که خط پایه تنها توانست ۶۴ فایلCQE ، ۳۰ فایل CFE و در مجموع ۹۴ فایل باینری را از کار بیندازد. این نتیجه بسیار قابلتوجه است؛ زیرا هیبرید فازر Driller [۳۵] با اجرای کانکولیک (concolic execution) توانست پس از ۲۴ ساعت فقط ۷۷ فایل باینری CQE را از کار بیندازد (در حالی که برای هر فایل باینری چهار نمونه فازینگ اختصاص داده شده بود و کل مجموعه از ۶۴ هسته CPU استفاده میکرد). در مجموع، Driller حدود ۱۲۶۴۰ ساعت CPU زمان محاسباتی مصرف کرده است. در مقایسه، ما با فازینگ خالص و منابع محاسباتی کمتر (۱۳۱ باینری × ۱۴ هسته × ۶ ساعت = ۱۱۰۰۴ ساعت CPU) به نتایجی مشابه یا حتی بهتر دست یافتیم.
دوم، خط آبی (پیکربندی ج) و خط قرمز (پیکربندی ب) حدوداً پس از ۳ ساعت با هم تلاقی میکنند. در این نقطه، هر دو پیکربندی ۱۰۵ باینری را از کار انداخته بودند. این نشان میدهد که ترکیب با بذرگذاری متقاطع (Cross-Seeding) میتواند ۱۰۵ باینری را بهطور قابلتوجهی سریعتر از ترکیب بدون بذرگذاری متقاطع (Cross-Seeding) از کار بیندازد.
ما همین سه پیکربندی را روی مجموعه داده LAVA-M به مدت ۲۴ ساعت و روی مجموعه داده دنیای واقعی به مدت ۴۸ ساعت نیز اجرا کردیم. نتایج در شکل ۹ و شکل ۱۰ نمایش داده شده است. مشاهده شد که ترکیب بدون بذرگذاری متقاطع (Cross-Seeding) همیشه با حاشیه قابلتوجهی نسبت به خط پایه ۱۴ فازر با معیار (bc) عملکرد بهتری دارد. با این حال، ترکیب با بذرگذاری متقاطع (Cross-Seeding) عملکرد متناقضی در دو مجموعه داده نشان داد؛ در برخی موارد حتی از خط پایه نیز ضعیفتر عمل کرد. این تفاوتها از نظر آماری معنادار نیستند، اما نشان میدهند که گاهی اوقات سربار ناشی از بذرگذاری متقاطع (Cross-Seeding) میتواند مزایای آن را خنثی کند. تحقیقات Xu et al [۵۲] نیز نشان داده است که سربار بذرگذاری متقاطع (Cross-Seeding) در فازینگ موازی قابلتوجه است و پیشنهادهایی در سطح سیستمعامل برای بهبود عملکرد ارائه کردهاند. ارزیابی دقیقتر عملکرد این ترکیبها موضوع جالبی برای تحقیقات آینده خواهد بود.
جالب خواهد بود که عملکرد ترکیب معیارهای پوشش همراه با بذرگذاری متقابل (Cross-Seeding) با در نظر گرفتن این تغییرات در سطح سیستمعامل (OS-level Modifications) دوباره ارزیابی شود. انجام این بررسی را به کارهای آینده واگذار میکنیم. در مجموع، ترکیب معیارهای مختلف پوشش، چه با بذرگذاری متقابل و چه بدون آن، رویکرد بهتری است؛ زیرا میتواند به کشف تعداد بیشتری از باگها کمک کند و همچنین آنها را در زمان کوتاهتری شناسایی کند.
۵. بحث و کارهای آینده Discussion and Future Work))
در این بخش، چندین حوزه کلیدی را که پتانسیل بهبود و بررسی در تحقیقات آینده دارند، مورد بحث قرار میدهیم.
محاسبه دقت و پوشش (Precision and Coverage Calculation). برای معیارهای پوشش ارائهشده، به دلیل ملاحظات کارایی، از فرمولهای ساده برای محاسبه جفتهای کلید-مقدار در نقشه hit_count استفاده کردیم که این امر با هزینه کاهش دقت همراه است. برای مثال، معادله ۳ از یک عمل XOR ساده برای محاسبه زمینه فراخوانی (Calling Context) استفاده میکند و بنابراین نمیتواند تابعی را که دو بار فراخوانی شده است از تابعی که تازه برگشته، متمایز کند. بهطور مشابه، معادله ۲ با XOR کردن بلوکهای n-1 قبلی، ترتیب دقیق بین انتقالها را حذف کرده و دقت پوشش شاخه N-Gram را کاهش میدهد. مشکل مرتبط دیگر، تصادم یا برخوردهای هش (Hash Collisions) [۱۲] است. فرمولهای ساده ممکن است منجر به تولید کلید یکسان برای دو مجموعه متفاوت از مقادیر ورودی شوند. بنابراین، طراحی فرمولهای دقیقتر که هم دقت را افزایش دهند و هم برخوردهای هش را کاهش دهند، موضوع مهمی برای تحقیقات آتی است. هرچند [۱۲] الگوریتمی حریصانه برای کاهش برخورد پیشنهاد کرده، این روش فقط برای پوشش شاخه ساده قابل اعمال است و تعمیم آن به سایر معیارها دشوار است.
انتخاب معیار پوشش آگاه از برنامه و تخصیص منابع (Program-Aware Coverage Selection and Resource Allocation). همانطور که در شکل ۲ مشاهده میشود، معیارهای پوشش ارائهشده از نظر حساسیت به ترتیب یکسانی قرار ندارند. این یعنی هر معیار قدرت منحصربهفردی در شکستن الگوهای خاص حلقهها و ساختارهای کد دارد. نتایج ارزیابی بخش ۴ نیز تأیید میکند که (۱) هیچ معیار «برتری» وجود ندارد که در همه پارامترها بهترین باشد، و (۲) معیارهای حساستر مانند bc، n2، n4،n8 همیشه عملکرد بهتری ندارند. در این مقاله، ترکیب سادهای از معیارها را بررسی کردیم و منابع محاسباتی را بهطور مساوی تقسیم کردیم. از آنجا که فازینگ را میتوان بهعنوان مسئله باندیت چند اهرمی (Multi-Armed Bandit – MAB) [۵۱] مدلسازی کرد، میتوان با تکنیکهایی مانند نسبت جهش تطبیقی (Adaptive Mutation Ratio) [۶] و تحلیل ایستا یا پویا روی برنامه، معیار مناسب را انتخاب کرده و تخصیص منابع را بهصورت پویا مدیریت کرد.
۶. کارهای مرتبط (Related Work)
در بخش 2، برخی از پژوهشهای مرتبط با فازینگ جعبهخاکستری (Greybox Fuzzing) را بررسی کردیم. در این بخش، بهاختصار به تعدادی دیگر از پژوهشهای مرتبط با فازینگ میپردازیم. فازینگ نخستین بار بهمنظور آزمون قابلیت اطمینان (Reliability) ابزارهای UNIX و با رویکرد جعبهسیاه (Blackbox) معرفی شد [22]. از آن زمان تاکنون، فازینگ جعبهسیاه (Blackbox Fuzzing) بهطور گسترده مورد استفاده و توسعه قرار گرفته است که نتیجه آن، ظهور ابزارهای بالغ و شناختهشدهای همچون Peach [46] وZzuf [50] بوده است.
پژوهشهای متعددی نیز با هدف بهبود این روش انجام شدهاند. برای مثال،Woo و همکاران[51] با استفاده از یک مدل ریاضی، بیش از ۲۰ الگوریتم زمانبندی بذرها (Seed Scheduling) را ارزیابی کردهاند تا الگوریتمی را بیابند که در یک بودجه زمانی (Time Budget) مشخص، بیشترین تعداد باگ را کشف کند. SYMFUZZ [6] با شناسایی وابستگی میان موقعیتهای بیت (Bit Positions)، نرخ جهش (Mutation Ratio) را برای یک جفت برنامه–بذر (Program–Seed Pair) بهینهسازی میکند تا تعداد باگهای کشفشده بیشینه شود.
Rebert و همکاران [30] الگوریتمی بهینه برای انتخاب زیرمجموعهای از فایلهای ورودی از میان یک مجموعه فایل، به عنوان فایلهای بذر اولیه (Initial Seed Files) پیشنهاد کردهاند؛ بهگونهای که تعداد باگهای کشفشده در طول یک کمپین فازینگ (Fuzzing Campaign) بیشینه شود. MoonShine [23] نیز چارچوبی ارائه میکند که با جمعآوری و تقطیر (Distilling) ردیابیهای فراخوانی سیستم (System Call Traces)، به صورت خودکار برنامههای بذر (Seed Programs) را برای فازینگ هستههای سیستمعامل (OS Kernels) تولید میکند.
فازینگ جعبهسفید (Whitebox Fuzzing) با هدف هدایت فرایند فازینگ از طریق استدلال درباره ویژگیهای مختلف برنامهها انجام میشود. Mayhem [5] از چندین تکنیک تحلیل برنامه، از جمله اجرای کانکولیک (Concolic Execution)، بهره میگیرد تا رفتار اجرای برنامه را برای یک ورودی پیشبینی کرده و باگهای قابل بهرهبرداری (exploitable bugs) را کشف کند.
TaintScope [37] با استفاده از تحلیل پویای آلودگی (Dynamic Taint Analysis)، فیلدهای مربوط به جمعآزما (Checksum) را در ورودی شناسایی کرده و بخشهای کد مسئول پردازش آنها را مشخص میکند تا فازینگ بتواند بررسیهای جمعآزما را دور بزند. BuzzFuzz [13] از تحلیل آلودگی برای استنتاج فیلدهای ورودی مؤثر بر نقاط حساس کد استفاده میکند؛ این نقاط معمولاً پارامترهای فراخوانیهای سیستمی و کتابخانهای هستند. سپس فرایند فازینگ را بر روی همین فیلدها متمرکز میکند. MutaGen [18] با اعمال جهش (Mutation) روی کد ماشینِ یک مولد ورودی و استفاده از برش پویا (Dynamic Slicing) برای تعیین دستورالعملهای مناسب جهت جهش، به تولید ورودیهای آزمون با پوشش بالا میپردازد.
Redqueen [1] رویکرد دیگری برای عبور از آزمونهای بایتهای جادویی (Magic Bytes) و جمعآزما (Checksum) ارائه میدهد. این ابزار با استفاده از ردیابی سبک شاخهها (Lightweight Branch Tracing)، ارتباط میان ورودی و وضعیت برنامه (Input-to-State Correspondence) را استنتاج میکند.
ProFuzz [53] تلاش میکند با استفاده از اطلاعات پوشش، نوع معنایی (Semantic Type) بایتهای ورودی را استنتاج کند و سپس متناسب با نوع هر بایت، راهبرد جهش مناسب را به کار گیرد. NEUZZ [32] تحلیل آلودگی را با استفاده از یک شبکه عصبی تقریب میزند. این روش با یادگیری نگاشت میان ورودی و پوشش شاخهها (Input-to-Branch-Coverage Mapping)، پیشبینی میکند که تغییر کدام بایتهای ورودی میتواند به افزایش پوشش کد منجر شود. Eclipser [9] با بررسی اینکه تغییر هر بایت از ورودی بر کدام شاخهها تأثیر میگذارد، شرطهای شاخه وابسته به ورودی (Input-Dependent Branch Predicates) را شناسایی میکند و سپس با استفاده از جستجوی دودویی (Binary Search) تلاش میکند نتیجه آن شاخه را معکوس (Flip) کند.
شایان ذکر است که در سالهای اخیر، فازینگ جعبهسفید (Whitebox Fuzzing) بهطور گسترده برای کشف آسیبپذیریهای هسته سیستمعامل (OS Kernel) و درایورهای دستگاه (Device Drivers) مورد مطالعه و استفاده قرار گرفته است. CAB-Fuzz [19] با بهینهسازی اجرای همزمان کانکولیک (Concolic Execution)، امکان پیمایش سریع مسیرهای اجرایی مهم و مستعد خطا را فراهم میکند تا آسیبپذیریها را در هستههای سیستمعامل تجاری (Commercial Off-The-Shelf یا COTS OS Kernels) شناسایی کند.
SemFuzz [54] از اطلاعات معنایی مرتبط با آسیبپذیریها که از گزارشهای متنی (Text Reports) استخراج میشوند، برای هدایت فرایند تولید دنبالههای فراخوانی سیستم (System Call Sequences) استفاده میکند؛ بهگونهای که این دنبالهها بتوانند موجب کرش هسته لینوکس شده و بهعنوان اثبات مفهوم (Proof-of-Concept یا PoC) برای بهرهبرداری از آسیبپذیریها عمل کنند.
IMF [16] با بهرهگیری از مدلهای وابستگی میان فراخوانیهای توابع API (Dependence Models Between API Function Calls) که از گزارشهای API (API Logs) استنتاج شدهاند، برنامهای تولید میکند که قادر است فازینگ هستههای سیستمعامل متداول (Commodity OS Kernels) را انجام دهد. DIFUZE [10] با استفاده از رابطهای اختصاصی (Specific Interfaces) که از طریق تحلیل ایستای (Static Analysis) کد درایورهای هسته (Kernel Driver Code) بازیابی شدهاند، ورودیهایی با ساختار صحیح (Correctly Structured Inputs) تولید میکند تا برای فازینگ درایورهای هسته مورد استفاده قرار گیرند. ترکیب فازینگ جعبهسفید (Whitebox Fuzzing) با فازینگ جعبهسیاه (Blackbox Fuzzing) یا فازینگ جعبهخاکستری (Greybox Fuzzing)، به فازینگ ترکیبی (Hybrid Fuzzing) منجر میشود.
در پایاننامه کارشناسی ارشد Pak [24]، ابتدا از اجرای نمادین (Symbolic Execution) برای کشف گرههای مرزی (Frontier Nodes) که نمایانگر مسیرهای اجرای منحصربهفرد هستند، استفاده میشود. سپس فازینگ جعبهسیاه از این گرهها آغاز میشود تا بخشهای عمیقتر کد در امتداد مسیرهای منشعب از آنها مورد کاوش قرار گیرند.
Stephens و همکاران [35] ابزار Driller را توسعه دادهاند که در شرایطی که فازینگ جعبهخاکستری به دلیل وجود قیود پیچیده (Complex Constraints) در انشعابهای برنامه دیگر قادر به پیشرفت و کشف مسیرهای جدید نیست، بهصورت انتخابی اجرای نمادین (Selective Symbolic Execution) را به کار میگیرد تا بذرهای ورودی جدید (New Seed Inputs) تولید کند. علاوه بر این، Shoshitaishvili و همکاران [33]، Driller را با هدف بهکارگیری دانش انسانی (Human Knowledge) توسعه دادهاند.
DigFuzz [56] یک مدل احتمالاتی مبتنی بر روش مونتکارلو (Monte Carlo-based Probabilistic Model) ارائه میکند که برای اولویتبندی مسیرها (Path Prioritization) در اجرای کانکولیک (Concolic Execution) در فازینگ ترکیبی بهکار میرود. QSYM [55] یک موتور سریع اجرای کانکولیک (Fast Concolic Execution Engine) طراحی میکند که اجرای نمادین (Symbolic Execution) را بهصورت تنگاتنگ با اجرای بومی (Native Execution) یکپارچه میسازد تا از فازینگ ترکیبی پشتیبانی کند.
علاوه بر این، Skyfire [36] رویکردی دادهمحور (Data-driven) برای تولید بذرهای اولیه (Initial Seeds) صحیح، متنوع و غیرمعمول ارائه میدهد. این رویکرد با بهرهگیری از دانشی شامل ویژگیهای نحوی (Syntax Features) و قواعد معنایی (Semantic Rules) که از مجموعه بزرگی از نمونههای مورد آزمون (Test Case Samples) آموخته شدهاند، ورودیهای اولیه مناسبی را برای آغاز فرایند فازینگ تولید میکند. Xu و همکاران [52] مجموعهای از عملگرهای اجرایی جدید (Operating Primitives) را طراحی کردهاند تا با کاهش زمان اجرای هر ورودی، عملکرد فازینگ را بهبود بخشند؛ بهویژه زمانی که فازینگ بهصورت موازی روی چندین هسته پردازنده اجرا میشود.
T-Fuzz [26] مفهوم فازینگ تبدیلی (Transformational Fuzzing) را معرفی میکند. این روش بهطور خودکار بررسیهای صحت (Sanity Checks) را که موجب گیر افتادن فرایند فازینگ در برنامه هدف میشوند، شناسایی و حذف میکند تا پوشش (Coverage) افزایش یابد. سپس، با استفاده از رویکردی مبتنی بر اجرای نمادین (Symbolic Execution)، باگهای واقعی (True Bugs) را در نسخه اصلی برنامه بازتولید (Reproduce) میکند.
۷. نتیجهگیری (Conclusion)
در این مقاله، اولین مطالعه نظامند را در مورد تأثیر معیارهای پوشش مختلف بر عملکرد فازینگ جعبهخاکستری (Grey-Box Fuzzing) انجام دادیم. این مطالعه بر روی مجموعه دادههای DARPA CGC، LAVA-M و فایلهای باینری دنیای واقعی انجام شد.برای این منظور، مفهوم حساسیت (Sensitivity) را هنگام مقایسه معیارهای پوشش بهطور رسمی تعریف کردیم و چندین معیار با سطوح حساسیت متفاوت را بررسی کردیم. نتایج نشان داد که هر معیار پوشش منجر به کشف مجموعههای متفاوتی از آسیبپذیریها میشود و هیچ معیار واحدی نمیتواند بر سایرین برتری مطلق داشته باشد.همچنین نشان دادیم که ترکیب معیارهای پوشش مختلف با یا بدون بذرگذاری متقاطع (Cross-Seeding) به کشف تعداد بیشتری از کرشها و در زمان کوتاهتر کمک میکند. امیدواریم این مطالعه، تحقیقات آینده را برای توسعه معیارهای پوشش پیشرفتهتر در حوزه فازینگ جعبهخاکستری فعالسازی کند.
منابع
[1] Cornelius Aschermann, Sergej Schumilo, Tim Blazytko, Robert Gawlik, and Thorsten Holz. 2019. REDQUEEN: Fuzzing with Input-to-State Correspondence. In Proceedings of the 2019 Annual Network and Distributed System Security Symposium (NDSS). The Internet Society.
[2] Marcel Böhme, Van-Thuan Pham, Manh-Dung Nguyen, and Abhik Roychoudhury. 2017. Directed Greybox Fuzzing. In Proceedings of the 2017 ACM SIGSAC Conference on Computer and Communications Security (CCS). ACM.
[3] Marcel Böhme, Van-Thuan Pham, and Abhik Roychoudhury. 2016. Coverage-based Greybox Fuzzing as Markov Chain. In Proceedings of the 2016 ACM SIGSAC Conference on Computer and Communications Security (CCS). ACM.
[4] DARPA CGC. 2014. Challenge Binaries. DARPA Cyber Grand https://github.com/ CyberGrandChallenge. (2014).
[5] Sang Kil Cha, Thanassis Avgerinos, Alexandre Rebert, and David Brumley. 2012. Unleashing mayhem on binary code. In Proceedings of the 2012 IEEE Symposium on Security and Privacy (Oakland). IEEE.
[6] Sang Kil Cha,Maverick Woo,and David Brumley. 2015. Program-Adaptive Mutational Fuzzing. In Proceedings of the 2015 IEEE Symposium on Security and Privacy (Oakland). IEEE.
[7] Peng Chen and Hao Chen. 2018. Angora: Efficient Fuzzing by Principled Search. In Proceedings of the 2018 IEEE Symposium on Security and Privacy (Oakland). IEEE.
[8] Vitaly Chipounov, Volodymyr Kuznetsov, and George Candea. 2011. S2E: A platform for in-vivo multi-path analysis of software systems. ACM SIGPLAN Notices 46, 3 (2011), 265–278.
[9] Jaeseung Choi, Joonun Jang, Choongwoo Han, and Sang Kil Cha. 2019. Grey-box Concolic Testing on Binary Code. In Proceedings of the 2019 International Conference on Software Engineering (ICSE). IEEE.
[10] Jake Corina, Aravind Machiry, Christopher Salls, Yan Shoshitaishvili, Shuang Hao, Christopher Kruegel, and Giovanni Vigna. 2017. DIFUZE: Interface Aware Fuzzing for Kernel Drivers. In Proceedings of the 2017 ACMSIGSAC Conference on Computer and Communications Security (CCS). ACM.
[11] Brendan Dolan-Gavitt, Patrick Hulin, Engin Kirda, Tim Leek, Andrea Mambretti, Wil Robertson, Frederick Ulrich, and Ryan Whelan. 2016. Lava: Large-scale automated vulnerability addition. In Proceedings of the 2016 IEEE Symposium on Security and Privacy (Oakland). IEEE.
[12] Shuitao Gan, Chao Zhang, Xiaojun Qin, Xuwen Tu, Kang Li, Zhongyu Pei, and Zuoning Chen. 2018. CollAFL: Path Sensitive Fuzzing. In Proceedings of the 2018 IEEE Symposium on Security and Privacy (Oakland). IEEE.
[13] Vijay Ganesh, Tim Leek, and Martin Rinard. 2009. Taint-based directed whitebox fuzzing. In Proceedings of the 31st International Conference on Software Engineering (ICSE). IEEE.
[14] GregoryGay,MattStaats,MichaelWhalen,andMatsPE Heimdahl. 2015. The Risks of Coverage-Directed Test Case Generation. IEEE Transactions on Software Engineering 41, 8 (2015), 803–819.
[15] Patrice Godefroid, Michael Y Levin, David A Molnar, and others. 2008. Automated whitebox fuzz testing. In Proceedings of the 2008 Annual Network and Distributed System Security Symposium (NDSS). The Internet Society.
[16] HyungSeok Han andSang Kil Cha. 2017. IMF: Inferred Model-based Fuzzer. In Proceedings of the 2017 ACM SIGSAC Conference on Computer and Communications Security (CCS). ACM.
[17] Laura Inozemtseva and Reid Holmes. 2014. Coverage Is Not Strongly Correlated with Test Suite Effectiveness. In Proceedings of the 36th International Conference on Software Engineering (ICSE). ACM.
[18] Ulf Kargén and Nahid Shahmehri. 2015. Turning programs against each other: high coverage fuzz-testing using binary-code mutation and dynamic slicing. In Proceedings of the 2015 10th Joint Meeting on Foundations of Software Engineering (FSE). ACM.
[19] SuYongKim,SanghoLee,InsuYun,WenXu,Byoungyoung Lee, Youngtae Yun, and Taesoo Kim. 2017. CABFuzz: Practical Concolic Testing Techniques for COTSOperating Systems. In Proceedings of the 2017 USENIX Fuzzing. In Proceedings of the 24th USENIX Security Annual Technical Conference. USENIX. [20] George T. Klees, Andrew Ruef, Benjamin Cooper, Shiyi Wei, and Michael Hicks. 2018. Evaluating Fuzz Testing. In Proceedings of the 2018 ACMSIGSACConferenceon Computer and Communications Security (CCS). ACM. [21] Zhiqiang Lin, Xiangyu Zhang, and Dongyan Xu. 2008. Convicting exploitable software vulnerabilities: An efficient input provenance based approach. In IEEE International Conference on Dependable Systems andNetworks (DSN). IEEE.
[22] Barton P Miller, Louis Fredriksen, and Bryan So. 1990. An empirical study of the reliability of UNIX utilities. Commun. ACM 33, 12 (1990), 32–44.
[23] Shankara Pailoor, Andrew Aday, and Suman Jana. 2018. MoonShine: Optimizing OS Fuzzer Seed Selection with Trace Distillation. In Proceedings of the 27th USENIX Security Symposium. IEEE.
[24] Brian S Pak. 2012. Hybrid fuzz testing: Discovering software bugs via fuzzing and symbolic execution. In Master’s thesis, School of Computer Science Carnegie Mellon University (2012).
[25] Jianfeng Pan, Guanglu Yan, and Xiaocao Fan. 2017. Digtool: A Virtualization-Based Framework for Detecting Kernel Vulnerabilities. In Proceedings of the 26th USENIX Security Symposium. USENIX.
[26] Hui Peng, Yan Shoshitaishvili, and Mathias Payer. 2018. T-Fuzz: fuzzing by program transformation. In Proceedings of the 2018 IEEE Symposium on Security and Privacy (Oakland). IEEE.
[27] Theofilos Petsios, Jason Zhao, Angelos D Keromytis, and Suman Jana. 2017. SlowFuzz: Automated DomainIndependent Detection of Algorithmic Complexity Vulnerabilities. In Proceedings of the 2017 ACM SIGSAC Conference on Computer and Communications Security (CCS). ACM.
[28] Mohit Rajpal, William Blum, and Rishabh Singh. 2017. Not all bytes are equal: Neural byte sieve for fuzzing. arXiv preprint arXiv:1711.04596 (2017).
[29] Sanjay Rawat, Vivek Jain, Ashish Kumar, Lucian Cojocar, Cristiano Giuffrida, and Herbert Bos. 2017. VUzzer: Application-aware Evolutionary Fuzzing. In Proceedings of the 2017 Annual Network andDistributed System Security Symposium (NDSS). The Internet Society.
[30] Alexandre Rebert, Sang Kil Cha, Thanassis Avgerinos, Jonathan M Foote, David Warren, Gustavo Grieco, and David Brumley. 2014. Optimizing Seed Selection for USENIX Association Symposium. USENIX.
[31] Sergej Schumilo, Cornelius Aschermann, Robert Gawlik, Sebastian Schinzel, and Thorsten Holz. 2017. kAFL: Hardware-Assisted Feedback Fuzzing for OS Kernels. In Proceedings of the 26th USENIX Security Symposium. USENIX.
[32] Dongdong She, Kexin Pei, Dave Epstein, Junfeng Yang, Baishakhi Ray, and Suman Jana. 2019. NEUZZ: Efficient Fuzzing with Neural Program Learning. In Proceedings of the 2019 IEEE Symposium on Security and Privacy (Oakland). IEEE. [33] YanShoshitaishvili,Michael Weissbacher,Lukas Dresel, Christopher Salls, Ruoyu Wang, Christopher Kruegel, and Giovanni Vigna. 2017. Rise of the HaCRS: Augmenting Autonomous Cyber Reasoning Systems with Human Assistance. In Proceedings of the 2017 ACM SIGSAC Conference on Computer and Communications Security (CCS). ACM.
[34] Dawn Song, David Brumley, Heng Yin, Juan Caballero, Ivan Jager, Min Kang, Zhenkai Liang, James Newsome, Pongsin Poosankam, and Prateek Saxena. 2008. BitBlaze: A new approach to computer security via binary analysis. Information Systems Security (2008), 1–25.
[35] Nick Stephens, John Grosen, Christopher Salls, Andrew Dutcher, Ruoyu Wang, Jacopo Corbetta, Yan Shoshitaishvili, Christopher Kruegel, and Giovanni Vigna. 2016. Driller: Augmenting Fuzzing Through Selective Symbolic Execution.. In Proceedings of the 2016 Annual Network and Distributed System Security Symposium (NDSS). The Internet Society.
[36] Junjie Wang,Bihuan Chen,Lei Wei,andYang Liu. 2017. Skyfire: Data-driven Seed Generation for Fuzzing. In Proceedings of the 2017 IEEE Symposium on Security and Privacy (Oakland). IEEE.
[37] Tielei Wang, Tao Wei, Guofei Gu, and Wei Zou. 2010. TaintScope: A Checksum-aware Directed Fuzzing Tool for Automatic Software Vulnerability Detection. In Proceedings of the 2010 IEEE Symposium on Security and Privacy (Oakland). IEEE.
[38] Website. 2018. American Fuzzy Lop (AFL) Fuzzer. http://lcamtuf.coredump.cx/afl/. (2018). Accessed: 2018-04.
[39] Website. 2018. Angr: a framework for analyzing binaries. https://angr.io/. (2018). Accessed: 2018-04. [40] Website. 2018. honggfuzz. http://honggfuzz.com/. (2018). Accessed: 2018-04.
[40] Website. 2018. honggfuzz. http://honggfuzz.com/. (2018). Accessed: 2018-04.
[41] Website. 2018. Intel PIN Tool. https: [51] Maverick Woo, Sang Kil Cha, Samantha Gottlieb, and //software.intel.com/en-us/articles/ pin-a-dynamic-binary-instrumentation-tool. (2018). Accessed: 2018-04.
[42] Website. 2018. pora. The LAVA Synthetic Bug Corhttps://moyix.blogspot.com/2016/10/ the-lava-synthetic-bug-corpora.html/. (2018). Accessed: 2018-04.
[43] Website. 2018. libFuzzer. https://llvm.org/docs/ LibFuzzer.html. (2018). Accessed: 2018-04.
[44] Website. 2018. Of Bugs and Baselines. https://moyix.blogspot.com/2018/03/ of-bugs-and-baselines.html. (2018). Accessed: 2018-04.
[45] Website. 2018. OSS Fuzz. https: //testing.googleblog.com/2016/12/ announcing-oss-fuzz-continuous-fuzzing. html. (2018). Accessed: 2018-04.
[46] Website. 2018. Peach Fuzzer. https://www.peach. tech/. (2018). Accessed: 2018-04. [47] Website. 2018. Security @ Adobe. //blogs.adobe.com/security/2012/05/ https: a-basic-distributed-fuzzing-framework-for-foe. html. (2018). Accessed: 2018-04.
[48] Website. 2018. Trail of Bits Blog. //blog.trailofbits.com/2016/11/02/ shin-grr-make-fuzzing-fast-again. Accessed: 2018-04. https: (2018).
[49] Website. 2018. Utilities for automated crash sample processing/analysis. https://github.com/rc0r/ afl-utils. (2018). Accessed: 2018-04.
[50] Website. 2018. Zzuf: multi-purpose fuzzer. http:// caca.zoy.org/wiki/zzuf. (2018). Accessed: 201804. 14 David Brumley. 2013. Scheduling Black-box Mutational Fuzzing. In Proceedings of the 2013 ACM SIGSAC Conference on Computer and Communications Security (CCS). ACM.
[51] Maverick Woo Sang Kil Cha, Samantha Gottlieb, andDavid Brumley 2013. Scheduling Black-box Mutational Fuzzing. In Proceedings of the 2013 ACM SIGSAC Conference on Computer and Communications Security (CCS). ACM.
[52] WenXu,Sanidhya Kashyap,andTaesoo Kim. 2017. Designing New Operating Primitives to Improve Fuzzing Performance. In Proceedings of the 2017 ACM SIGSAC Conference on Computer and Communications Security (CCS). ACM.
[53] Wei You, Xueqiang Wang, Shiqing Ma, Jianjun Huang, Xiangyu Zhang, XiaoFeng Wang, and Bin Liang. 2019. ProFuzzer: On-the-fly Input Type Probing for Better Zero-day Vulnerability Discovery. In Proceedings of the 2019 IEEE Symposium on Security and Privacy (Oakland). IEEE.
[54] Wei You, Peiyuan Zong, Kai Chen, XiaoFeng Wang, Xiaojing Liao, Pan Bian, and Bin Liang. 2017. SemFuzz: Semantics-based Automatic Generation of Proofof-Concept Exploits. In Proceedings of the 2017 ACM SIGSAC Conference on Computer and Communications Security (CCS). ACM.
[55] Insu Yun, Sangho Lee, Meng Xu, Yeongjin Jang, and Taesoo Kim. 2018. QSYM: APractical Concolic Execution Engine Tailored for Hybrid Fuzzing. In Proceedings of the 27th USENIX Security Symposium. USENIX.
[56] Lei Zhao, Yue Duan, Heng Yin, and Jifeng Xuan. 2019. Send Hardest Problems My Way: Probabilistic Path Prioritization for Hybrid Fuzzing. In Proceedings of the 2019 Annual Network and Distributed System Security Symposium (NDSS). The Internet Society.