آزمون فازی یا فازینگ (Fuzz testing – Fuzzing) در سالهای اخیر در شناسایی نقصهای امنیتی پیشرفت چشمگیری داشته است. این روش تعداد زیادی موارد آزمایشی (test cases) تولید کرده و اجرای آنها را برای یافتن خطاها پایش میکند. فازینگ تاکنون هزاران باگ (Bug) و آسیبپذیری را در برنامههای مختلف شناسایی کرده است.
با وجود اثربخشی، هنوز یک تحلیل نظاممند از شکافهایی که فازینگ با آنها مواجه است وجود ندارد. فازینگ باید به عنوان یک تکنیک کشف نقص و آسیب پذیری، فاصله بین فضای کل ورودیها و نقصها را کاهش دهد. بدون اعمال محدودیت در ورودیهای تولید شده، فضای ورودی نامتناهی است. در مقابل، نقصها در یک برنامه بسیار پراکندهاند، که نشان میدهد فضای نقصها بسیار کوچکتر از کل فضای ورودی است.
علاوه بر این، از آنجا که فازینگ تعداد زیادی موارد آزمون (test cases) تولید میکند تا اهداف را به صورت تکراری بررسی کند، لازم است این فرآیند به صورت خودکار انجام شود. با توجه به پیچیدگی برنامهها و انواع نقصها، خودکارسازی اجرای برنامههای متنوع چالشبرانگیز است. ما در این مقاله، به صورت نظاممند شکافها و همچنین راهحلهای آنها را با در نظر گرفتن گستره (breadth) و عمق (depth) بررسی و تحلیل میکنیم. این مطالعهٔ مروری میتواند به عنوان یک نقشهراه برای هر دو گروه مبتدیان و توسعهدهندگان پیشرفته عمل کند تا درک بهتری از فازینگ به دست آورند.
۱. مقدمه (INTRODUCTION)
امنیت نرمافزار یک مشکل جدی در سیستمهای کامپیوتری است که بر زندگی روزمره مردم تأثیر میگذارد و حتی باعث مشکلات مالی شدیدی میشود [109، 169]. آزمون فازی (Fuzz testing) به یکی از موفقترین تکنیکها برای تشخیص نقصهای امنیتی در برنامهها تبدیل شده است. فازینگ (Fuzzing)، موارد آزمایشی متعددی را برای آزمایش مکرر برنامههای هدف ایجاد و استثنائات برنامه را رصد میکند. استثنائات، شاخصهای نقصهای امنیتی بالقوه هستند. بهطورکلی، فازینگ دارای صفی از بذرها (Seed) است که به عنوان ورودی در نظر گرفته میشوند و ورودیهای جدید از طریق جهش (mutation) این بذرها در یک حلقه بینهایت تولید میگردند. با هدایت منابع محاسباتی برای فازینگ به روشهای مختلف [22، 23، 37، 40، 65، 188، 202]، محققان میتوانند آسیبپذیریها را به طور مؤثرتر و کارآمدتری کشف کنند. تاکنون، فازینگ هزاران باگ در برنامههای دنیای واقعی، مانند باگهای کشف شده در برنامههای کاربردی عمومی [30]، دستگاههای اینترنت اشیا (IoT[1]) [36]، میانافزار (firmware) [211]، هستهها (kernel) [194] و سیستمهای پایگاه داده (database systems) [212] را کشف کرده است.
اگرچه فازینگ در تشخیص نقصهای امنیتی به موفقیتهای بزرگی دست یافته است، اما هنوز شکافهای دانشی برای توسعه راهحلهای کارآمد تشخیص نقص دارد. همانطور که در شکل ۱ نشان داده شده است، سه شکاف اصلی عبارتند از فضای نقص پراکنده ورودیها، فضای ورودی معتبر دقیق و اجرای خودکار اهداف مختلف. پاراگرافهای زیر جزئیات شکافها را توضیح میدهند.
شکاف ۱: فضای نقص پراکنده ورودیها. نقصها در برنامهها پراکنده هستند و فقط برخی از ورودیهای خاص میتوانند نقصها را ایجاد کنند. از آنجا که هدف اصلی فازینگ تشخیص نقصها در برنامههای هدف است، نظریههای فازینگ برای تولید ورودیهایی که متعلق به فضای نقص هستند، مورد نیاز هستند. برخی از نقصهای امنیتی کمعمق هستند به طوری که میتوان آنها را در مدت زمان کوتاهی از کمپینهای فازینگ کشف کرد. با این حال، بسیاری از نقصهای امنیتی برای بررسی مسیرهای اجرایی پیچیده و حل محدودیتهای مسیر تنگ، به فازینگ نیاز دارند. بنابراین، یک الگوریتم فازینگ بسیار کارآمد نیاز به درک پیچیدهای از برنامههای تحت آزمون (PUT یا Program Under Test) و نقصهای امنیتی دارد. از آنجا که نقصها معمولاً قبل از فازینگ ناشناخته هستند، نظریههای فازینگ مبتنی بر درک PUTها و/یا نقصهای امنیتی، منابع محاسباتی را به سمت مناطقی از کد هدایت میکنند که احتمال وجود نقص در آنها بیشتر است.
شکاف ۲: فضای ورودی معتبر دقیق. فازینگ در برنامههای مختلف مورد استفاده قرار گرفته است و هر برنامه به ورودیهای خاص خود نیاز دارد. برنامههای مدرن به طور فزایندهای بزرگتر میشوند و در نتیجه مشخصات ورودیها پیچیدهتر میشود. بنابراین، تولید ورودیهای معتبری که برنامههای هدف بپذیرند، چالش برانگیز است. علاوه بر این، برای بهبود کارایی فازینگ، بهتر است ورودیهای تولید شده حالتهای اجرایی مختلفی را اعمال کنند (مثلاً پوشش کد). این امر مستلزم فازینگ برای توسعه طرحهای پیشرفتهتر به منظور تولید ورودیهای معتبر است. بدون تجزیه و تحلیل سیستماتیک PUTها، محدود کردن دقیق فضای ورودی تقریباً غیرممکن است. به عنوان مثال، یک جهش تصادفی از فایلهای PDF ممکن است مشخصات PDF را نقض کند. فازینگ باید فایلهای PDF را با دقت جهش دهد تا ورودیهای تولید شده متعلق به فضای ورودی معتبر باشند.
شکاف ۳: اهداف مختلف. از آنجا که فازینگ به طور مکرر PUTها را برای آزمونهای متعدد آزمایش میکند، فرآیندهای فازینگ برای کارایی بالا باید به صورت خودکار انجام شوند. به دلیل تنوع PUTها و نقصها، محیطهای اجرا متفاوت هستند. فازینگ برخی از برنامهها به صورت خودکار، مانند برنامههای خط فرمان، ساده است. با این حال، بسیاری از برنامههای دیگر مانند سختافزار برای آزمایش خودکار نیاز به تلاش بیشتری دارند. علاوه بر این، نقصهای امنیتی نیز به شاخصهای خودکار برای ثبت نقصهای واقعی بالقوه نیاز دارند. خرابی اجرای برنامه یک شاخص پرکاربرد است زیرا به طور خودکار استثنائات را از سیستمهای عامل دریافت میکند. با این حال، بسیاری از نقصهای امنیتی دیگر ممکن است خود را به صورت خرابی نشان ندهند، مانند رقابتهای داده. این نقصها نیاز به طراحیهای دقیقی دارند تا به طور خودکار در طول فازینگ ثبت شوند.
جامعه تحقیقاتی تلاشهای زیادی برای کاهش این شکافها انجام داده است. نظریههای زیادی برای فرموله کردن جزئی فرآیندهای فازینگ ارائه شده است. رویکردهای مختلفی برای کاهش فضای ورودی طراحی شدهاند. علاوه بر این، سناریوهای اجرایی مختلف با موفقیت خودکار شدهاند. چند نظرسنجی، فازینگ را روشن کردهاند، اما هیچ یک از آنها به طور سیستماتیک شکافهای فازینگ و همچنین راهحلهای آنها را بررسی و تجزیه و تحلیل نمیکنند [102، 107، 119]. بنابراین، هنوز در مورد سؤالاتی مانند اینکه شکافها چیستند، راهحلهای بالقوه چیستند و چگونه میتوان شکافها را پر کرد، مشخص نیست. در حالی که سایر نظرسنجیها بر چیستی فازینگ تمرکز دارند، این مقاله همچنین توضیح میدهد که چگونه و چرا راهحلهای موجود مشکلات را حل میکنند. با چنین اطلاعاتی، این مقاله یک نقشه راه برای پر کردن شکافها و هموار کردن راهها برای تحقیقات آینده ایجاد میکند. برای مبتدیانی که دانش محدودی در مورد فازینگ دارند، این مقاله مفهوم فازینگ و راهحلهای موجود برای بهبود فازینگ را در اختیار آنها قرار میدهد. برای توسعهدهندگان پیشرفته، این مقاله همچنین سه مسیر اصلی (یعنی سه شکاف) را در اختیارشان قرار میدهد تا بتوانند با دنبال کردن یک یا چند مسیر، به موفقیت دست یابند.
در این مقاله، ما به طور سیستماتیک شکافها و راهحلهای فازینگ را با در نظر گرفتن وسعت و عمق بررسی و تحلیل میکنیم. از آنجایی که فازینگ در درجه اول تکنیکی برای مسائل امنیتی است، ما عمدتاً مقالاتی را از کنفرانسهای امنیتی و نرمافزاری، از جمله اما نه محدود به چهار کنفرانس امنیت سایبری و سه کنفرانس مهندسی نرمافزار، از ژانویه ۲۰۰۸ تا مه ۲۰۲۱ جمعآوری میکنیم.
چهار کنفرانس امنیت سایبری عبارتند از کنفرانس ACM در مورد امنیت کامپیوتر و ارتباطات ([2]CCS)، سمپوزیوم امنیت شبکه و سیستمهای توزیعشده (NDSS[3])، سمپوزیوم IEEE در مورد امنیت و حریم خصوصی (Security and privacy –[4]S&P) و سمپوزیوم امنیت Usenix ([5]USENIX). سه کنفرانس مهندسی نرمافزار عبارتند از کنفرانس بینالمللی مهندسی نرمافزار خودکار (ASE[6])، کنفرانس بینالمللی مهندسی نرمافزار (ICSE[7]) و سمپوزیوم ACM SIGSOFT در مورد بنیاد مهندسی نرمافزار/کنفرانس مهندسی نرمافزار اروپا ([8]FSE/ESEC).
این مقاله به این شرح سازماندهی شده است: بخش ۲ مروری بر فازینگ ارائه میدهد. بخش ۳ فرآیندهای فازینگ و نظریههای مختلف فازینگ را برای فرموله کردن فرآیندها به تصویر میکشد. بخش ۴ راهحلهای متنوع برای کاهش فضای جستجوی ورودیها را تجزیه و تحلیل میکند. بخش ۵ نحوه خودکارسازی اجرای PUTهای (برنامه تحت آزمون[9]) مختلف و تشخیص انواع اشکالات را تجزیه و تحلیل میکند. بخش ۶ جهتهایی را برای تحقیقات آینده ارائه میدهد.
۲. مروری بر فازینگ (OVERVIEW OF FUZZING)
اصطلاحات. ابتدا برای سهولت در مطالعه، چند اصطلاح را معرفی میکنیم. همانطور که در شکل ۲ نشان داده شده است، یک ورودی زمانی به عنوان بذر (seed) نگه داشته میشود که از نظر شایستگی (fitness) عملکرد بهتری داشته باشد (برای مثال، پوشش جدیدی ایجاد کند).
شایستگی یا معیار ارزیابی کیفیت (fitness)، کیفیت یک بذر یا ورودی را اندازهگیری میکند. در ادامه، در طول کمپینهای فازینگ، بذرهایی از مجموعه بذرها انتخاب میشوند تا روی آنها عملیات جهش (mutation) انجام شود. عملگرهای جهش را «جهش دهنده» (mutator) مینامند. زمانی که یک بذر از مجموعه بذرها انتخاب میشود، یک «برنامه زمانبندی توان» (power schedule) میزان انرژی اختصاصیافته به آن بذر را تعیین میکند. انرژی در اینجا به تعداد جهشهایی اشاره دارد که در دور فعلی فازینگ به آن بذر اختصاص داده میشود. پیادهسازی یک الگوریتم فازینگ را «فازر» (fuzzer) مینامند.
در سال 1990، بی. پی. میلر ( B. P. Mille) و همکارانش 90 برنامه را با اجرای آنها روی رشتههای ورودی تصادفی آزمایش کردند و دریافتند که بیش از 24٪ از آنها از کار میافتند [129]. برنامهای که رشتههای ورودی تصادفی تولید میکرد، توسط میلر فاز (fuzz) نامگذاری شد. از آن زمان، آزمایش فاز (یا فازینگ) به نام تکنیکی تبدیل شده است که اشکالات را از طریق موارد آزمایشی متعدد شناسایی میکند. امروزه، از آنجا که برنامهها به طور فزایندهای پیچیدهتر میشوند و فازینگ یک رویکرد ارزان است، فازینگ یکی از ابزارهای اصلی برای کشف اشکالات است. همانطور که در شکل 2 نشان داده شده است، فازینگ از سه جزء اساسی تشکیل شده است، یعنی مولد ورودی، اجراکننده و مانیتور نقص. مولد ورودی، ورودیهای متعددی را در اختیار اجراکننده قرار میدهد و اجراکننده برنامههای هدف را روی ورودیها اجرا میکند. سپس، فازینگ اجرا را نظارت میکند تا بررسی کند که آیا حالتهای اجرایی یا نقصهای جدیدی (مثلاً خرابیها) را کشف میکند یا خیر.
فازینگ از دیدگاه تولید ورودی به دو دسته تقسیم میشود: فازینگ مبتنی بر تولید (generation-based) و فازینگ مبتنی بر جهش (mutation-based). فازینگ مبتنی بر تولید، ورودیها را از ابتدا و بر اساس گرامرها [3, 56, 57] یا مجموعهای از دادههای معتبر (corpus) [74, 79, 111, 112, 185] تولید میکند. همانطور که در شکل ۲ نشان داده شده، این نوع فازینگ ورودیها را مستقیماً از یک مجموعه بذر (seed) دریافت میکند.
در مقابل، فازینگ مبتنی بر جهش، ورودیهای موجود (که به آنها seed یا بذر گفته میشود) را تغییر میدهد تا ورودیهای جدید ایجاد کند [22, 23, 66, 206, 216]. با داشتن یک مجموعه بذر (seed)، این نوع فازینگ مراحل زمانبندی بذر، زمانبندی بایت، و زمانبندی جهش را انجام میدهد تا ورودیها را تولید کند. لازم به ذکر است که فازینگ لزوماً نیازی ندارد همه مراحل شکل ۲ را طی کند. برای مثال، فازینگ مبتنی بر تولید، زمانبندی بایت یا جهش را انجام نمیدهد و بیشتر روی انتخاب بهترین مجموعه بذر از فایلهای ورودی اولیه تمرکز دارد.
بر اساس میزان اطلاعاتی که در حین اجرا مشاهده میشود، فازینگ به سه دسته تقسیم میشود: جعبه سیاه (blackbox)، جعبه سفید (whitebox) و جعبه خاکستری (greybox).
- فازینگ جعبه سیاه (blackbox) هیچ دانشی از حالتهای داخلی اجرای برنامه ندارد [3, 29, 36, 78, 99]. این نوع فازرها معمولاً با استفاده از قالب ورودیها [59, 78, 99] یا حالتهای خروجی مختلف [55, 61] فرایند فازینگ را بهینه میکنند.
- فازینگ whitebox تمام اطلاعات داخلی اجرای برنامه را در اختیار دارد و میتواند فضای حالت برنامه هدف را بهصورت سیستماتیک بررسی کند. این نوع معمولاً از اجرای نمادین ترکیبی یا کونکولیک (concolic execution) برای تحلیل برنامهها استفاده میکند [71, 81, 150, 177, 204].
- فازینگ جعبه خاکستری (greybox) سطحی از اطلاعات بین این دو حالت دارد؛ برای مثال بسیاری از فازرها از پوشش یالها (edge coverage) به عنوان اطلاعات داخلی اجرای برنامه استفاده میکنند [7, 23, 66, 133, 216].
رایجترین حالتهای اجرایی، اطلاعات مربوط به پوشش کد هستند) مانند بلاکهای پایه (basic blocks) [133] یا یالها (edges) [206] در گراف جریان کنترل (CFG)). فرض اساسی در استفاده از پوشش این است که کشف حالتهای اجرایی بیشتر (مثلاً پوشش جدید) احتمال یافتن باگها را افزایش میدهد. برای مثال، Miller [130] گزارش میدهد که افزایش ۱٪ در پوشش کد منجر به افزایش ۰.۹۲٪ در کشف باگ میشود. بنابراین، فازینگ هدایت شده با پوشش (coverage-guided fuzzing) با هدف افزایش پوشش کد انجام میشود [23, 66, 101, 203, 206]. با این حال، به دلیل کاربردهای متنوع فازینگ، حالتهای اجرایی فقط به پوشش کد محدود نمیشوند. این حالتها میتوانند شامل موارد زیر باشند:
- معتبر بودن اجرا در برنامههای شیگرا [141]
- ماشین حالت در پیادهسازی پروتکلها [3, 11, 55, 61, 64, 69, 154]
- پوشش هم ارجاعی (alias) در پیادهسازیهای همزمانی [194]
- پوشش نورونی (neuron coverage) در مدلهای یادگیری عمیق [148]
- لاگهای اجرایی در تلویزیون هوشمند اندروید [1]
فازرها معمولاً از کرش (crash) به عنوان شاخص باگهای امنیتی استفاده میکنند، زیرا کرشها ثبت خودکار و سادهای دارند [206]. سیستمعاملها بهطور خودکار سیگنالهایی برای اطلاع از کرش برنامه تولید میکنند. با این حال، برخی از نقصها بهصورت کرش ظاهر نمیشوند؛ بنابراین فازرها از شاخصهای دیگری مانند نقض ایمنی فیزیکی نیز استفاده میکنند [41, 82]. نکته مهم این است که این شاخصها فقط نشاندهنده وجود احتمالی مشکلات امنیتی هستند و برای تأیید نهایی آسیبپذیری، نیاز به بررسی بیشتر توسط ابزارهای امنیتی یا تحلیل دستی دارند [85, 168, 175].
۳. نظریه فازینگ (FUZZING THEORY)
هدف اصلی فازینگ، جستجوی موارد آزمایشی (test cases) است که بتوانند نقصها (مانند باگها) را تحریک کنند. چالش اینجاست که بهدلیل پیچیدگی برنامههای هدف (PUT)، فضای جستجو نامحدود است. بنابراین، پیدا کردن ورودیهایی که باعث بروز نقص شوند با استفاده از جهشهای کور (blind mutation)، مانند پیدا کردن سوزن در انبار کاه است.
برای افزایش احتمال کشف نقصها، فازرها از بازخورد اجرای برنامه، مانند حالتهای اجرایی یا نتایج، بهعنوان معیار ارزیابی کیفیت (fitness) استفاده میکنند. یک معیار رایج، مبتنی بر پوشش کد (مانند basic block یا edge) است [23, 39, 116, 157, 203, 210] که برای تعیین میزان پاداش ورودیهای تولید شده استفاده میشود. با این حال، پوشش کد همیشه در دسترس نیست، و حتی زمانی که در دسترس باشد، ممکن است به اندازه کافی حساس نباشد تا نقصها را آشکار کند (بخش 3.5).
علاوه بر این، اگر فقط از پوشش کد بهعنوان بازخورد استفاده شود، حتی اگر تعداد ورودیهای تولید شده در هر دقیقه بهصورت نمایی افزایش یابد (مثلاً با استفاده از ماشینهای بیشتر)، تعداد آسیبپذیریهای کشف شده تنها بهصورت خطی افزایش پیدا میکند [19]. بنابراین، یک راهکار رایج این است که فرایند فازینگ بهینهسازی شود یا اطلاعات مورد استفاده در معیار ارزیابی کیفیت (fitness) غنیتر گردد.
نظریههای فازینگ قصد دارند فرآیندهای فازینگ را بهینه کنند تا فازینگ بتواند نقصها را به طور مؤثرتر و کارآمدتری آشکار کند؛ یعنی فازینگ میتواند نقصها را در بودجه زمانی کوتاهتر یا با موارد آزمایش کمتر کشف کند. فازینگهای موجود از راهحلهای مختلف مسائل بهینهسازی برای فازینگ فرآیندها استفاده میکنند. همانطور که در شکل 2 نشان داده شده است، فازینگ میتواند مجموعه بذر (seed set)، برنامه زمانبندی بذر (seed schedule)، برنامه زمانبندی بایت (byte schedule) و برنامه جهش (mutation schedule) را با شایستگی یا معیار ارزیابی کیفیت (fitness) مبتنی بر حالتهای اجرا یا کشف نقص بهینه کند. جدول ۱ راهحلهای بهینهسازی برای فرآیندهای فازینگ مختلف را نشان میدهد. ستون Fitness By نشان میدهد که چگونه راهحلهای مربوطه فرآیندهای فازینگ را فرموله میکنند. ستونهای Gene. -based و Muta.-based به ترتیب فازینگ مبتنی بر تولید و مبتنی بر جهش هستند. فازینگهای جدول 1 انتخاب شدهاند زیرا سهم اصلی آنها توسعه نظریههای فازینگ است.
۳.۱ انتخاب مجموعه بذر (Seed Set Selection)
بهینهسازی مجموعههای اولیه بذرها بر کمینهسازی اندازه یک مجموعه تمرکز دارد؛ یعنی کمترین تعداد اولیهای را انتخاب میکند که میتوانند تمام پوشش کد کشفشده را پوشش دهند [۲، ۱۴۷، ۲۰۶]. دلیل کمینهسازی این است که افزونگی اولیهها، منابع محاسباتی را برای بررسی نواحی کد که به خوبی بررسی شدهاند، هدر میدهد. COVERSET [158] مسئله کمینهسازی یک مجموعه اولیه را به عنوان یک مسئله پوشش مجموعه حداقل (MSCP[9]) فرموله میکند که زیرمجموعههایی را که شامل همه عناصر هستند، کمینه میکند. از آنجایی که MSCP یک مسئله NP-hard است، COVERSET از یک الگوریتم تقریبی چندجملهای حریصانه برای به دست آوردن مجموعه حداقل استفاده میکند.
3.2 برنامه زمانبندی بذر (Seed Schedule)
با مجموعه بذر (Seed)، برنامه زمانبندی بذر با هدف حل مسائل (1) انتخاب بذر برای دور بعدی و (2) بودجه زمانی برای بذر انتخاب شده، انجام میشود. در عمل، به جای بودجه زمانی، اکثر فازرها تعداد دفعات جهش بذرهای انتخاب شده را بهینه میکنند [23، 203، 206]. اگرچه این دو مسئله کاملاً واضح هستند، اما راهحلهای موجود برای بهینهسازی آنها به دلیل پیچیدگی PUTها یا اشکالات متفاوت است. مهمترین چالش، عدم قطعیت پوشش کد یا اشکالات کشف نشده است. قبل از تأیید اشکالات، نمیتوان دانست که آیا یک ورودی میتواند باعث ایجاد یک اشکال شود یا خیر. بنابراین، مسئله بهینهسازی برازش مؤثری ندارد. به طور مشابه، قبل از بررسی خطوط کد، نمیتوان توزیع احتمال رفتارهای برنامه (مثلاً رفتارهای شاخهای) را به دست آورد. بنابراین، یافتن راهحل بهینه سراسری از نظر ریاضی (تقریباً) غیرممکن است. در نتیجه، محققان تقریباً یا تا حدی فرآیندهای فازینگ را بر اساس مسائل بهینهسازی متنوع فرموله میکنند. همانطور که در شکل 2 نشان داده شده است، نظریههای فازینگ را میتوان بر اساس ویژگیهای نقصها (مثلاً ورود باگ) یا حالتهای اجرا (مثلاً انتقال لبه) طراحی کرد.
3.2.1 ارزیابی کیفیت بر اساس تعداد باگها (Fitness by #Bugs)
بهطور کلی، فازینگ از دو نوع معیار شایستگی (fitness) برای مسائل بهینهسازی استفاده میکند: یکی ارزیابی کیفیت مبتنی بر باگها و دیگری مبتنی بر وضعیت اجرای برنامه (مانند پوشش کد). ارزیابی کیفیت یک مقدار قابل سنجش است که کیفیت یک بذر یا ورودی را اندازهگیری میکند. از آنجا که فازینگ روشی برای کشف باگهاست، یک معیار شایستگی و ارزیابی بدیهی میتواند تعداد باگها باشد.
برای بیشینهسازی تعداد باگها، یکی از رویکردها این است که بودجه زمانی هر بذر زمانبندی شود، در حالی که بذرها بهصورت تصادفی یا ترتیبی انتخاب میشوند. بدون در نظر گرفتن وضعیتهای اجرایی، این مسئله بیشینهسازی را میتوان بهصورت یک مسئله برنامهریزی خطی عدد صحیح (Integer Linear Programming – ILP) سادهسازی کرد [158]. به این معنا که ILP تلاش میکند تعداد باگها را تحت قیود خطی، مانند کران بالای بودجه زمانی برای هر بذر، بیشینه کند. با حل این مسئله ILP، میتوان بهطور خودکار بودجه زمانی هر بذر را محاسبه کرد. دیدگاه دیگری نیز این است که فرایند رسیدن به باگها را بهصورت نسخه وزندار مسئله «جمعآوری کوپنها» (Weighted Coupon Collector’s Problem – WCCP) در نظر بگیریم [13].
جدول 1. فازرها و راهحلهای بهینهسازی آنها
Year | Fuzzer | Solution(Process) | Fitness By | Target App/Bug | Input | Runtime Info. | |
Muta.-based | Gene.-based | ||||||
2006 | Sidewinder [62] | MC(seed.) + GA(rete.) | block transition | general | ✓ | ◐ | |
2007 | RANDOOP [141] | GA(rete.) | legality | object-oriented | ✓ | ● | |
2013 | FuzzSim [192] | WCCP(seed.) | #bugs | general | ✓ | ● | |
2014 | COVERSET [158] | MSCP(set.) | code coverage | general | ✓ | ◐ | |
ILP(seed.) | #bugs | ✓ | ●+◐+○ | ||||
2015 | Ruiter and Poll [55] | GA(rete.) | state machine | protocol | ✓ | ● | |
2016 | AFLFast [23] | MC(seed.) + GA(rete.) | path transition | general | ✓ | ◐ | |
2016 | classfuzz [42] | MH(mutation.) + GA(rete.) | code coverage | JVM | ✓ | ◐ | |
2017 | VUzzer [157] | MC(seed.) + GA(rete.) | block transition | general | ✓ | ◐ | |
2017 | AFLGo [22] | SA(seed.) + GA(rete.) | path transition | general | ✓ | ◐ | |
2017 | NEZHA [151] | GA(rete.) | asymmetry | semantic bugs | ✓ | ●+◐ | |
2017 | DeepXplore [148] | GA(rete.) | neuron coverage | deep learning | ✓ | ◐ | |
2018 | STADS [17] | Species(seed.) | state discovery | general | ✓ | ◐ | |
2018 | CollAFL [66] | GA(rete.) | code coverage | general | ✓ | ◐ | |
2018 | Angora [37] | GD(byte.) + GA(rete.) | code coverage | general | ✓ | ◐ | |
2019 | DigFuzz [210] | MC(seed.) + GA(rete.) | block transition | general | ✓ | ○ | |
2019 | MOPT [116] | PSO(mutation.) + GA(rete.) | code coverage | general | ✓ | ◐ | |
2019 | NEUZZ [172] | NN(byte.) + GA(rete.) | branch behavior | general | ✓ | ◐ | |
2019 | Cerebro [105] | MOO(seed.) + GA(rete.) | code coverage | general | ✓ | ◐ | |
2019 | DifFuzz [138] | GA(rete.) | asymmetry | side-channel | ✓ | ● | |
2020 | AFLNET [154] | GA(rete.) | state machine | protocol | ✓ | ◐ | |
2020 | EcoFuzz [203] | VAMAB(seed.) + GA(rete.) | path transition | general | ✓ | ◐ | |
2020 | Entropic [21] | Shannon(seed.) + GA(rete.) | state discovery | general | ✓ | ◐ | |
2020 | MTFuzz [171] | MTNN(byte.) + GA(rete.) | branch behavior | general | ✓ | ◐ | |
2020 | Ankou [118] | GA(rete.) | code coverage | general | ✓ | ◐ | |
2020 | FIFUZZ [87] | GA(rete.) | code coverage | error-handling | ✓ | ◐ | |
2020 | IJON [6] | GA(rete.) | code coverage | general | ✓ | ◐ | |
2020 | Krace [194] | GA(rete.) | alias coverage | data race | ✓ | ◐ | |
2021 | AFL-HIER [88] | UCB1(seed.) + GA(rete.) | path transition | general | ✓ | ◐ | |
2021 | PGFUZZ [82] | GA(rete.) | safety policy | robotic vehicle | ✓ | ● | |
2021 | Aafer et al. [1] | GA(rete.) | validation log | SmartTV | ✓ | ● | |
2021 | AFLChurn [214] | SA(seed.) + ACO(byte.) + GA(rete.) | path transition + commit history | general | ✓ | ◐ | |
اختصارات جدول:
MC: زنجیره مارکوف (Markov Chain)
MSCP: مسئله حداقل پوشش مجموعه (Minimal Set Cover Problem)
ILP: مسئله برنامهریزی عدد صحیح (Integer Linear Programming Problem)
WCCP: مسئله جمعآوری کوپن وزندار (Weighted Coupon Collector’s Problem)
VAMAB: نوعی از باندیت چنددستهای خصمانه (Variant of Adversarial Multi-Armed Bandit)
UCB1: کران اطمینان بالا، نسخه اول (Upper Confidence Bound, version one)
MH: Metropolis-Hastings
PSO: بهینهسازی ازدحام ذرات (Particle Swarm Optimization)
Shannon: آنتروپی شانون (Shannon’s entropy)
Species: مدلهای کشف گونهها (Models of Species Discovery)
ACO: بهینهسازی کلونی مورچگان (Ant Colony Optimization)
SA: آنیلینگ شبیهسازی شده (Simulated Annealing)
NN: شبکه عصبی (Neural Network)
MTNN: شبکههای عصبی چندوظیفهای (Multi-task Neural Networks)
GA: الگوریتم ژنتیک (Genetic Algorithm)
GD: گرادیان کاهشی (Gradient Descent)
MOO: بهینهسازی چندهدفه (Multi-objective Optimization)
R: تصادفی (Random)
set: انتخاب مجموعه بذر (Seed Set Selection)
seed: زمانبندی بذر (Seed Schedule)
byte: زمانبندی بایت (Byte Schedule)
mutation.: زمانبندی جهش (Mutation Schedule)
rete: نگهداشت بذر (Seed Retention)
○: فازینگ جعبه سفید (Whitebox Fuzzing)
◐: فازینگ جعبه خاکستری (Greybox Fuzzing)
●: فازینگ جعبه سیاه (Blackbox Fuzzing)
دلتا: پوشش کد حساستر
*: در این مقاله، انرژی (energy) مستقیماً بر اساس مدل تخصیص داده نمیشود، اما در واقع مدل قابلیت تخصیص انرژی را دارد.
WCCP تخمین میزند که قبل از رسیدن یک باگ جدید به فرآیند، چقدر زمان لازم است، که مشابه مسئله خریدهای مورد انتظار قبل از دریافت کوپن جدید توسط مصرفکننده است [192]. هر باگ منحصر به فرد به دست آمده توسط فازینگ، نوعی کوپن است و WCCP قصد دارد تعداد خریدها (بودجه زمانی) مورد نیاز برای رسیدن کوپنهای جدید (باگهای منحصر به فرد) را پیشبینی کند. برای پیشبینی زمان رسیدن باگ، WCCP به توزیع همه باگها نیاز دارد که با مشاهده باگهای کشف شده تخمین زده میشود. بر اساس توزیع، فازینگ به تدریج حداقل زمان، که توسط WCCP پیشبینی میشود، را برای شناسایی باگهای جدید به بذرها (Seed) اختصاص میدهد. هم ILP و هم WCCP قصد دارند بودجه زمانی بیشتری را به بذرهایی اختصاص دهند که پتانسیل بیشتری برای شناسایی باگها دارند.
3.2.2 معیار ارزیابی کیفیت با انتقال وضعیت (زنجیره مارکوف)- (Fitness by State Transition – Markov Chain)
از آنجا که باگها در برنامههای تحت آزمون (PUTs) پراکنده هستند، فرآیند بهینهسازی هنگام استفاده از تعداد باگها به عنوان معیار شایستگی و ارزیابی کیفیت، بهسرعت به بهینههای محلی همگرا میشود. در نتیجه، فازینگ بر روی نواحیای از کد تمرکز میکند که به باگهای کشف شده مرتبط هستند. این موضوع ممکن است فرصتهای لازم برای بررسی پوشش کد بیشتر را از بین ببرد. در چنین شرایطی، باگهای عمیق که توسط شرایط پیچیده محافظت میشوند، میتوانند از دید فازینگ پنهان بمانند.
برای کاهش این مشکل، فازرها شایستگی را بر اساس وضعیتهای اجرایی (مانند پوشش کد) محاسبه میکنند، زیرا وضعیتهای اجرایی اطلاعات بیشتری در اختیار فازینگ قرار میدهند. اغلب فازرهای موجود، شایستگی را بر اساس پوشش کد محاسبه میکنند؛ یعنی هدف آنها کشف پوشش کد بیشتر است [21, 23, 62, 88, 157, 203]. دلیل دیگر استفاده از پوشش کد این است که پوشش بیشتر کد نشاندهنده احتمال بالاتر کشف باگ است [130].
همانطور که در شکل ۲ نشان داده شده است، اگر فازینگ بتواند گذارهای حالت (state transitions) را به درستی مدلسازی کند، میتواند بهطور مؤثر آن را برای کشف حالتهای ناشناخته هدایت کند. یکی از نظریههای رایج برای مدلسازی گذار حالت، زنجیره مارکوف (Markov chain) است [93] که یک فرایند تصادفی است و از یک حالت به حالت دیگر منتقل میشود. بهطور خلاصه، زنجیره مارکوف یک جدول احتمالاتی نگه میدارد که در آن هر عنصر pᵢⱼ احتمال گذار از حالت i به حالت j را نشان میدهد.
برای مدلسازی فازینگ، یکی از راهحلها این است که یک بلوک پایه (basic block) در گراف جریان کنترل (CFG) بهعنوان یک حالت تعریف شود و گذار حالت نیز بهصورت پرش از یک بلوک پایه به بلوک دیگر در نظر گرفته شود. از آنجا که احتمالهای گذار بین بلوکها بدون اجرای برنامه قابل دستیابی نیست، فازرها این احتمالات را با ثبت فراوانی گذار بین بلوکها در طول فرایند فازینگ محاسبه میکنند [62, 157, 210].
برای مثال، اگر یک یال AB تعداد ۳۰ مرتبه بررسی شده باشد در حالی که یال همسایه آن AC، هفتاد بار بررسی شده باشد، احتمال انتقال یالهای AB و AC به ترتیب 0.3 و 0.7 است (شکل 3 (الف)). احتمالات انتقال در یک مسیر ABDEG را میتوان به همین روش بدست آورد. فرض کنید احتمالات برای یالهای AB، BD، DE و EG به ترتیب 0.3، 0.25، 0.6 و 0.8 باشد. سپس، شایستگی (معیار ارزیابی کیفیت) یک بذر که مسیر ABDEG را آزمایش میکند را میتوان به صورت 0.3 × 0.25 × 0.6 × 0.8 = 0.036 محاسبه کرد. در ابتدای فازینگ، احتمالات انتقال را میتوان با روش مونت کارلو [125] بدست آورد که بلوکهای پایه را به صورت تصادفی بررسی میکند. با شایستگی محاسبه شده بر اساس زنجیره مارکوف، فازرها میتوانند محاسبه تخصیص انرژی را هدایت کنند [62، 157] یا سختترین مسیر (کمترین احتمال انتقال) را برای حل با اجرای کانکولیک انتخاب کنند [210]. اساساً، هرچه احتمال انتقال کمتر باشد، شایستگی آن بالاتر است. انگیزه این است که نواحی کد با دسترسی دشوار (احتمال انتقال کم) به انرژی بیشتری برای فاز کردن نیاز دارند زیرا نواحی با دسترسی آسان را میتوان به راحتی به خوبی کاوش کرد.
فازینگ مبتنی بر جهش، ورودیهای جدیدی را با جهش بذرها تولید میکند و هر ورودی یک مسیر اجرا را اعمال میکند. این امر دیدگاه دیگری را برای مدلسازی یک فرآیند فازینگ بر اساس زنجیره مارکوف فراهم میکند. به طور خاص، حالت به عنوان یک مسیر اجرا که توسط یک ورودی اعمال میشود تعریف میشود. در عین حال، انتقال حالت، جهش یک ورودی ti است که یک ورودی جدید tj تولید میکند. به همین ترتیب، انتقال حالت نیز انتقال از یک مسیر i است که توسط ورودی ti اعمال میشود، به مسیر دیگری j که توسط ورودی tj اعمال میشود. مشابه انتقالهای بلوکی، احتمالات انتقال مسیر بر اساس اجراهای قبلی در طول فازینگ محاسبه میشوند. همانطور که توسط AFLFast [23] استنباط شده است، حداقل انرژی مورد نیاز برای یک حالت i برای کشف یک حالت جدید j، /pij1 است، که در آن pij احتمال انتقال است. بنابراین، AFLFast انرژی بیشتری را به مسیرهای با تکرار کمتر اختصاص میدهد.
فازینگ مبتنی بر جهش با تغییر دادن بذرها (seed) ورودیهای جدید تولید میکند و هر ورودی یک مسیر اجرایی را طی میکند. این موضوع یک دیدگاه دیگر برای مدلسازی فرایند فازینگ بر اساس زنجیره مارکوف (Markov chain) فراهم میکند. بهطور مشخص، در این مدل وضعیت (state) بهصورت یک مسیر اجرایی تعریف میشود که توسط یک ورودی طی شده است. در همین حال، انتقال وضعیت (state transition) همان جهش یک ورودی (ti) است که ورودی جدید (tj) را تولید میکند.
در نتیجه، این انتقال حالت در واقع به معنای انتقال از مسیر (i) (که توسط (tj) طی شده) به مسیر (j) (که توسط (tj) طی شده) است. مشابه انتقال بین بلاکها، احتمالهای انتقال بین مسیرها نیز بر اساس اجراهای قبلی در طول فازینگ محاسبه میشوند. طبق نتیجهگیری AFLFast [23]، حداقل انرژی لازم برای یک حالت (i) جهت کشف یک حالت جدید (j)، برابر است با (1/pij)، که در آن (pij) احتمال انتقال است. بنابراین، AFLFast انرژی بیشتری به مسیرهای کمتکرار اختصاص میدهد؛ یعنی مسیرهایی که احتمال انتقال پایینی دارند. گونههای مختلفی از این مدل در فازینگ خاکستری هدایتشده (Directed Greybox Fuzzing – DGF) [22, 217] و فازینگ خاکستری رگرسیونی (Regression Greybox Fuzzing – RGF) [214] نیز بررسی شدهاند.
3.2.3 شایستگی مبتنی بر گذار حالت – باندیت چند اهرمی (Fitness by State Transition (Multi-armed Bandit))
اگرچه زنجیره مارکوف در مدلسازی گذار حالتها به موفقیت بزرگی دست یافته است، اما برای مدلسازی برنامه اولیه فازینگ به اندازه کافی عمیق نیست. زنجیره مارکوف به احتمالات انتقال بین همه حالتها نیاز دارد تا فازینگ تصمیم مناسبی بگیرد. با این حال، معمولاً بسیاری از حالتها در طول فازینگ بررسی نشدهاند، که نشان میدهد تصمیمات مبتنی بر زنجیره مارکوف بهینه نیستند. برای انتقال بلوکها، یک راه حل استفاده از قانون سه در آمار برای انتقال از یک بلوک کشف شده به یک بلوک کشف نشده است [210]. برای انتقال مسیر، یک راه حل ساده برای به دست آوردن همه احتمالات انتقال، برنامه Round-Robin [156] است که بودجه زمانی را بین بذرها (Seed) به طور مساوی تقسیم میکند [158]. با این حال، این راه حل نمیتواند زمان تغییر از Round-Robin به زنجیره مارکوف را تعیین کند. تعادل بین پیمایش همه بذرها و تمرکز بر یک بذر خاص، یک مسئله کلاسیک “اکتشاف در مقابل بهرهبرداری” است. یک راه حل بهتر برای حل مسئله «اکتشاف در مقابل بهرهبرداری» فرموله کردن انتقال مسیر به عنوان یک مسئله باندیت چند اهرمی (MAB – Multi-armed Bandit) است [14].
برای یک مسئله باندیت چند اهرمی، یک بازیکن قصد دارد با مشاهده پاداشهای حاصل از انجام برخی آزمایشها روی اهرمهای یک دستگاه اسلات، کل پاداشها را به حداکثر برساند. اکتشاف فرآیندی است که در آن بازیکن تمام اهرمها را برای به دست آوردن انتظارات پاداش خود بازی میکند. هنگامی که انتظارات پاداش همه اهرمها مشخص باشد، بهرهبرداری فرآیندی است که در آن بازیکن فقط اهرمهایی را انتخاب میکند که بالاترین انتظارات پاداش را دارند. به منظور فرموله کردن انتقال مسیر، یک ti اولیه به عنوان یک اهرم تعریف میشود. در همین حال، پاداش، کشف یک مسیر جدید است که توسط یک ورودی اعمال میشود، که از ti اولیه تولید میشود.
با توجه به اینکه تعداد کل بذرها در طول فازینگ در حال افزایش و انتظار پاداش یک بذر در طول فازینگ در حال کاهش است، [203] EcoFuzz مدل باندیت چند اهرمی متخاصم (VAMAB[13]) را برای حل این مشکل پیشنهاد میدهد. به طور خاص، EcoFuzz به طور تطبیقی انرژی را برای بذرهای فاز نشده، یعنی فرآیند اکتشاف، اختصاص میدهد. با پاداش همه بذرها، EcoFuzz انتظار یک بذر ti را به صورت (pii /√i-1) تخمین میزند، که در آن pii احتمال خود-انتقالی است (یعنی جهش بذر ti منجر به اعمال همان مسیر i میشود). منطق این است که احتمال خود-انتقالی پایین نشان میدهد که جهشهای بذر میتوانند مسیرهای دیگر (مسیرهای جدید) را با احتمال بالا کشف کنند. بنابراین، EcoFuzz بذرهایی با احتمال خود-انتقالی پایین را ترجیح میدهد. به طور مشابه، AFL-HIER [88 نیز انتقال مسیرها را به عنوان یک مسئله MAB فرموله میکند. در حالی که EcoFuzz از معیارهای واحد (یعنی پوشش لبه) برای حفظ بذرهای جدید استفاده میکند، AFL-HIER پیشنهاد میکند از معیارهای پوشش چند سطحی، مانند توابع، لبهها و بلوکهای پایه، برای اضافه کردن بذرهای جدید استفاده شود. AFL-HIER از UCB1 [9]، یکی از الگوریتمهای MAB، برای حل مسئله MAB با معیارهای پوشش چند سطحی استفاده میکند.
3.2.4 معیار ارزیابی کیفیت با کشف وضعیت (Fitness by State Discovery)
هم زنجیره مارکوف و هم MAB انتقال حالت برنامهها را فرموله میکنند. با این حال، هدف اصلی فازینگ کشف وضعیتهای جدید، به عنوان مثال، پوشش کد جدید، خرابیهای جدید یا اشکالات جدید است. این امر بوهم و همکاران [17، 20، 21] را بر آن داشت تا فرآیندهای فازینگ را به عنوان یک مسئله کشف گونه فرموله کنند [32، 33، 52]. به طور خلاصه، بومشناسان نمونههای متعددی را از طبیعت جمعآوری میکنند و گونههای موجود در نمونهها ممکن است فراوان یا نادر باشند. بومشناسان ویژگیهای یک مجموعه کامل، از جمله گونههای کشف نشده، را بر اساس نمونهها برونیابی میکنند. به طور مشابه، ورودیهای تولید شده توسط فازرها نمونههای جمعآوری شده هستند و فضای ورودی یک برنامه، مجموعه است.
فازینگ ورودیها را بر اساس معیارهای خاص به گونههای مختلف دستهبندی میکند. به عنوان مثال، یک مسیر اجرا میتواند یک گونه باشد و تمام ورودیهایی که مسیر را اعمال میکنند متعلق به این گونه هستند. در این مورد، یک گونه نادر، یک مسیر اجرایی است که چند ورودی آن را اعمال میکنند. یک فرضیه مهم در کشف گونهها این است که ویژگیهای گونههای کشف نشده تقریباً فقط با گونههای نادر کشف شده قابل توضیح است [31]. این فرضیه نشان میدهد که فازینگ میتواند انرژی بیشتری را به گونههای نادر (مثلاً مسیرهای نادر) برای کشف حالتهای جدید اختصاص دهد. بر اساس مسئله کشف گونهها، انتروپیک [21] فازینگ را به عنوان یک فرآیند یادگیری درک میکند؛ یعنی یک فازر به تدریج اطلاعات بیشتری در مورد رفتارهای برنامه (گونهها) یاد میگیرد.
آنتروپیک (روش فازینگ مبتنی بر آنتروپی) پیشنهاد میکند از آنتروپی شانون [170] برای اندازهگیری کارایی کشف گونهها استفاده شود. آنتروپی اصلی شانون H میانگین اطلاعات گونهها را اندازهگیری میکند و به صورت H = – ∑i pilog(pi) محاسبه میشود، که در آن pi احتمال انتخاب گونه Si است. اگر نمونههای جمعآوریشده شامل گونههای زیادی باشند، آنتروپی H بزرگ (اطلاعات بیشتر) است؛ در غیر این صورت، اگر نمونههای جمعآوریشده شامل گونههای کمی باشند، آنتروپی H کوچک (اطلاعات کمتر) است. در همین حال، انتروپیک استدلال میکند که نرخ کشف گونهها، کارایی فرآیندهای فازینگ را کمّی میکند. با استنباط از نظریه شانون، آنتروپیک کارایی کشف گونهها را برای یک بذر (Seed) اندازهگیری میکند. به طور خاص، pt i احتمال جهش یک بذر t و تولید ورودی متعلق به گونه Si است. نرخ یادگیری بذر t بر اساس احتمال pti و یک تخمینگر آنتروپی بهبود یافته محاسبه میشود. آنتروپیک نتیجه میگیرد که انرژی بیشتری به بذرهایی با نرخ یادگیری بزرگتر اختصاص داده میشود؛ یعنی به بذرهایی که گونههای جدید را با کارایی بیشتری کشف میکنند، انرژی بیشتری اختصاص داده میشود.
۳.۳ زمانبندی بایت (Byte Schedule)
زمانبندی بایت، فرکانس انتخاب یک بایت در یک بذر (Seed) برای جهش را تعیین میکند. اکثر فازرها بایتها را به صورت اکتشافی بر اساس اطلاعات اجرایی [7، 37، 38، 67، 101، 103، 157، 160، 187] یا به صورت تصادفی [22، 23، 118، 203، 206] انتخاب میکنند. زمانبندی بایت نیاز به درک پیچیدهتری از رفتارهای برنامه، مانند محدودیتهای مسیر یا جریان داده، نسبت به زمانبندی بذر دارد. بنابراین، فازرها بر روی یک مسئله سادهتر به نام اهمیت بایتها تمرکز میکنند که نشان میدهد چگونه بایتها بر فرآیندهای فازینگ تأثیر میگذارند. از آنجا که اکثر فازرهای جعبه خاکستری از پوشش لبه برای آزمایش PUTها استفاده میکنند، اولین رویکرد، تعریف اهمیت به عنوان چگونگی تأثیر بایتها بر رفتارهای شاخهها است.
NEUZZ [172] و MTFuzz [171] روابط بین بایتهای ورودی و رفتارهای شاخهها را بر اساس مدلهای یادگیری عمیق ([14]DL) مدلسازی میکنند. گرادیانهای مدلهای DL اهمیت بایتها را کمّی میکنند، زیرا گرادیان بزرگ یک بایت نشان میدهد که یک اختلال کوچک در بایت منجر به تفاوت قابل توجهی در رفتار شاخهها میشود. برای جهشهای بعدی، فازینگ بایتهای با اهمیت بالاتر را برای جهش در اولویت قرار میدهد.
یک رویکرد دیگر برای کمّیسازی اهمیت بایتها این است که آن را بر اساس معیار ارزیابی کیفیت بذرها (seed) تعریف کنیم. همانطور که در بخش 3.2 تحلیل شده، معیار ارزیابی کیفیت (fitness) یک بذر نشاندهنده کیفیت آن است. بنابراین، فازینگ میتواند روی بایتهایی تمرکز کند که کیفیت را بهبود میدهند.
AFLChurn [214] از الگوریتم بهینهسازی کلونی مورچگان (Ant Colony Optimization – ACO) [60] استفاده میکند تا یاد بگیرد بایتها چگونه بر معیار ارزیابی کیفیت تأثیر میگذارند. مشابه فرآیند جستجوی غذا توسط کلونی مورچگان:
- اگر تغییر یک بایت باعث بهبود fitness یک بذر (seed) شود، فازینگ امتیاز آن بایت را افزایش میدهد.
- با ادامه فازینگ، امتیاز همه بایتها بهمرور کاهش مییابد، که معادل تبخیر فرومون در ACO است.
در نتیجه، فازینگ ترجیح میدهد بایتهایی را انتخاب کند که امتیاز بالاتری دارند.
3.4 برنامه عملگر جهش (Mutation Operator Schedule)
همانطور که در شکل 2 نشان داده شده است، مرحله نهایی مولد ورودی، انتخاب یک عملگر جهش (جهشدهنده) برای جهش بایت(های) انتخاب شده است. برنامه جهش تصمیم میگیرد که کدام جهشدهنده برای جهش بعدی بایتها انتخاب شود. انگیزه برنامه جهش بر اساس مشاهده تغییر کارایی جهشدهندهها است [42، 116]. Classfuzz [42] استدلال میکند که جهشدهندههایی که حالتهای جدید بیشتری را بررسی کردهاند، احتمال انتخاب بالاتری دارند. بنابراین، classfuzz فرض میکند که زنجیره مارکوف مونت کارلو (MCMC) میتواند فرآیند برنامه جهش را مدلسازی کند. Classfuzz از الگوریتم Metropolis-Hastings [45]، یکی از روشهای MCMC، برای حل مسئله برنامه جهش استفاده میکند. به طور خاص، هر جهشدهنده دارای نرخ موفقیتی است که حالتهای جدید بررسی شده توسط جهش دهنده را کمّی میکند. Classfuzz ابتدا به طور تصادفی جهشدهنده بعدی را انتخاب میکند و سپس بر اساس نرخ موفقیت جهشدهندههای فعلی و جهش یافتههای انتخاب شده، انتخاب را میپذیرد یا رد میکند.
MOPT [116] از بهینهسازی ازدحام ذرات ([15]PSO) [94] برای مدلسازی فرآیند انتخاب جهش استفاده میکند. PSO از چندین ذره استفاده میکند و به تدریج آنها را به سمت بهترین موقعیتهایشان حرکت میدهد. در مورد مسئلهی زمانبندی جهش، یک جهش دهنده یک ذره است و موقعیت، احتمال انتخاب جهشدهنده است. یک ذره بهترین موقعیت خود را زمانی پیدا میکند که ذره بیشترین تعداد حالتهای جدید را در یک موقعیت در میان سایر موقعیتها ایجاد کند. بنابراین، تمام ذرات (جهش دهندهها) به صورت مجانبی بهترین موقعیتهای خود (احتمالات) را پیدا میکنند که توزیع احتمال برای انتخاب جهش دهندهها را میسازد. کمپینهای فازینگ بعدی، جهشدهندهها را بر اساس توزیع احتمال انتخاب میکنند.
۳.۵ اطلاعات متنوع برای ارزیابی کیفیت (Diverse Information for Fitness)
علاوه بر زمانبندی بذرها (seed)، بایتها یا عملگرهای جهش، از شایستگی یا معیار ارزیابی کیفیت (fitness) میتوان برای هدایت نگهداری بذرها (seed retention) نیز استفاده کرد. فازرها معمولاً از الگوریتم ژنتیک (GA) برای مدلسازی فرایند نگهداری بذر استفاده میکنند.
بهطور مشخص، یک فازر با جهش دادن یک بذر، ورودی جدیدی تولید میکند؛ اگر این ورودی حالتهای اجرایی جدیدی را کشف کند (یعنی شایستگی یا معیار ارزیابی کیفیت (fitness) بهتری داشته باشد)، به عنوان یک بذر جدید نگه داشته میشود. هنگام انتخاب بذر برای دور بعدی آزمایش (بر اساس زمانبندی بذر)، ممکن است همین بذر جدید انتخاب شود.
بیشتر فازرهای مبتنی بر پوشش بذرها [7, 23, 116, 177, 204, 206] را بر اساس پوشش یالها (edge coverage) نگه میدارند. برای بهبود توانایی کشف نقصها، نیاز به پوشش کدی حساستر است تا اطلاعات بیشتری از حالتهای اجرایی آشکار شود.
از سوی دیگر، انواع جدیدی از معیارهای ارزیابی کیفیت کیفیت (fitness) برای سناریوهای خاص طراحی شدهاند، مانند مدلهای یادگیری عمیق [148] یا وسایل نقلیه رباتیک [82]. نکته مهم این است که تنوع اطلاعات نه تنها در نگهداری بذرها، بلکه در مسائل زمانبندی که پیشتر مطرح شد نیز مورد استفاده قرار میگیرد.
۳.۵.۱ پوشش کد حساس (Sensitive Code Coverage)
حساسیت معیار شایستگی یا ارزیابی کیفیت (fitness) نشان دهنده توانایی آن در تمایز بین حالتهای اجرایی مختلف است. بسیاری از فازرهای مبتنی بر پوشش [7, 23, 116, 177, 204, 206] از یک bitmap استفاده میکنند تا اطلاعات مربوط به پوشش یالها (edge coverage) را در اختیار فازینگ قرار دهند.
در اصل، bitmap یک بردار فشرده است که در آن اندیس هر عنصر نشان دهنده یک شناسه یال است. برای این منظور، مقدار هش بهصورت (hash(bi, bj)) برای شناسه یالها محاسبه میشود، که در آن (bi) و (bj) شناسه بلاکهایی هستند که در زمان ابزارگذاری (instrumentation) به صورت تصادفی اختصاص داده شدهاند.
اگرچه این پیادهسازی در زمان اجرا سریع است، اما دقت پوشش یال را کاهش میدهد. به طور مشخص، این روش با مشکل برخورد یالها (edge collision) مواجه است؛ یعنی دو یال متفاوت ممکن است یک شناسه یکسان بگیرند [66, 216]. همانطور که در شکل (a)3 نشان داده شده است، اگر شناسههای لبه idAB = idAC و idBD = idCD باشند، آنگاه مسیرهای ABD و ACD یکسان در نظر گرفته میشوند.
در نتیجه، چون فازینگ در این حالت پوشش جدیدی کشف نمیکند، مسیر دارای باگ ACDEG را نادیده میگیرد. بنابراین، برای اختصاص شناسههای یال یکتا، فازینگ باید شناسههای بلاک را با دقت بیشتری تعیین کند و از توابع هش دقیقتری استفاده نماید [66].
با استفاده از bitmap، فازینگ میتواند تشخیص دهد که آیا یک ورودی یالهای جدیدی را اجرا میکند یا نه و در صورت وجود، آن ورودی را به عنوان یک بذر جدید نگه دارد. به طور مشخص، فازرها یک bitmap کلی نگه میدارند که اتحاد (union) bitmapهای اجرایهای فردی است. هنگام تعیین یالهای جدید، فازینگ یک bitmap فردی را با bitmap کلی مقایسه میکند تا ببیند آیا یالهای جدیدی در اجرای فردی وجود دارد یا خیر.
با این حال، اتحاد bitmapها باعث از دست رفتن اطلاعات اجرایی میشود [118]. برای مثال، اگر مسیرهای ABDEG و ACDFG در شکل ۳(a) قبلاً اجرا شده باشند، ورودی که مسیر جدید ACDEG را اجرا میکند، بهعنوان بذر نگه داشته نخواهد شد، زیرا تمام یالها قبلاً در bitmap کلی وجود دارند.
بنابراین، یک راهکار پیشنهادی ترکیب bitmapهای فردی است [118]. با این حال، ترکیب bitmapها میتواند منجر به ایجاد تعداد بسیار زیادی بذر شود، و چالش اصلی این است که بین کارایی فازینگ و حساسیت پوشش یالها تعادل برقرار شود.
یکی از راهکارهای ممکن برای کاهش بعد دادهها، استفاده از تحلیل مولفههای اصلی پویا (dynamic Principal Component Analysis, PCA) است [191, 118]. راهکارهای دیگر برای افزایش حساسیت پوشش یالها شامل:
- Path hash [198]
- Calling context [37, 87, 171]
- Multilevel coverage [88]
- Code complexity [105]
این روشها اطلاعات اضافی را به پوشش یالها اضافه میکنند تا حساسیت آن افزایش یابد. بهبود bitmap بر جستجوی پوشش بیشتر کد تمرکز دارد. با این حال، چنین بهبودی ممکن است در بررسی حالتهای اجرای پیچیده شکست بخورد. به عنوان مثال، شکل (b)3 قطعه کد یک هزارتو است که در آن جفت (a، b) موقعیت در هزارتو را نشان میدهد. برای فعال کردن ()bug، جفت (a، b) باید جفتی با مقادیر خاص باشد. با این حال، قطعه سوئیچ فقط چهار لبه دارد و میتواند به سرعت بررسی شود. پس از آن، فازینگ هیچ راهنمایی برای رسیدن به محل اشکال ندارد. بنابراین، یک راه حل موثر، معرفی رویکرد انسان در حلقه برای راهنمایی بررسی حالتهای اجرای پیچیده است [6]. در مثال شکل (b)3، یک تحلیلگر میتواند یک حاشیه نویسی در کد اضافه کند تا فازینگ مقادیر مختلف جفت (a، b) را بررسی کند. علاوه بر این، مقدار یک شرط مقایسه حساستر از نتایج دودویی است، یعنی “بررسی شده” یا “بررسی نشده” [37، 38، 65، 98، 137]. برای مثال، اگر مقدار (x[3] – 0x44) در شکل (a)3 مشخص باشد، یک فازر میتواند بذرهایی را انتخاب کند که احتمال بیشتری دارد شرط (x[3] == 0x44) را برآورده کنند.
3.5.2 معیارهای شایستگی یا ارزیابی کیفیت متنوع (Diverse Fitness)
شایستگی (fitness) محدود به پوشش کد نیست. در واقع، پوشش کد همیشه عملی نبوده و یا بهترین بازخورد برای کمپینهای فازینگ محسوب نمیشود. بنابراین، پژوهشگران از انواع مختلف بازخورد برای کاربردها یا نقصهای متفاوت استفاده میکنند. اگر پوشش کد در دسترس نباشد، یک راه حل بدیهی این است که بذرها بر اساس خروجیهای اجرای برنامه نگه داشته شوند؛ مانند قانونی بودن نتایج اجرا [141] یا وضعیت ماشین حالت در پیادهسازیهای پروتکل [154].
از آنجا که فازینگ میتواند برای کشف نقصهای انواع مختلفی از برنامهها به کار رود، انواع متفاوتی از معیار شایستگی برای کاربردهای خاص [1, 82, 148] یا انواع خاصی از نقصها [194] طراحی شدهاند. در ادامه، انواع گوناگون معیارهای شایستگی بصورت خلاصه بیان شده است.
- قانونمندی نتیجهٔ اجرا (Legality of execution result). یک برنامهٔ شیءگرا (مانند Java) از یک دنباله از فراخوانیهای متد تشکیل شده است و نتیجهٔ اجرا یا معتبر (قانونی) است یا منجر به ایجاد استثناء میشود. فازینگ دنبالههای جدیدی از فراخوانیهای متد تولید و بهدست میآورد که میتوانند حالتهای جدید و معتبر بیشتری از اشیاء را کاوش کنند [141].
- ماشین حالتِ پیادهسازیهای پروتکل (State machine of protocol implementations). یک ماشین حالت از حالتها و ورودیهایی تشکیل شده است که این حالتها را تغییر میدهند [161]. بهدلیل پیچیدگی پروتکلها، فازرها معمولاً ماشین حالت را بهتدریج و با افزودن حالتهای جدید به آن استنتاج میکنند [55, 61, 64, 69, 154]. این ماشین حالت از یک بذر (یعنی یک ماشین حالت اولیه) آغاز میشود و فازرها حالتهای فعلی ماشین حالت را جهش میدهند تا حالتهای جدید را کشف کنند. آسیبپذیریها بر اساس این ماشین حالت تحلیل میشوند، با هدف جستوجوی گذارهای آسیبپذیر [55].
- سیاست ایمنی وسایل نقلیه رباتیک (Safety policy of robotic vehicles): سیاستهای ایمنی، الزامات ایمنی فیزیکی یا عملکردی یک وسیله نقلیه رباتیک را تعیین میکنند، مانند حداکثر دمای موتور [82]. زمانی که یک ورودی به نقض این سیاستها نزدیکتر باشد، آن ورودی برای تغییرات و جهشهای بعدی (later mutation) نگه داشته میشود.
- شایستگی یا معیار ارزیابی کیفیت برای سیستمهای یادگیری عمیق (Fitness for deep learning systems): هدف فازینگ در سیستمهای یادگیری عمیق، افزایش مقاومت و قابلیت اطمینان آنها است [68, 115, 148]. برای این منظور، فازرها انواع مختلفی از معیارهای ارزیابی کیفیت را طراحی میکنند، مانند پوشش نورونها (neuron coverage) برای کشف موارد مرزی [148]، تابع خطا (loss function) برای افزایش دادههای آموزشی [68]، یا پوشش در سطح عملگر (operator-level coverage) برای بررسی موتورهای استنتاج یادگیری عمیق (یعنی چارچوبها و کتابخانهها) [115].
- گزارش اعتبارسنجی Android SmartTVs (Validation log of Android SmartTVs): این گزارشها شامل پیامهای اجرای Android SmartTV هستند [1]. گزارشهای اعتبارسنجی برای استنتاج ورودیهای معتبر و استخراج مرزهای ورودی استفاده میشوند. ورودیهای معتبر بذرهای مؤثری برای فازینگ فراهم میکنند و مرزهای ورودی، فضای جستجوی ورودیها را کاهش میدهند.
- عدم تقارن رفتاری در آزمون تفاضلی (differential testing). در آزمون تفاضلی، باگها از طریق مشاهدهٔ اختلاف رفتار بین پیادهسازیهای مختلفی که یک کارکرد یکسان دارند و روی یک ورودی مشترک اجرا میشوند، کشف میگردند. این عدم تقارنهای رفتاری نشان میدهند که تا چه حد پیادهسازیهای مختلف با یکدیگر ناسازگار یا متفاوت هستند. فازینگ تلاش میکند موارد آزمونی تولید کند که بتوانند تعداد بیشتری از این اختلافها را آشکار کنند [138, 151].
- پوشش همارجاعی برای تشخیص رقابت داده (Alias coverage for data race): پوشش هم ارجاعی برای شناسایی دادههای رقابتی (data race) در سیستم فایلهای کرنل طراحی شده است [194]. دادههای رقابتی یک باگ همزمان است که در آن دو thread بدون همگامسازی مناسب به یک مکان حافظه مشترک دسترسی دارند. بنابراین، پوشش هم ارجاعی جفتهای دسترسی به حافظه که ممکن است همپوشانی داشته باشند را دنبال میکند.
- مکانهای خطرناک برای باگها (Dangerous locations for bugs): مکانهای خطرناک بخشهای کدی هستند که احتمال وقوع باگ در آنها بالاتر است. فازرها میتوانند منابع خود را به سمت این مکانها هدایت کنند تا اثربخشی و کارایی فازینگ افزایش یابد. برای باگهای همزمان، مکانهای خطرناک معمولاً بخشهای کدی هستند که منجر به نقض اتمیکیتی [97]، دادههای رقابتی [84, 167] یا همپوشانیهای مشکوک [35] میشوند. برای باگهای غیرهمزمان، مکانهای خطرناک میتوانند از طریق آزمون پچ [122]، بازتولید کرش [155]، گزارش تحلیل استاتیک [48]، یا شناسایی جریان اطلاعات [123] شناسایی شوند. علاوه بر این، مکانهای خطرناک ممکن است شامل دسترسیهای حافظه [84, 182, 188]، بررسیهای سنی تایزر (sanitizer) [40, 140]، یا تاریخچهٔ کامیتها (commit history) [214] نیز باشند.
3.6 نظریه ارزیابی (Evaluation Theory)
ارزیابی فازینگ معمولاً به صورت جداگانه از مرحلهی کشف باگ انجام میشود. با این حال، ما ارزیابی را بخشی از فرآیند فازینگ میدانیم، زیرا ارزیابی مناسب میتواند به بهبود عملکرد فازینگ کمک کند [215]. یک ارزیابی مناسب شامل موارد زیر است: یک مجموعه (Corpus) آزمایشی مؤثر [215]، محیط یا پلتفرم ارزیابی عادلانه [30, 104, 126]، زمان فازینگ منطقی و کافی [17, 20]، و معیارهای مقایسهای جامع [96, 104]. با وجود تلاشهای انجام شده در این زمینه، هنوز یک سؤال باز وجود دارد: چگونه میتوان تکنیکها (یعنی الگوریتمهای فازینگ) را ارزیابی کرد، نه صرفاً پیادهسازیها (یعنی کدهایی که این الگوریتمها را اجرا میکنند) [18]. یک راهکار رایج، ارزیابی فازرها بر اساس آزمونهای آماری است که احتمال یا شاخصی ارائه میدهد که تفاوت میان تکنیکهای مختلف فازینگ را نشان میدهد [96].
شکاف ۱: نظریههای فازینگ، شکاف بین فضای ورودی و فضای نقص را کاهش میدهند. نظریههای فازینگ، فرآیندهای فازینگ را بر اساس رفتارهای برنامه، مانند ورود باگ، انتقال حالت و کشف حالت، فرموله میکنند. اکثر نظریهها، فرآیند زمانبندی بذر (seed) را فرموله میکنند. تقریباً همه فازرها، حفظ بذر را بر اساس الگوریتم ژنتیک فرموله میکنند.
۴. فضای جستجوی ورودیها (SEARCH SPACE OF INPUTS)
همانطور که در بخش ۳ بحث شد، فازرها از راهحلهای بهینهسازی برای حل مسئله جستجوی تولید ورودی استفاده میکنند که فرآیند جستجو را در فضای ورودی بهینه میکند. اگر یک فازر بتواند فضای ورودی را کاهش دهد، عملکرد فازینگ را بهبود خواهد بخشید. برای دستیابی به این هدف، فازرها بایتهای مرتبط در یک ورودی را گروهبندی کرده و جهشدهندههای خاصی را برای هر گروه اعمال میکنند.
فرض کنید یک ورودی شامل a ×b بایت است و به طور مساوی به بخشهای a تقسیم شده است. سپس به جای 256 a ×b، فضای جستجوی فازینگ هنگام حل یک محدودیت مسیر خاص، a × 256b است. بایتهای مرتبط میتوانند آنهایی باشند که ساختار داده یکسانی را میسازند [16، 201]، بر محدودیت مسیر یکسانی تأثیر میگذارند [37، 38، 65، 67، 157، 160، 187]، یا با بخش یکسانی از یک گرامر مطابقت دارند [78، 115، 120، 136، 181، 197، 212]. جهش دهندهها شامل جهش بایت (مثلاً bitflip، حذف بایت و درج بایت) [23، 206] و جهش تکهای (مثلاً جایگزینی تکهای، حذف تکهای و درج تکهای) [74، 77، 78، 181، 197] میشوند.
همانطور که در شکل (a)4 نشان داده شده، کل فضای ورودی میتواند به سه بخش تقسیم شود که هر بخش به ترتیب با متغیرهای i، k و آرایه []a مرتبط است. از طرف دیگر، هنگام حل یک محدودیت مسیر (path constraint)، روشهایی که بر بایتهای مرتبط تمرکز میکنند نیز فضای جستجو را کاهش میدهند. برای مثال، هنگام حل محدودیت مسیر خط ۱۴ در شکل (a)4، اگر محدودیت خط ۱۳ برآورده شود، فضای جستجو تنها ۱ بایت خواهد بود.
نوع ویژهای از ورودیها، ورودیهای با ساختار بسیار مشخص هستند که برای برنامههایی مانند پیادهسازی پروتکلها، موتورهای Document Object Model (DOM) و کامپایلرها استفاده میشوند. همانطور که در شکل ۴(b) نشان داده شده، پارسر cJSON نیاز دارد که بخشهای ورودی با برخی کاراکترهای خاص شروع شوند. اگر ورودی این الزام را نقض کند، اجازه ندارد عملکردهایی که توسط پارسر محافظت میشوند را بررسی کند.
جدول ۲، روشهایی که فضای جستجوی ورودی را کاهش میدهند و روابط مورد استفاده برای گروهبندی بایتهای ورودی را توصیف میکند. فازرهای ذکر شده در جدول ۲ انتخاب شدهاند زیرا اصلیترین دستاورد آنها کاهش فضای ورودی است.
۴.۱ رابطه محدودیت بایت (Byte-constraint Relation)
برای اکثر محدودیتهای مسیر (path constraints)، تنها بخش کوچکی از یک ورودی بر آنها تأثیر میگذارد. اگر یک فازر تنها بایتهای مرتبط را تغییر دهد، عملکرد فازینگ میتواند به طور قابل توجهی بهبود یابد، زیرا فضای جستجوی ورودیها کاهش مییابد.
برای مثال، هنگام فازینگ با جهش تصادفی، ممکن است برای برآورده کردن شرط if (a[2] == 33) در شکل (a) 4 نیاز به تولید 25611 ورودی باشد. با این حال، اگر مشخص باشد که تنها بایت pos[10] بر مقدار a[2] تأثیر میگذارد، میتوان فقط همان بایت pos[10] را تغییر داد تا شرط برآورده شود. در نتیجه، حداکثر تنها ۲۵۶ ورودی برای حل محدودیت مسیر کافی است. پس از بهدست آوردن رابطه بایت-محدودیت، یک روش ساده برای جهش، تغییر تصادفی بایتهای مرتبط است [67, 157, 187]. روش یکنواختتر این است که مقادیر یک بایت را به ترتیب از ۰ تا ۲۵۵ تنظیم کنیم [172]. با این حال، هر دو روش مؤثر نیستند، زیرا هیچ دانشی درباره کیفیت ورودیها ندارند.
اگر فرایند استنباط رابطه بایت بتواند مقادیر دستورهای مقایسهای در برنامه را بهدست آورد، فازینگ میتواند بایتهای مرتبط را تغییر داده و ورودیهایی را انتخاب کند که پیشرفت در برآورده کردن محدودیتهای مسیر ایجاد کنند. یک ورودی پیشرفت ایجاد میکند اگر با تعداد بیشتری از بایتهای یک محدودیت مسیر مطابقت داشته باشد [65, 103]. علاوه بر این، فازینگ میتواند از الگوریتم نزول گرادیان (gradient descent) برای تغییر بایتهای مرتبط استفاده کرده و بهتدریج محدودیتهای مسیر را حل کند [37, 38].
جدول 2. فضای ورودی
Year | Fuzzer | Input Space Reduced By | Relation | Target App | Input | Runtime Info. | |
Muta.-based | Gene.-based | ||||||
2009 | BuzzFuzz [67] | dynamic taint analysis | byte-constraint | general | ✓ | ○ | |
2010 | TaintScope [187] | dynamic taint analysis | byte-constraint | general | ✓ | ○ | |
2010 | FLAX [160] | dynamic taint analysis | input-web operation | web apps | ✓ | ● | |
2012 | LangFuzz [80] | fragment | chunk-chunk | JavaScript engine | ✓ | ● | |
2015 | MutaGen [92] | encoding function | byte-instruction | file processor | ✓ | ● | |
2016 | Driller [177] | concolic execution | input-path | general | ✓ | ○ | |
2016 | MoWF [153] | input model | chunk-chunk | file processor | ✓ | ●+○ | |
2016 | TLS-Attacker [173] | framework integration | chunk-chunk | protocol | ✓ | ● | |
2017 | Steelix [103] | relation inference | byte-constraint | general | ✓ | ◐ | |
2017 | Skyfire [185] | fragment | chunk-chunk | file processor | ✓ | ● | |
2017 | Learn& Fuzz [74] | machine learning | chunk-chunk | file processor | ✓ | ● | |
2017 | GLADE [12] | grammar synthesis | chunk-chunk | file processor | ✓ | ● | |
2017 | DIFUZE [53] | dependency inference | chunk-chunk | kernel driver | ✓ | ● | |
2017 | IMF [77] | dependency inference | chunk-chunk | kernel | ✓ | ● | |
2018 | IoTFuzzer [36] | encoding function | byte-function | IoT | ✓ | ● | |
2018 | FairFuzz [101] | relation inference | byte-coverage | general | ✓ | ◐ | |
2018 | QSYM [204] | concolic execution | input-path | general | ✓ | ○ | |
2018 | T-Fuzz [150] | program transformation | input-bug path | general | ✓ | ◐+○ | |
2018 | ContractFuzzer [86] | dependency inference | chunk-chunk | smart contract | ✓ | ◐ | |
2019 | RESTler [8] | dependency inference | chunk-chunk | cloud service | ✓ | ● | |
2019 | NEUZZ [172] | neural network | byte-coverage | general | ✓ | ◐ | |
2019 | SLF [200] | relation inference | byte-constraint | general | ✓ | ◐ | |
2019 | NAUTILUS [5] | input model | chunk-chunk | file processor | ✓ | ◐ | |
2019 | CodeAlchemist [78] | fragment | chunk-chunk | JavaScript engine | ✓ | ● | |
2019 | ILF [79] | machine learning | chunk-chunk | smart contract | ✓ | ◐+○ | |
2019 | GRIMOIRE [16] | format inference | byte-coverage | file processor | ✓ | ◐ | |
2019 | ProFuzzer [201] | format inference | byte-coverage | file processor | ✓ | ◐ | |
2020 | GREYONE [65] | relation inference | byte-variable | general | ✓ | ◐ | |
2020 | Pangolin [81] | concolic execution | input-path(s) | general | ✓ | ○ | |
2020 | SQUIRREL [212] | IR | chunk-chunk | DBMS | ✓ | ◐ | |
2020 | FreeDOM [197] | IR | chunk-chunk | DOM | ✓ | ● | |
2020 | Montage [99] | fragment | chunk-chunk | JavaScript engine | ✓ | ● | |
2020 | HFL [95] | dependency inference | chunk-chunk | kernel | ✓ | ○ | |
2020 | FANS [110] | dependency inference | chunk-chunk | Android | ✓ | ● | |
2021 | POLYGLOT [43] | IR | chunk-chunk | language processor | ✓ | ◐ | |
2021 | DIANE [159] | encoding function | byte-function | IoT | ✓ | ● | |
2021 | Facovado [59] | dependency inference | chunk-chunk | JavaScript engine | ✓ | ● | |
توضیحات جدول:
فازرها با گروهبندی بایتهای مرتبط، فضای ورودی را کاهش میدهند. این گروههای بایت بر اساس روابط خاصی به دست میآیند.
○: فازینگ جعبه سفید؛ ◐: فازینگ جعبه خاکستری؛ ●: فازینگ جعبه سیاه
4.1.1 تحلیل پویای آلودگی (Dynamic Taint Analysis)
تحلیل پویای آلودگی (DTA) [51، 135] یک تکنیک رایج برای ایجاد روابط بین بایتهای ورودی و محدودیتهای مسیر است. DTA دادههای خاصی را در ورودیها علامتگذاری میکند و برچسبها را در طول اجرا منتشر میکند. اگر متغیری در برنامه برچسبی دریافت کند، متغیر با آن برچسب به دادهها متصل میشود [51]. فازرها [37، 38، 67، 157، 160، 187] از DTA برای ایجاد روابط بین بایتهای ورودی و نقاط حساس به امنیت (مثلاً فراخوانیهای سیستم/کتابخانه یا پرشهای شرطی) استفاده میکنند.
۴.۱.۲ استنتاج رابطه (Relation Inference)
روش DTA نیاز به تلاش دستی زیاد دارد و همچنین ممکن است به دلیل جریانهای داده پنهان (implicit dataflows) روابط نادرستی تولید کند [65]. چون فازینگ برنامههای هدف را با تعداد زیادی تست مورد بررسی قرار میدهد، یک راهکار سبک و کمهزینه این است که رابطه بین بایتها را در زمان اجرا استنتاج کنیم.
یکی از راهها این است که بررسی کنیم آیا جهش (mutation) یک بایت، مقدار یک متغیر [65]، نتیجه یک دستور مقایسه [7, 103, 200]، یا تعداد اجرای یک شاخه (branch hit) [101] را تغییر میدهد یا خیر. اگر تغییر ایجاد شد، آن بایت به ترتیب با متغیر، دستور مقایسه، یا شاخه مربوطه مرتبط است. راهکار دیگری برای استنتاج، ساخت تقریبی ارتباط بین بایتهای ورودی و رفتار شاخهها با استفاده از یادگیری عمیق (deep learning) است [172].
۴.۲ اجرای کونکولیک (Concolic Execution)
اجرای کونکولیک یا اجرای همزمان نمادین و واقعی (Concolic execution)، که با نام اجرای نمادین پویا یا dynamic symbolic execution نیز شناخته میشود، متغیرهای برنامه را بهصورت نمادین در نظر میگیرد، محدودیتهای مسیر (path constraints) را دنبال میکند و از حلکنندههای محدودیت (constraint solvers) برای تولید ورودیهای واقعی برای یک مسیر مشخص استفاده میکند [165].
به عبارت دیگر، اجرای همزمان نمادین و واقعی، با حل مستقیم محدودیتهای مسیر، فضای جستجو را کاهش میدهد. تکنیکهایی که هم از اجرای نمادین و هم از فازینگ استفاده میکنند، به نام فازینگ ترکیبی (hybrid fuzzing) یا فازینگ سفیدجعبه (whitebox fuzzing) شناخته میشوند.
فازینگ ترکیبی [72, 73, 153] از فازینگ برای پیمایش مسیرهای اجرایی در برنامههای هدف استفاده میکند و از اجرای همزمان نمادین و واقعی برای حل محدودیتهای موجود در آن مسیرها بهره میبرد. فازینگ به دلیل ماهیت تصادفی خود، در حل محدودیتهای مسیر محدودیت دارد. اگرچه اجرای همزمان نمادین و واقعی در حل محدودیتها مؤثر است، بهکارگیری آن برای هر مسیر اجرایی زمانبر است. بنابراین، زمانی که فازینگ دیگر قادر به کشف حالتهای جدید نیست، اجرای همزمان نمادین و واقعی برای حل محدودیتهایی که فازینگ نمیتواند برآورده کند، به کار گرفته میشود [177].
یکی از بهبودهای فازینگ هیبریدی (hybrid fuzzing) این است که اولویت را به مسیرهایی بدهد که حل محدودیتهای آنها برای اجرای همزمان نمادین و واقعی دشوارتر است [210]. علاوه بر انتخاب مسیر، عملکرد فازینگ ترکیبی میتواند با توسعه حلکنندههای تقریبی محدودیتها بهبود یابد. به طور معمول، حلکنندههای SMT (Satisfiability Modulo Theories)، مانند MathSAT5 [49] یا Z3 [54] برای حل محدودیتهای مسیر استفاده میشوند.
با این حال، حلکنندههای SMT در حل محدودیتها با مشکلاتی مواجه هستند که ناشی از پیچیدگی محدودیتها یا انفجار مسیرها (path explosion) است [177]. برای کاهش این مشکل، حلکننده محدودیتها تنها محدودیتهای مسیری را نمادینسازی میکند که توسط ورودیها تحت تأثیر قرار میگیرند [46, 204].
بهبود دیگر مبتنی بر این مشاهده است که بسیاری از محدودیتهای مسیر به صورت خطی یا یکنواخت هستند [47]. بنابراین، حلکننده محدودیت به صورت جعبه خاکستری (greybox) عمل میکند؛ به عنوان مثال، از توابع خطی برای تقریب رفتار محدودیتها استفاده میکند. جالب توجه است که محققان به حل محدودیتهای مسیر از طریق فازینگ نیز توجه کردهاند [24, 108].
برای مثال، JFS [108] فرمولهای SMT را به یک برنامه ترجمه میکند و از فازینگ مبتنی بر پوشش (coverage-guided fuzzing) برای اکتشاف برنامه استفاده میکند. فرمولهای SMT زمانی حل میشوند که ورودی تولید شده توسط فازینگ به مکانهای مشخصی از برنامه مربوطه برسد.
حلکنندههای محدودیت (constraint solvers) میتوانند با توجه به ویژگیهای هدف (target) بهبود یابند.
در مورد شرطهای تو در تو (nested conditions)، مانند خطوط ۱۳–۱۵ در شکل ۴(a)، Pangolin [81] روش انتزاع مسیر چندوجهی (polyhedral path abstraction) را برای حل محدودیتهای مسیر تو در تو پیشنهاد میکند. این انتزاع مسیر چندوجهی فضای راهحلهای محدودیتهای تاریخی را حفظ میکند و از آن برای ارضای محدودیتهای مسیر فعلی استفاده مجدد میکند. برای مثال، برای حل محدودیت در خط ۱۴ شکل ۴(a)، ورودی ابتدا باید شرایط خط ۱۳ را برآورده کند.
برای استفاده از فازینگ هیبریدی (hybrid fuzzing) در برنامههایی که ورودیهای بسیار ساختاریافته (highly structured inputs) نیاز دارند، Godefroid و همکاران [71] ابتدا توکنهای گرامر را به عنوان متغیرهای نمادین (symbolic variables) نمادین میکنند. سپس از حلکننده محدودیتهای بدون زمینه (context-free constraint solver) برای تولید ورودیهای جدید استفاده میکنند.
۴.۳ تبدیل برنامه (Program Transformation)
در فازینگ، هدف از تبدیل برنامه این است که بررسیهای صحت یا صحتسنجی (sanity checks) را حذف کند که مانع از کشف حالات اجرایی بیشتر توسط فازر میشوند. با حذف این چکها، فازینگ میتواند کدهای عمیقتر در برنامه هدف را بررسی کرده و باگهای بالقوه را آشکار کند [150].
البته این حذف ممکن است منجر به تولید مثبتهای کاذب در مکانهای باگ شود که میتوانند با اجرای نمادین (symbolic execution) مورد بررسی دقیقتر قرار گیرند. بنابراین، تبدیل برنامه با تمرکز روی ورودیهایی که احتمالاً باگ را فعال میکنند، فضای جستجو را کاهش میدهد.
۴.۴ مدل ورودی (Input Model)
بسیاری از برنامهها به ورودیهای بسیار ساختاریافته نیاز دارند، مانند پیادهسازی پروتکلها [3]، موتورهای DOM [197]، موتورهای جاوا اسکریپت [78]، خوانندگان PDF [74]، فراخوانیهای سیستمی [77] و کامپایلرها [43]. یک مدل ورودی، قوانین ساخت یک ورودی بسیار ساختاریافته، از جمله ساختار، قالببندی و محدودیتهای داده ورودیها را مشخص میکند. به منظور تولید ورودیهایی که مشخصات را برآورده میکنند، فرآیند تولید به عملیات خاصی محدود میشود. اگر یک ورودی، نحو یا معنای برنامههای هدف را نقض کند، ورودی در مراحل اولیه توسط برنامه رد میشود. به عبارت دیگر، فضای ورودی تابع مدل ورودی است.
۴.۴.۱ مدلها یا ابزارهای قابل دسترس (Accessible Models or Tools)
بسیاری از فازرها فایلهای ورودی معتبر را بر اساس مدلهای ورودی قابل دسترس [۳، ۵۶، ۵۷، ۱۰۰، ۱۱۵، ۱۳۶، ۱۴۷، ۱۸۱] یا ابزارهای موجود [۷۵، ۱۵۳] تولید میکنند. تولید ورودی بر اساس مشخصات ساده نیاز به تلاش مهندسی سنگین دارد. علاوه بر این، مستعد خطا است زیرا تجزیه مشخصات پیچیده است. تجزیهگر cJSON شکل ۴ (ب) پیادهسازی مشخصات JSON است که اگرچه به دلیل تجزیه پیچیده انواع مختلف داده، مستعد خطا است، اما ساده است. بنابراین، جامعه تحقیقاتی برخی از ابزارها را برای ورودیهای بسیار ساختاریافته، مانند QuickCheck [50] و ANTLR [146]، به صورت متنباز منتشر کرده است. به عنوان مثال، NAUTILUS [5] و Superion [186] ورودیهای جدیدی را بر اساس ANTLR تولید میکنند. سپس، هم NAUTILUS و هم Superion از پوشش کد برای بهینهسازی فرآیند جهش استفاده میکنند. در برخی سناریوها، مدل ورودی میتواند به سادگی نوعی باشد که دادههای تولید شده با آن مطابقت خواهند داشت (مثلاً انواع آرگومانهای API یا سیگنالهای فیزیکی) [1، 41، 70، 179]. به عنوان مثال، دادههای مربوط به محرکهای سیستمهای سایبر-فیزیکی (CPS) میتوانند مقادیر دودویی روشن یا خاموش باشند [41].
۴.۴.۲ ادغام پیادهسازیها (Integration of Implementations)
رویکرد امیدوارکننده دیگر، ادغام فازینگ با پیادهسازی برنامههای هدف است [۶۴، ۸۹، ۱۷۳]. چنین ادغامی به فازینگ اجازه میدهد تا با سفارشیسازی فرآیند تولید ورودی، ویژگیهای مورد نظر برنامههای هدف را بررسی کند. به عنوان مثال، TLS-Attacker [۱۷۳] چارچوبی ایجاد میکند که میتواند ورودیها را بر اساس نوع هر بخش تغییر دهد و ترتیب پیامهای پروتکل را دستکاری کند. این چارچوب شامل پیادهسازی کامل پروتکل امنیت لایه انتقال (TLS) است.
۴.۴.۳ نمایش میانی (Intermediate Representation – IR)
یک رویکرد پیچیدهتر این است که مدل ورودی به یک نمایش میانی (IR) تبدیل شود. برای ورودیهای به شدت ساختیافته، جهش (mutation) روی فایلهای ورودی اصلی بسیار پیچیده است و نگه داشتن نحو و معنای صحیح را دشوار میکند.
بنابراین، پژوهشگران فایلهای اصلی را به IR تبدیل میکنند، که سادهتر و یکپارچهتر است. فازرها روی IR جهش ایجاد میکنند و سپس IR جهش یافته را دوباره به قالببندی ورودی اصلی بازمیگردانند. این استراتژی جهش باعث میشود که ورودیها هم از نظر نحو و هم از نظر معنا درست باقی بمانند و ورودیهای متنوعتری تولید شود. برای مثال، از IR برای تست سیستمهای مدیریت پایگاه داده (DBMS) [212]، بررسی موتورهای DOM [197]، یا فازینگ پردازندههای زبانهای مختلف (مثل کامپایلرها یا مفسرها) [43] استفاده شده است.
۴.۵ ترکیب مجدد قطعهها (Fragment Recombination)
بر اساس مشخصات ورودی، یک راهکار دیگر برای تولید ورودی، ایجاد فایلهای ورودی جدید از طریق ترکیب مجدد قطعهها است. ایده اصلی ترکیب مجدد قطعهها این است که فایلهای ورودی را به تکههای کوچک (قطعهها) تقسیم کنیم و سپس یک فایل ورودی جدید با ترکیب قطعههای کوچک از فایلهای مختلف بسازیم.
هر قطعه با مشخصات ورودیها مطابقت دارد تا فایلهای ترکیبشده از نظر نحوی صحیح باشند. به طور ایدهآل، فایل ورودی بازسازیشده، یک مسیر اجرای جدید را فعال کرده یا یک باگ جدید را آشکار میکند.
همانطور که در شکل ۵ نشان داده شده، فازرها ابتدا یک فایل ورودی را به یک درخت تجزیه میکنند (مثلاً درخت نحو انتزاعی (AST[16]))، که این کار درستی نحوی ورودی را حفظ میکند. برای اینکه ورودیها بهدرستی تجزیه شوند، مجموعهای از ورودیهای معتبر (input corpus) لازم است [78, 180, 185, 199]. یکی از راهها برای جمعآوری چنین مجموعهای، دانلود فایلها از اینترنت است [26].
علاوه بر معتبر بودن، فازرها همچنین ورودیهای مشکلدار که قبلاً باعث رفتارهای نامعتبر شدهاند را در مجموعه ورودی جمعآوری میکنند [80, 99, 145]. فرض اساسی این است که یک باگ جدید ممکن است هنوز در همان مکان یا نزدیکی مکانی که یک ورودی قبلاً باگ کشف کرده، وجود داشته باشد [80].
این ورودیهای مشکلدار مسیرهای اجرای پیچیدهای را تجربه کردهاند که منجر به رفتارهای نامعتبر میشوند. بنابراین، ترکیب مجدد قطعهها ممکن است همان مسیرهای پیچیده یا مسیرهای مجاور را فعال کند و این به فازینگ کمک میکند تا خطوط کد عمیقتر را کشف کند.
در مرحله دوم، فایلهای ورودی به قطعههای کوچک تقسیم میشوند که در استخر قطعهها (fragment pool) ذخیره میشوند. از آنجا که فازرها ورودیها را به AST تجزیه میکنند، قطعهها میتوانند زیر-درختهایی شامل نمادهای غیرترمینال باشند.
هنگام ترکیب مجدد قطعهها، فایل ورودی تازه تولیدشده باید از نظر نحوی صحیح باشد. بنابراین، فازرها قطعههای نحویسازگار را بر اساس انتخاب تصادفی [80, 120, 199]، الگوریتم ژنتیک [180] یا یادگیری ماشین [185] ترکیب میکنند.
علاوه بر درستی نحوی، درستی معنایی نیز تاثیر قابلتوجهی بر اثربخشی فازینگ دارد. برای مثال، برای تولید ورودیهای جاوااسکریپت (JavaScript) که هم از نظر نحوی و هم معنایی صحیح باشند، CodeAlchemist [78] قطعهها را با محدودیتهای اسمبلی (assembly constraints) برچسبگذاری میکند. یعنی، قطعههای مختلف فقط زمانی ترکیب میشوند که محدودیتها رعایت شده باشند.
۴.۶ استنتاج قالب (Format Inference)
اگر مدلهای ورودی در دسترس نباشند، استنتاج قالب ورودیها یک راهحل امیدوارکننده برای تولید ورودیهای معتبر است. علاوه بر این، یک مدل ورودی تنها قادر است ورودیهایی با یک قالب خاص تولید کند. برای اینکه از چندین قالب ورودی پشتیبانی شود، توسعه دهندگان باید از مدلهای ورودی جدید استفاده کنند و مدل ورودی مناسب را هنگام تولید ورودی انتخاب نمایند. بنابراین، استنتاج قالب نسبت به روشهای مبتنی بر مدل، مقیاسپذیری بالاتری دارد.
۴.۶.۱ مبتنی بر مجموعه ورودی (Corpus-based)
برای استنتاج قالب ورودیها (Input format)، یک روش مستقیم این است که یادگیری از یک مجموعه ورودی معتبر (input corpus) انجام شود. با توجه به فقدان مدلهای ورودی از پیش تعریف شده، پژوهشگران مدلهای یادگیری عمیق انتها به انتها (end-to-end) را به عنوان جانشین مدل ورودی به کار میگیرند. شبکه عصبی بازگشتی ([17]RNN) [127] یکی از مدلهای یادگیری عمیق مناسب برای تولید ورودیهای ساختاریافته توسط فازرها است [74, 79, 111, 112].
با این حال، راهحل جانشین ممکن است در تولید ورودیهای نامعتبر مشکل داشته باشد. برای مثال، بالاترین نرخ تولید ورودیهای با نحو معتبر توسط DeepFuzz [112] تنها ۸۲.۶۳٪ است. برای افزایش نرخ تولید ورودیهای معتبر، دادههای آموزشی باید متناسب با قالب هدف اصلاح شوند. به عنوان مثال برای تولید فایلهای PDF، دادههای آموزشی از ترتیب اشیاء PDF تشکیل میشوند و نه از دادههای متنی ساده [74]. برای قراردادهای هوشمند (smart contracts)، دادههای آموزشی شامل ترتیب تراکنشها است [79].
بهطور مشابه، LipFuzzer [208] مدلهای زبانی خصمانه (adversarial linguistic models) را برای تولید فرمانهای صوتی آموزش میدهد، که دادههای آموزشی آن در قالب ساختار زبانی ارائه شدهاند. علاوه بر این، فازینگ میتواند یک دستور زبان مستقل از متن (context-free grammar)، مانند خصوصیات منظم شامل تکرارها و جایگزینیها، را بر اساس یک مجموعه ورودی معتبر ترکیب (synthesis) کند [12]. سپس این دستور زبان ترکیب شده (synthesized grammar) برای تولید ورودیهای بسیار ساختاریافته مورد استفاده قرار میگیرد.
۴.۶.۲ مبتنی بر پوشش کد (Coverage-based)
راهحل مبتنی بر مجموعه ورودی (corpus-based) نیاز دارد که دادههای آموزشی پوشش جامع از مشخصات ورودی داشته باشند، که ممکن است عملی نباشد [200]. علاوه بر این، این روش از دانش وضعیتهای داخلی اجرا (مانند پوشش کد) استفاده نمیکند، که ممکن است منجر به پوشش کد پایین شود. در واقع، قالب ورودیها نشاندهنده روابط بین بایتهای مختلف در ورودی است. بنابراین، بر اساس پوشش کد، فازرها روابط بایت به بایت را استنتاج میکنند تا عملکرد فازینگ را بهبود بخشند [16, 201].
به عنوان مثال GRIMOIRE [16] از پوشش کد برای استنتاج قالب مورد نیاز برنامههای هدف استفاده میکند. هدف آن شناسایی مرزهای قالب یک ورودی است. به طور مشخص، برخی بایتها در یک ورودی تغییر داده میشوند و بررسی میشود که آیا تغییرات باعث تغییر پوشش کد میشوند یا خیر. اگر پوشش کد تغییر نکند، موقعیتهایی که بایتها در آنها تغییر یافتهاند میتوانند به صورت تصادفی تغییر داده شوند. در غیر این صورت، موقعیتها باید با دقت تغییر داده شوند. ProFuzzer [201] ابتدا شش نوع داده تعریف میکند که اکثر محتوای ورودی را پوشش میدهند. سپس، بر اساس توزیع پوشش لبهها (edge coverage)، نوع هر بایت را استنتاج میکند و بایتهای متوالی که به یک نوع تعلق دارند را با هم ادغام میکند.
۴.۶.۳ تابع کدگذاری (Encoding Function)
برخلاف همه روشهای پیشین که روی ورودیها تمرکز دارند، برخی از فازرها به دنبال بخشهای کد میگردند که قالب ورودیها را کدگذاری میکنند [36, 92, 159]. از آنجا که این بخشهای کد با تولید ورودیهای ساختاریافته مرتبط هستند، فازرها قبل از کدگذاری قالبها، جهش (mutation) را اعمال میکنند. اگرچه ممکن است کد منبع PUT در دسترس نباشد، اما پیادهسازیهای متناظر آنها که ورودیهای ساختاریافته تولید میکنند اغلب در دسترس هستند [92].
برای مثال برخی ابزارها برای تولید ورودیهای بسیار ساختاریافته به صورت متنباز ارائه شدهاند [50, 146] (بخش ۴.۴.۱). در مورد دستگاههای IoT، بیشتر آنها از طریق برنامههای همراه کنترل میشوند که پیامهایی با دستگاههای هدف رد و بدل میکنند [36].
با یافتن بخشهای کد مرتبط با کدگذاری قالبها، تغییرات میتوانند روی آرگومانهای توابع [36, 159] یا دستوراتی که قالبها را محاسبه میکنند [92] اعمال شوند. به عنوان مثال، IoTFuzzer [36] چنین توابعی را رهگیری (hook) میکند و دادههای آرگومانهای آنها را تغییر میدهد.
۴.۷ استنتاج وابستگیها (Dependency Inference)
استنتاج قالب (Format Inference) عمدتاً به منظور رعایت الزامات نحوی (syntactic requirements) انجام میشود، اما ممکن است هنوز ورودیهایی تولید کند که وابستگی دادهای نادرست داشته باشند. برای مثال، در کد نمونه ۲ در شکل ۶، خطا در خطوط ۲ تا ۵ رخ میدهد زیرا تابع ()errf تعریف نشده است. بسیاری از برنامهها نیاز دارند که وابستگی دادهای ورودیها صحیح باشد؛ این ورودیها معمولاً از دنبالهای از دستورات (sequences of statements) تشکیل شدهاند. این دنبالهها میتوانند شامل موارد زیر باشند:
- فراخوانیهای سیستمی برای کد کرنل [77, 95, 142]
- اشیاء برای پردازندههای برنامههای شیءگرا [59, 117]
- رابطهای برنامهنویسی سرویسها یا کتابخانهها (APIs) [8, 83, 110]
- رابطهای باینری برنامه (ABIs) برای قراردادهای هوشمند [86]
از یک طرف، اکثر این برنامهها نیاز به تعریف/اعلان دادهها قبل از استفاده از آنها در ورودیها دارند، همانطور که در شکل ۶ نشان داده شده است. از طرف دیگر، خروجی اجرای برخی دستورات به عنوان دادههای آرگومان برای سایر دستورات استفاده میشود.
۴.۷.۱ اسناد یا کد منبع (Documents or Source Code)
وابستگی دادههای توالیها معمولاً از طریق تحلیل استاتیک استنباط میشود. از آنجا که بسیاری از برنامهها دارای اسناد یا کد منبعی هستند که رابطهای خود را توصیف میکنند، محققان وابستگی دادهها را بر اساس آن منابع استنباط میکنند [۸، ۵۳، ۵۹، ۸۶، ۱۱۰، ۱۱۷]. این منابع حاوی اطلاعاتی در مورد نحوه استفاده از یک رابط و پیشنیازهای رابط هستند. هنگامی که فازینگ ورودیهایی از جمله یک رابط تولید میکند، فازینگ برای تولید پیشنیازهای رابط نیز لازم است. در غیر این صورت، ورودی تولید شده در مراحل اولیه رد خواهد شد.
با این حال، تحلیل ایستا (static analysis) موجب ایجاد خطای مثبت کاذب بالا (high false positives) میشود و همچنین وابستگیهای رابطها (dependencies of interfaces) را ممکن است از دست بدهد. بنابراین، وقتی دسترسی به کد منبع برنامههای تحت آزمون وجود دارد، یک راهحل بهتر ترکیب تحلیل ایستا و پویا (dynamic analysis) است [95].
۴.۷.۲ برنامههای دنیای واقعی (Real-world Programs)
بسیاری از برنامههای واقعی (real-world programs) خطوط کدی را پیادهسازی میکنند که رابطها (interfaces) را فراخوانی میکنند و در این فرآیند، وابستگی دادهای رابطها (data dependency of interfaces) در نظر گرفته شده است. بنابراین، فازینگ (fuzzing) میتواند برنامههای جدیدی تولید کند که این رابطها را بر اساس برش برنامهای (program slicing) برنامههای واقعی فراخوانی میکنند [10].
علاوه بر این، وابستگی دادهای میتواند از طریق تحلیل گزارشهای (Log) اجرای برنامههای واقعی استنتاج شود [77, 83, 142]. این لاگهای اجرا به طور صریح حاوی اطلاعات ترتیب اجرای رابطها (ordering information of interfaces) هستند، یعنی اطلاعاتی درباره اینکه کدام رابط ابتدا اجرا شده است. علاوه بر این، لاگهای اجرا به طور ضمنی شامل اطلاعات وابستگی آرگومانها بین رابطها (argument dependency between interfaces) نیز هستند. برای بهدست آوردن اطلاعات صریح و ضمنی، فازینگ هنگام اجرای برنامه واقعی، هر رابط را رهگیری (hook) میکند و اطلاعات مورد نظر را ضبط میکند.
شکاف ۲: کاهش فضای ورودی به گروهبندی بایتهای ورودی که از نظر نحوی و/یا معنایی به هم مرتبط هستند، متکی است. مزیت گروهبندی بایتها، بهبود کارایی در کاوش حالتهای اجرایی بیشتر است. یعنی، فازینگ احتمال بیشتری دارد که محدودیتهای مسیر را برآورده کند، به طوری که نواحی کد عمیق محافظتشده توسط این محدودیتها را کاوش میکند.
۵. خودکارسازی (Automation)
اجرای خودکار، پایه و اساس استفاده از نظریه فازینگ (fuzzing theory) و روشهای کاهش فضای ورودی (input space reduction) است. فازینگ به طور مکرر برنامههای تحت آزمون را اجرا میکند و اجرای آنها را برای یافتن استثناها (exceptions) بررسی میکند. سپس این استثناها برای تعیین اینکه آیا باگ هستند یا خیر، مورد بررسی قرار میگیرند.
بنابراین، برای موفقیت در فازینگ، اولین نیاز این است که PUTها به صورت خودکار و مکرر اجرا شوند. اکثر فازرها تاکنون در آزمون نرمافزارهای خط فرمان (command-line software) موفق بودهاند، اما نمیتوان آنها را مستقیماً برای سایر اهداف، مانند سختافزار یا نرمافزارهای چندزبانه (polyglot software) استفاده کرد [18].
دومین نیاز، شاخص خودکار برای شناسایی باگهای احتمالی است. در حال حاضر، فازینگ از توقفهای غیرعادی یا کرشها (crash) به عنوان نشانهای از باگهای احتمالی استفاده میکند. با این حال، بسیاری از باگها به صورت توقف غیرعادی ظاهر نمیشوند، مانند رقابتهای داده (data races).
از آنجا که ماهیت فازینگ بر تکرار اجرای هدفها استوار است، سومین نیاز، سرعت بالای اجرای فازینگ است. سرعت بالاتر اجرا به این معناست که تعداد بیشتری از موارد آزمون (test cases) در همان بازه زمانی بررسی میشوند و بنابراین فرصت بیشتری برای کشف نواقص (defects) فراهم میشود.
۵.۱ اجرای خودکار نرم افزارهای تحت آزمون (Automatic Execution of PUT)
فازینگ برای کاربردهای متنوع استفاده میشود که هر یک نیازمند تلاشهای مهندسی متفاوت برای خودکارسازی فرآیند فازینگ هستند. در این بخش، چند نوع از کاربردهایی که در آنها فازینگ با موفقیت فرآیند تست را خودکار کرده است معرفی میشوند.
۵.۱.۱ برنامههای خط فرمان (Command-line Programs)
فازینگ در آزمون برنامههای خط فرمان (مانند برنامههای «عمومی» در جداول ۱ و ۲) موفقیت قابل توجهی داشته است. در این روش، برنامههای تحت آزمون در یک زیرفرآیند اجرا میشوند و ورودیها و گزینههای لازم به آنها داده میشود [23, 206, 214]. برای افزایش سرعت اجرا، فازینگ تمام مراحل اجرای برنامههای تحت آزمون را دوباره پخش نمیکند؛ بلکه یک فرآیند فرزند ایجاد میکند تا مراحل پیشپردازش مانند بارگذاری فایل برنامه در حافظه را رد کند [206, 216].
معمولاً فازینگ از یک گزینه خط فرمان برای تمامی کمپینهای فازینگ استفاده میکند؛ یعنی همه ورودیهای تولیدشده بر اساس همان یک گزینه اجرا میشوند. با این حال، از آنجا که گزینههای مختلف میتوانند پوشش کد متفاوتی ایجاد کنند، یک تست کامل نیازمند شمردن تمامی گزینههای خط فرمان است. یک راهکار کارآمد این است که اگر ورودیای برای یک گزینه نامعتبر باشد، فازینگ تست باقی گزینهها را رد کند [176]. مشاهده مهم در این روش این است که اگر یک ورودی برای یک گزینه نامعتبر باشد، احتمالاً برای تمام گزینههای دیگر نیز نامعتبر خواهد بود.
۵.۱.۲ سیستمهای یادگیری عمیق (Deep Learning Systems)
فازینگ سیستمهای یادگیری عمیق (DLSs) مشابه تست برنامههای خط فرمان عمل میکند. در این روش، ورودیهای تولیدشده توسط فازینگ برای تست سیستمها استفاده میشوند و هدف فازینگ، تولید ورودیهایی با کیفیت (fitness) بهتر است [68, 115, 148]. این ورودیها میتوانند دادههای آموزشی، دادههای آزمایشی یا حتی مدلهای یادگیری عمیق بسته به هدف تست باشند.
از سوی دیگر، معیار کیفیت میتواند پوشش نورونها، تابع خطا (loss function) یا پوشش در سطح عملگرها باشد، همانطور که در بخش ۳.۵.۲ توضیح داده شد. در تست سیستمهای یادگیری عمیق، فازینگ نه تنها به کشف نقصها کمک میکند [115]، بلکه مقاومت و پایداری مدلها را نیز بررسی میکند [68, 148].
۵.۱.۳ هستههای سیستمعامل (Operating System Kernels)
هستههای سیستمعامل (OS) نسبت به برنامههای خط فرمان پیچیدهتر هستند. هستهها شامل تعداد زیادی وقفهها (interrupts) و تردهای کرنل (kernel threads) هستند که منجر به وضعیتهای اجرایی غیرقطعی میشوند. به منظور آن که بتوان کرنلها را مشابه برنامههای خط فرمان فاز کرد، از یک هایپروایزر (hypervisor) مانند QEMU یا KVM برای اجرای کرنل هدف استفاده میشود [143, 164]. همزمان، پوشش کد از طریق فناوری Intel Processor Trace (PT) به دست میآید. اگرچه این روش امکان فازینگ هستههای مختلف با بازخورد را فراهم میکند، اما هنوز نیاز به ساخت دستی ورودیهای صحیح از نظر نحو و معنا دارد.
ورودیهای هسته معمولاً شامل تصاویر سیستم فایل یا دنبالهای از فراخوانیهای سیستمی یا syscallها هستند. فازرها میتوانند هستهها را به شکل سبکتری تست کنند، یعنی پس از تحلیل یا استنتاج وابستگی دادهای فراخوانیهای سیستمی (بخش ۴.۷)، دنبالهای از syscallها برای اجرای روی هسته هدف تولید میکنند [53, 77, 95, 142, 183, 194, 196]. سپس فازرها بررسی میکنند که آیا اجرای این دنبالهها منجر به پانیک سیستم شده است یا خیر، که میتواند نشانهای از باگهای احتمالی هسته هدف باشد. روش دیگر فازینگ هستهها، شبیهسازی دستگاههای خارجی است. از آنجایی که هسته با این دستگاههای شبیهسازیشده ارتباط برقرار میکند، فازرها میتوانند ورودیهایی برای تست درایورها در هسته تولید کنند [149].
5.1.4 سامانههای سایبری-فیزیکی (CPS یا Cyber-Physical Systems)
این سامانهها شامل دو بخش اصلی هستند که به طور تنگاتنگ با هم یکپارچه شدهاند: عناصر محاسباتی و فرایندهای فیزیکی [41]. یکی از عناصر محاسباتی پرکاربرد در این سیستمها کنترلکننده منطقی برنامهپذیر (PLC) است که عملگرها (actuators) را برای مدیریت فرایندهای فیزیکی کنترل میکند و ورودیها را از حسگرها (sensors) دریافت مینماید.
بنابراین، هنگام فازینگ CPSها، فازرها میتوانند PLCها را جایگزین کرده و مستقیماً از طریق شبکه، دستورات متعددی را به عملگرها ارسال کنند [41]. روش دیگر برای فازینگ CPSها، بررسی برنامههای کنترلی و زمان اجرای PLCها است [179]. با این حال، باینریهای PLC را نمیتوان به همان شیوهای که برنامههای خط فرمان فاز میشوند، مورد آزمون قرار داد.
از آنجا که برنامههای PLC دارای قالبهای باینری متنوع و ارتباطات پیچیده با اجزای فیزیکی هستند، خودکارسازی این برنامهها نیز متفاوت است. با تحلیل باینریهای PLC و پلتفرمهای توسعه آنها (مانند Codesys)، میتوان باینریهای PLC را بهصورت خودکار فاز کرد، زمانی که روی دستگاههای PLC اجرا میشوند [179].
۵.۱.۵ اینترنت اشیا (IoT)
خودکارسازی فازینگ دستگاههای اینترنت اشیا (IoT) شامل شبیهسازی (emulation) [34, 205, 211] و آزمون در سطح شبکه [36, 63, 159] است. شبیهسازها [34, 205] میتوانند برنامههایی را اجرا کنند که در اصل روی فریمور IoT اجرا میشوند، بدون نیاز به سختافزار مربوطه. با کمک این شبیهسازها، فازرها برنامههای هدف را به صورت جعبه خاکستری (greybox) اجرا میکنند [211].
از سوی دیگر، فازینگ در سطح شبکه دستگاههای IoT را بهصورت جعبه سیاه (blackbox) بررسی میکند. از آنجا که دستگاههای IoT میتوانند از طریق شبکه با دنیای بیرون ارتباط برقرار کنند، فازرها بهطور خودکار پیامها (درخواستها) را به این دستگاهها ارسال کرده و منتظر نتایج اجرا (پاسخها) از آنها میمانند [36, 63, 159]. با دستهبندی پاسخها، معیار شایستگی برابر با تعداد دستهها در نظر گرفته میشود؛ یعنی هدف این است که دستههای بیشتری کشف شوند [63].
۵.۱.۶ برنامههای دارای رابط گرافیکی کاربری (Applications with Graphical User Interface)
برنامههای دارای رابط کاربری گرافیکی (GUI). سرعت اجرای برنامههای دارای رابط کاربری گرافیکی (GUI) به مراتب کندتر از برنامههای خط فرمان است [91]. از آنجا که سرعت اجرا یکی از عوامل کلیدی موفقیت فازینگ محسوب میشود، خودکارسازی برنامههای GUI معمولاً رابط گرافیکی را با رویکردی سریعتر جایگزین میکند و اهداف را بهصورت خط فرمان اجرا مینماید [91, 106, 121].
برای مثال، فازرها میتوانند تعاملات رابط کاربری را مدلسازی کنند تا دنبالههایی از رویدادها را برای برنامههای اندروید تولید کنند [106, 121]. علاوه بر این، فازرها میتوانند از یک مهار (harness) نیز استفاده کنند که زمینهٔ اجرای برنامه را آماده میکند تا توابع هدف در رابطهای گرافیکی به طور مستقیم فراخوانی شوند [91].
۵.۱.۷ برنامههای دارای شبکه (Applications with Network)
برخی برنامهها، ورودیها (پیامها) را از طریق شبکه دریافت میکنند، مانند: قراردادهای هوشمند (smart contracts) [79, 86, 137, 193]، پیادهسازیهای پروتکل (protocol implementations) [55, 61, 64, 69, 154]، خدمات ابری (cloud services) [8]، سرویسهای سیستم بومی اندروید [1, 110]، یا خودروهای رباتیک [82]. در چنین برنامههایی، میتوان ورودیها را به صورت محلی تولید کرد و اجرای برنامه هدف را به صورت راه دور انجام داد. کارایی تست خودکار به کیفیت ورودیهای تولید شده و همچنین کیفیتی که وضعیتهای اجرایی را نشان میدهد بستگی دارد. به طور مثال: ورودیهای قراردادهای هوشمند، دنبالهای از تراکنشهای قراردادها هستند؛ یعنی پیامهایی بین حسابهای مختلف. هنگام دریافت این تراکنشها، توابع قراردادهای هوشمند روی زیرساخت بلاکچین اجرا میشوند [79, 86, 137, 193].
۵.۲ تشخیص خودکار باگها (Automatic Detection of Bugs)
بسیاری از باگهای امنیتی میتوانند برای کنترل سیستمها، نشت دادههای خصوصی یا از کار انداختن سرورها مورد سوءاستفاده قرار گیرند [131]. چالش اصلی در تشخیص باگها این است که باگها غیرقابل پیشبینی هستند. بهطور خاص، ابزار تشخیص نمیداند باگها کجا هستند و حتی نمیداند که باگی در برنامه هدف وجود دارد یا خیر تا قبل از شروع تست. بنابراین، ثبت خودکار باگهای بالقوه در طول فرآیند فازینگ اهمیت بالایی دارد.
معمولاً شاخصها شامل کرشهای اجرای برنامه هستند، اما برخی شاخصهای دیگر نیز بر اساس الگوهای باگ طراحی شدهاند. اگرچه الگوهای باگ فقط میتوانند برخی انواع خاص باگها را آشکار کنند، در صورت وجود چنین باگهایی در برنامه هدف، بسیار مؤثر هستند [143]. این بخش عمدتاً شش نوع باگ را معرفی میکند که بهطور موفقیتآمیز توسط فازینگ کشف شدهاند: باگهای نقض حافظه (memory-violation bugs)، باگهای همزمانی (concurrency bugs)، پیچیدگی الگوریتمی، باگهای نوع Spectre، کانالهای جانبی (side channels)، و باگهای عدد صحیح (integer bugs).
۵.۲.۱ باگهای نقض حافظه (Memory-violation Bugs)
باگهای نقض حافظه از قدیمیترین و شدیدترین باگهای امنیتی هستند [131, 175, 178]. یک برنامه زمانی از نظر حافظه ایمن (memory safe) محسوب میشود که اشارهگرها فقط به نواحی موردنظر خود دسترسی داشته باشند. نقض ایمنی حافظه به دو دسته تقسیم میشود: نقض فضایی (spatial) و نقض زمانی (temporal) [175]. نقض فضایی زمانی رخ میدهد که دسترسی به حافظه خارج از محدوده مجاز انجام شود. نقض زمانی زمانی رخ میدهد که به یک مرجع نامعتبر (مثلاً حافظه آزاد شده) دسترسی صورت گیرد.
برای مثال، شکل (a) 7 یک نقض فضایی است زیرا اندازه buf از str بزرگتر است (سرریز بافر یا buffer overflow). در مقابل، شکل (b) 7 یک نقض زمانی است زیرا اشارهگر p پس از آزاد شدن حافظهاش استفاده میشود (use-after-free). با وجود اینکه روشهای متعددی برای کاهش اثر این نوع خطاها پیشنهاد شدهاند، بیشتر آنها در عمل استفاده نمیشوند، به دلیل معایبی مانند سربار عملکردی، سازگاری پایین و استحکام کم [178].
سرریز بافر (Buffer overflow) یکی از انواع باگهای نقض حافظه است که در آن دادهها خارج از محدوده مجاز نوشته میشوند (مثلاً مثال شکل (a)7). Dowser [76] بیان میکند که سرریزهای بافر معمولاً به دلیل دسترسی به آرایهها در داخل حلقهها رخ میدهند. برای شناسایی این نوع باگها در حلقهها، Dowser دستورالعملهایی را که در حلقهها به بافرها دسترسی دارند رتبهبندی میکند و به ورودیهایی اولویت میدهد که این دسترسیهای با رتبه بالاتر را اجرا میکنند. سپس از تحلیل آلودگی (taint analysis) و ترکیب اجرای واقعی و نمادین (concolic execution) برای حل محدودیتهای مسیر مربوط به این ورودیها استفاده میکند. از آنجا که Dowser روی آرایههای داخل حلقه تمرکز دارد، تنها تعداد کمی از دستورالعملها نیاز به ابزارسنجی دارند و همین تمرکز باعث افزایش سرعت اجرای هر دو تحلیل تِینت و اجرای کونکولیک میشود.
باگ use-after-free (UaF یا استفاده مجدد پس از آزادسازی) نوع دیگری از نقض حافظه است که در دسته نقض زمانی قرار میگیرد. همانطور که در شکل (b) 7 نشان داده شده، یک باگ UaF حداقل شامل سه مرحله است: (1) تخصیص حافظه به یک اشارهگر، (2) آزادسازی آن حافظه و سپس (3) استفاده مجدد از همان اشارهگر. این الگوی باگ باعث شده است که UAFL [184] ورودیهایی تولید کند که به تدریج بتوانند کل دنبالههای بالقوه UaF را پوشش دهند. این دنبالههای بالقوه با استفاده از تحلیل ایستای typestate و بر اساس الگوی باگ استخراج میشوند.
۵.۲.۲ باگهای همزمانی (Concurrency Bugs)
یکی دیگر از باگهای شدید امنیتی، باگهای همزمانی (concurrency bugs) هستند که زمانی رخ میدهند که برنامههای همزمان بدون همگامسازی (synchronization) یا ترتیب مناسب اجرا شوند. بهطور کلی، باگهای همزمانی به دو دستهٔ باگهای بنبست (deadlock) و باگهای غیر بنبست (non-deadlock) تقسیم میشوند [114]. باگ بنبست زمانی رخ میدهد که عملیاتهای یک برنامه منتظر یکدیگر میمانند تا منابع (مانند قفلها) آزاد شوند. باگهای همزمانی غیر بنبست عمدتاً شامل باگهای نقض یکپارچگی و غیرقابلتقسیم (atomicity-violation bugs) و باگهای نقض ترتیب (order-violation bugs) هستند [114].
یک باگ نقض یکپارچگی و غیرقابلتقسیم (atomicity-violation bug) ترتیبپذیری (serializability) مطلوبِ یک بخش از کد را نقض میکند. برای مثال، در Thread 1 در شکل ۸(a)، خط ۳ باید بعد از خط ۱ اجرا شود تا تابع fputs() با یک آرگومان معتبر فراخوانی شود. اما در Thread 2، خط ۲ قبل از خط ۳ در Thread 1 اجرا میشود. در نتیجه، مقدار p->info قبل از فراخوانی fputs() به NULL تنظیم میشود که باعث بروز خطا میگردد.
در مقابل، باگ نقض ترتیب (order-violation bug) زمانی رخ میدهد که دو (یا بیشتر) محل حافظه با ترتیب نادرست دسترسی شوند. برای نمونه، در شکل ۸(b)، دسترسی به mThd->State در Thread 2 قبل از مقداردهی اولیهی mThd در Thread 1 انجام میشود که خطایی از نوع استفاده از متغیر مقداردهینشده (use of uninitialized variables) ایجاد میکند.
باگهای همزمانی همچنین میتوانند منجر به نقضهای حافظهای شوند، مانند use-after-free و double-free [28]. یک راهحل برای کشف بنبستها (deadlock) این است که چرخهها در یک گراف ترتیب قفلها (lock order graph) شناسایی شوند، که در آن هر گره نمایانگر یک قفل است [4]. اگر در این گراف چرخهای وجود داشته باشد، یک بنبست بالقوه شناسایی میشود [90]. به منظور بهبود کارایی و مقیاسپذیری تشخیص چرخه، MagicFuzzer [27] به صورت تکراری قفلهایی را از گراف حذف میکند که در هیچ چرخهای حضور ندارند. سپس MagicFuzzer چرخههای باقیمانده را با استفاده از یک زمانبند تصادفی بررسی میکند.
ATOMFUZZER [144] در مورد نقضهای یکپارچگی و غیرقابلتقسیم (atomicity violations)، یک الگوی رایج باگ را مشاهده میکند که در آن یک قفل داخل یک بلوک اتمیک (atomicity -غیرقابلتقسیم) بهطور مکرر توسط دو رشته (thread) گرفته و آزاد میشود. بهطور مشخص، اگر یک رشته t داخل یک بلوک اتمیک قصد داشته باشد قفل L را بگیرد که قبلاً توسط همان رشته t گرفته و آزاد شده است، ATOMFUZZER اجرای رشته t را به تأخیر میاندازد و منتظر میماند تا رشته دیگری ′t قفل L را بگیرد. اگر در این فاصله، رشته ′t موفق به گرفتن قفل L شود، یک نقض اتمی بودن رخ داده است.
بهطور کلیتر، باگهای همزمانی به دلیل درهمتنیدگیهای نادرست (interleavings) بین رشتهها (threads) رخ میدهند. چالش اصلی این است که برنامههای همزمان ممکن است تعداد بسیار زیادی از این درهمتنیدگیها داشته باشند، بهطوریکه بررسی همه آنها عملاً غیرممکن است (که به آن مشکل انفجار حالت یا state-explosion گفته میشود).
CalFuzzer [166] این مشکل را با تکیه بر این واقعیت کاهش میدهد که برخی از درهمتنیدگیها معادل یکدیگر هستند، زیرا از ترتیبهای اجرایی متفاوت دستورالعملهایی بهوجود میآیند که با هم تعامل ندارند. این معادل بودن به این معناست که اجرای آنها به یک وضعیت نهایی یکسان منجر میشود.
CalFuzzer به صورت تصادفی مجموعهای از رشتهها را انتخاب میکند که دستورالعملهای بعدی آنها با یکدیگر تداخل ندارند و این دستورالعملها را بهطور همزمان اجرا میکند. به این ترتیب، CalFuzzer میتواند درهمتنیدگیهای مختلف را با کارایی بیشتری بررسی کند.
5.2.3 پیچیدگی الگوریتمی (Algorithmic Complexity)
آسیبپذیریهای پیچیدگی الگوریتم (AC) زمانی رخ میدهند که پیچیدگی بدترین حالت یک الگوریتم، عملکرد را به طور قابل توجهی کاهش میدهد، که میتواند منجر به حملات انکار سرویس (DoS) شود. شکل 9 مثالی را نشان میدهد که وقتی ورودیهای مختلفی به آرایه آرگومان داده میشود، الگوریتم پیچیدگیهای متفاوتی دارد. به عنوان مثال، اگر مقدار آرایه [8، 5، 3، 7، 9] باشد، الگوریتم، 37 خط کد (LOC) را اجرا میکند. از سوی دیگر، اگر آرایه [1، 5، 6، 7، 9] باشد، باعث اجرای 67 خط کد میشود. افزایش LOC به منابع محاسباتی بیشتری نیاز دارد. بنابراین، رفتار بدترین حالت میتواند توسط مهاجمان برای راهاندازی حمله DoS مورد سوء استفاده قرار گیرد.
بنابراین، SlowFuzz [152] با هدایت فازینگ به سمت اجراهایی که تعداد دستورالعملهای اجرا شده را افزایش میدهند، اشکالات AC را تشخیص میدهد. به طور مشابه، HotFuzz [15] با حداکثر کردن مصرف منابع روشهای منفرد، اشکالات AC را در روشهای جاوا تشخیص میدهد. MemLock [44] اشکالات AC را بر اساس هر دو معیار پوشش لبه و مصرف حافظه تشخیص میدهد. این الگوریتم، فازینگ را به سمت ورودیهایی هدایت میکند که میتوانند لبههای بیشتری را کشف کنند یا حافظه بیشتری مصرف کنند. فازرهای ذکر شده مستقیماً ورودیهای با بدترین عملکرد (WPI) را برای کشف اشکال AC تولید میکنند. در مقابل، Singularity [190] بر اساس مشاهده اینکه این WPIها همیشه از یک الگوی خاص پیروی میکنند، برنامهها را برای تولید ورودی ترکیب میکند.
5.2.4 باگهای نوع Spectre
باگ نوع Spectre یک حمله ریزمعماری است که از حدس و گمانهای شاخهای پیشبینی نشده برای کنترل دسترسیهای حافظه سوءاستفاده میکند [139]. به عنوان مثال، در شکل 10، یک مهاجم میتواند چندین مقدار ورودی را برای متغیر ورودی ارسال کند، که پیشبینیکننده شاخه را آموزش میدهد تا حدس بزند که آیا بررسی در خط 2 همیشه درست است یا خیر. هنگامی که مهاجم یک مقدار خارج از محدوده را برای ورودی ارسال میکند، پیشبینیکننده به طور نادرست رفتار شاخه را پیشبینی میکند و خطوط 3-4 به صورت حدس و گمان اجرا میشوند (یعنی بدون بررسی در خط 2 اجرا میشوند). از آنجایی که ورودی در واقع بررسی در خط 2 را برآورده نمیکند، اجرای خطوط 3-4 منجر به خواندن بیش از حد بافر میشود. بنابراین، ابزارهای SpecFuzz [139] برنامهها را برای شبیهسازی اجرای حدس و گمان هدف قرار میدهند، که میتواند مسیرهای کد پیشبینی نشده را به زور اجرا کند. سپس، هرگونه دسترسی نامعتبر به حافظه در مسیرهای پیشبینی نشده میتواند فعال شود.
5.2.5 باگهای کانال جانبی (Side-Channel Bugs)
اشکالات کانال جانبی از طریق مشاهده رفتارهای غیرعملکردی یک سیستم (مثلاً زمان اجرا) اطلاعات محرمانه را فاش میکنند. به عنوان مثال، اگر یک راز، متغیر a در عبارت “if (a > 0){…}else{…}” باشد، میتوان زمان اجرای شاخه then و شاخه else را مشاهده کرد تا مشخص شود که آیا مقدار a بزرگتر از صفر است یا خیر. نوع خاصی از کانالهای جانبی، کانالهای جانبی القا شده توسط JIT نامیده میشوند که توسط بهینهسازی Just-In-Time (JIT) ایجاد میشوند [25]. مشابه اشکالات نوع Spectre که در بالا ذکر شد، میتوان بارها و بارها برنامهها را برای آموزش کامپایلر JIT اجرا کرد تا زمان اجرای شاخه then یا شاخه else را بهینه کند. سپس، زمان اجرای شاخه آموزش دیده (مثلاً شاخه then) و شاخه آموزش ندیده (مثلاً شاخه else) به اندازهای بایاس میشوند که قابل مشاهده باشند. در نتیجه، مقدار محرمانه متغیر a فاش میشود.
۵.۲.۶ باگهای اعداد صحیح (Integer Bugs)
باگهای سرریز مثبت و منفی اعداد صحیح (Integer overflow/underflow bug) زمانی رخ میدهند که مقدار یک عبارت حسابی خارج از محدودهای باشد که توسط نوع ماشین تعیین میشود. از سوی دیگر، باگهای تبدیل اعداد صحیح زمانی رخ میدهند که یک نوع عدد صحیح به نوع عدد صحیح دیگری به اشتباه تبدیل شود. به منظور تشخیص باگهای اعداد صحیح، SmartFuzz [132] محدودیتهای خاصی را بر اساس باگهای مختلف اعداد صحیح به شبیهسازی نمادین اضافه میکند. سپس، حلکننده نمادین قصد دارد ورودیهای مشخصی تولید کند که ممکن است باگهای اعداد صحیح را فعال کند.
5.3 بهبود سرعت اجرا (Improvement of Execution Speed)
سرعت اجرا برای فازینگ حیاتی است زیرا فازینگ تعداد زیادی موراد آزمون را در یک بازه زمانی محدود اجرا میکند. هرچه سرعت اجرا بالاتر باشد، تعداد موارد آزمون بررسی شده بیشتر شده و شانس کشف نقصها افزایش مییابد. بنابراین، پژوهشگران تلاش زیادی برای بهبود سرعت اجرای فازینگ انجام دادهاند، از جمله تحلیل باینری [58, 134]، بهینهسازی فرآیندهای اجرا [46, 133, 204, 216] و تکنیکهای مخصوص برنامههای هدف [91, 162, 163, 174, 195, 196, 211].
5.3.1 تحلیل باینری (Binary Analysis)
فازینگ به عنوان یک پیشپردازش، عمدتاً از ابزارهای ابزارسنجی ایستا برای بهدست آوردن وضعیتهای اجرا استفاده میکند، زیرا ابزارسنجی ایستا سرعت اجرای بالایی برای فازینگ فراهم میکند [58, 134]. یکی از ابزارهای تحلیل استاتیک پرکاربرد LLVM [113] است که برنامهها را در زمان کامپایل ابزارسنجی میکند.
در مورد برنامههایی که منابع آنها باز و آزاد نیست، فازرها محدود به تحلیل باینری هستند [124]، زیرا کد منبع در دسترس نیست. مشکل این است که ابزارهای ابزارسنجی باینری (مانند Dyninst [128]) که در بسیاری از حوزهها موفق هستند (مثلاً شبیهسازی)، هنگام استفاده در فازینگ با سربار زمان اجرا مواجه میشوند.
برای بهبود سرعت اجرا و فراهم کردن عملکرد در سطح کامپایلر، RetroWrite [58] استفاده از تکنیکهای بازنویسی استاتیک باینری مبتنی بر اسمبلی قابل تجمیع را پیشنهاد میکند. این روش روی ابزارسنجی باینریهای ۶۴ بیتی مستقل از موقعیت (PIC) تمرکز دارد و از اطلاعات جابجایی PIC برای ابزارسنجی فایلهای اسمبلی استفاده میکند. سربار عملکرد کاهش مییابد زیرا RetroWrite میتواند قطعات کد درونخطی (inlined) را ابزارسنجی کند. هرچند سریع است، RetroWrite تنها از باینریهای ۶۴ بیتی PIC پشتیبانی میکند.
برای حفظ هر دو ویژگی سربار پایین زمان اجرا و مقیاسپذیری، FIBRE [134] ابزارسنجی را از طریق چهار فاز تغییر IR بهینه میکند. این چهار فاز برنامهها را با استفاده از بازنویسی استاتیک، درونخطیسازی، ردیابی زنده بودن رجیسترها و در نظر گرفتن قالبهای مختلف باینری (Binary format) ابزارسنجی میکنند.
تکنیکهای بازنویسی یادشده تنها یک بار باینریها را بازنویسی میکنند، که ممکن است منجر به بازنویسی نادرست باینری شود، بهویژه برای باینریهای stripped [189]. برای حل این مشکل، STOCHFUZZ [209] تکنیکهای بازنویسی تدریجی و تصادفی مبتنی بر این واقعیت پیشنهاد میکند که فازینگ برنامههای هدف را بهصورت تکراری اجرا میکند. بهطور مشخص، STOCHFUZZ باینریهای هدف را چندین بار بازنویسی میکند و بهتدریج مشکلات ایجادشده توسط بازنویسیهای قبلی را اصلاح میکند.
5.3.2 فرآیند اجرا (Execution Process)
سرعت اجرا همچنین میتواند در طول کمپین فازینگ بهبود یابد. UnTracer [133] مشاهده میکند که اغلب موارد آزمونی که در طول فازینگ تولید میشوند، پوشش جدیدی کشف نمیکنند. این نشان میدهد که دنبال کردن تمامی موارد آزمون، همانطور که AFL انجام میدهد، سربار زمان اجرای قابل توجهی ایجاد میکند. بنابراین، UnTracer تنها موارد آزمونهایی را دنبال میکند که پوشش جدید ایجاد میکنند تا سرعت اجرا افزایش یابد.
این کار با درج وقفهها در ابتدای بلاکهای پایه انجام میشود. وقتی یک بلاک بررسی شد، UnTracer ابزارسنجی آن بلاک را حذف میکند تا اجرای آینده در آن بلاک بدون وقفه ادامه یابد. از آنجا که پوشش بلاک اطلاعات وضعیت اجرای برنامه را از دست میدهد، CSI-Fuzz [216] از پوشش لبه برای بهبود UnTracer استفاده میکند. علاوه بر این، Zeror [213] با سوئیچ تطبیقی بین باینری ابزارسنجیشده توسط UnTracer و باینری ابزارسنجیشده توسط AFL، UnTracer را بهینه میکند.
5.3.3 برنامههای مختلف (Various Applications)
علاوه بر برنامههای عمومی، فازینگ همچنین برای کشف نقصها در اهدافی از زمینههای مختلف مانند دستگاههای IoT، کرنلهای سیستمعامل، و مانیتورهای ماشین مجازی (VMMها) استفاده میشود. از آنجایی که این اهداف معمولاً ویژگیهای خاصی دارند، فازینگ برای آنها سفارشیسازی میشود تا تستها به صورت مؤثر انجام شود. اگرچه شبیهسازی (emulation) رویکرد امیدوارکنندهای برای فازینگ فریمورهای IoT است، شبیهسازی کامل سیستم از طریق توان عملیاتی پایین محدود میشود. سربار زمان اجرای شبیهسازی کامل سیستم عمدتاً ناشی از ترجمه آدرسهای مجازی برای دسترسی به حافظه و شبیهسازی فراخوانیهای سیستم (system call) است. FIRM-AFL [211] این سربار را با ترکیب شبیهسازی در حالت کاربر (user-mode) و شبیهسازی کامل سیستم کاهش میدهد و بیشتر برنامهها را در شبیهسازی user-mode اجرا میکند.
برای فازینگ VMMها (یعنی هایپروایزرها)، Schumilo و همکاران [162, 163] یک سیستمعامل سفارشی و مکانیزم بازگردانی سریع snapshot طراحی کردهاند تا فازینگ بهصورت کارآمد انجام شود. در مورد فایلسیستمها، تغییر کل یک تصویر دیسک باعث کاهش قابل توجه توان عملیاتی فازینگ میشود زیرا اندازه تصویر بسیار بزرگ است. برای حل این مشکل، JANUS [196] تنها متادیتای تصویر بذر (seed) را تغییر میدهد؛ یعنی از ویژگیهای دادههای ساختیافته بهره میبرد. این راهحل فضای جستجوی ورودیها را کاهش میدهد و منجر به بهبود توان عملیاتی میشود.
کرنلهای سیستمعامل همچنین میتوانند از طریق یک دستگاه جانبی به خطر بیفتند؛ یعنی آسیبپذیریها در مرز سختافزار و سیستمعامل رخ میدهند. برای کشف نقصها در ارتباط بین دستگاه و درایور، PeriScope [174] پیشنهاد میکند که فازینگ بر اساس مکانیزم مدیریت page fault کرنل انجام شود.
برنامههای ویندوز با برنامههای لینوکس متفاوت هستند زیرا به شدت از رابطهای گرافیکی استفاده میکنند و ویندوز روشی برای کلون سریع فرآیندها ندارد. WINNIE [91] یک مهار (harness) ایجاد میکند تا برنامهها بدون رابط گرافیکی اجرا شوند. علاوه بر این، WINNIE تابع fork() را برای ویندوز پیادهسازی میکند تا فرآیندها بهصورت مؤثر کلون شوند.
BigFuzz [207] برنامههای محاسبات مقیاسپذیر و دادهمحور (DISC) را به یک برنامه معادل معنایی تبدیل میکند که مستقل از چارچوب DISC است. از آنجا که چارچوب DISC باعث تأخیر طولانی میشود، اجرای مستقل از چارچوب سرعت اجرای برنامه را بهطور قابل توجهی بهبود میبخشد.
شکاف ۳: اجرای خودکار برنامهها نیازمند درک دقیق و جامع از آن برنامهها است. هنگام طراحی شاخصها برای ثبت خودکار آسیبپذیریهای امنیتی، ابتدا باید ویژگیها و خصوصیات آن آسیبپذیریها مورد بررسی قرار گیرند.
۶. مسیر تحقیقات آینده (DIRECTIONS OF FUTURE RESEARCH)
فازیینگ توجه زیادی از جامعه پژوهشی به خود جلب کرده است و در دهههای اخیر هزاران باگ واقعی و آسیبپذیریهای جدی را کشف کرده است. در ادامه، چند مسیر تحقیقاتی آینده در حوزه فازیینگ را خلاصه میکنیم:
- معیارهای ارزیابی حساستر: پژوهشگران تلاشهای زیادی برای بهبود کارایی و اثربخشی پوشش کد، بهویژه حساسیت پوشش کد، انجام دادهاند (بخش ۳.۵.۱). اخیراً مشخص شده که پوشش کد محدودیتهایی در کشف باگهای پیچیده دارد. بنابراین، پژوهشگران پوشش کد را با معرفی اطلاعات اضافی (مثل مناطق کد خطرناک) که از تحلیل باگها بهدست آمده، گسترش دادهاند. کارهای آینده میتوانند با تحلیل باگها و شناسایی آنها بر اساس ویژگیهایشان، بهویژه باگهایی که از فازیینگ فعلی فرار میکنند، این رویکرد را توسعه دهند.
- تئوریهای پیشرفتهتر فازیینگ: تئوریهای کنونی فازیینگ تنها بخشی از فرایندهای فازیینگ را فرموله کردهاند (بخش ۳). اکثر کارهای موجود تمرکز خود را بر برنامهریزی بذرها (seed schedule) گذاشتهاند و تعداد کمی به سایر فرایندهای فازیینگ توجه کردهاند. با توجه به پیچیدگی فرایندهای فازیینگ، فرموله کردن کل فرایند فازیینگ کار سادهای نیست. با این حال، ممکن است بیش از یک فرایند فازیینگ مانند نظریه بازیها (Game Theory) فرموله شود که هم برنامهریزی بذرها و هم برنامهریزی بایتها (byte schedule) را در نظر بگیرد. یک چشمانداز بزرگتر، محدودیتهای نظری فازیینگ است (مثلاً محدودیت فازیینگ جعبه خاکستری یا greybox).
- از سوی دیگر، فرموله کردن فرایندهای فازیینگ با انواع مختلف معیار شایستگی یا ارزیابی کیفیت نیز راهی برای ایجاد تئوریهای پیشرفتهتر فازیینگ است. برای مثال، کارهای آینده میتوانند فرایندهای فازیینگ را با در نظر گرفتن همزمانی رخداد باگها و انتقالهای حالتها مدلسازی کنند.
ارزیابی صِحّتمند (Sound evaluation). چندین کار پژوهشی بر روی صِحّتمندی ارزیابی تمرکز کردهاند، اما هنوز نتیجهگیری قطعی در این زمینه ارائه نشده است (بخش ۳.۶). این مطالعات تنها پیشنهادهایی برای انجام ارزیابی صِحّتمند ارائه میدهند، مانند بودجه زمانی یا معیارهای ارزیابی. با این حال، پرسشهای بیشتری همچنان بدون پاسخ باقی ماندهاند. آیا باید برای مجموعهٔ ارزیابی از باگهای مصنوعی (synthesized bugs – باگهای ایجاد شده به صورت دستی) استفاده کنیم یا باگهای واقعی (real-world bugs)؟ آیا آزمونهای آماری (statistical tests) پاسخ نهایی برای تمایز بین دو تکنیک فازینگ هستند؟ یک بودجه زمانی معقول برای توقف فرایند فازینگ چقدر است؟ و چگونه باید برنامههای هدف خاص، مانند سختافزار، را زمانی که فازر مقایسهای وجود ندارد، ارزیابی کنیم؟
- استنتاج ورودیهای مقیاسپذیر (Scalable input inference): کارایی فازیینگ میتواند بهطور قابل توجهی افزایش یابد اگر در طول فازیینگ از قالببندی داده یا وابستگی دادهها استفاده شود (بخشهای ۴.۶ و ۴.۷). تحلیل ایستا (Static analysis) به طور گسترده برای استنتاج قالببندی و وابستگی داده استفاده میشود، اما تحلیل ایستا وابسته به برنامه است؛ یعنی پیادهسازی روشهای استنتاج باید ویژگیهای برنامههای مختلف را در نظر بگیرد. در حال حاضر، تحلیل پویا (Dynamic analysis) عمدتاً بر استنتاج قالببندی تمرکز دارد و تعداد کمی از کارها به استنتاج وابستگی داده پرداختهاند. روشهای استنتاج مبتنی بر تحلیل پویا میتوانند برای چندین برنامه استفاده شوند؛ یعنی تحلیل پویا مقیاسپذیرتر از تحلیل ایستا است. پژوهشهای آینده میتوانند بر استنتاج وابستگی داده بر اساس تحلیل پویا تمرکز کنند.
- عملگرهای جهش کارآمد (Efficient mutation operators): تقریباً همه فازرها در طول فازیینگ از جهشدهندههای ثابت استفاده میکنند. یعنی جهشدهندهها از قبل بر اساس ویژگیهای برنامه هدف طراحی شدهاند و در طول فرآیند فازیینگ تغییر نمیکنند (بخش ۴). تنها تعداد کمی از پژوهشها بر بهینهسازی برنامه زمانبندی جهشدهندهها تمرکز کردهاند، اما هیچ کاری به جهشدهندههای قابل تغییر نپرداخته است (بخش ۳.۴). آیا میتوان جهشدهندههای پویا طراحی کرد که در طول فازیینگ تغییر کنند و عملکرد را بهبود دهند؟ از آنجایی که برنامه زمانبندی جهشدهندهها به شدت با برنامه زمانبندی بایتها در تعامل است، طراحی جهشدهندهها با در نظر گرفتن برنامه بایت میتواند نویدبخش باشد. علاوه بر این، جهشدهندهها برای ورودیهای بسیار ساختاریافته ممکن است ویژگیهای متفاوتی نسبت به برنامههای عمومی داشته باشند، بنابراین برنامه زمانبندی جهشدهندهها برای ورودیهای ساختاریافته نیز ارزش مطالعه دارد.
- انواع بیشتر برنامهها (More types of applications): فازیینگ در کشف باگها در برنامههای خط فرمان موفقیت زیادی داشته است. پژوهشگران همچنین تلاشهای زیادی برای فازیینگ سایر انواع برنامهها انجام دادهاند (بخش ۵.۱). به دلیل پیچیدگی برنامههای مختلف، فازیینگ در عمل محدودیتهایی برای پوشش انواع بیشتر برنامهها دارد. برای مثال، تنها چند کار به امکان فازیینگ سیستمهای سایبر-فیزیکی پرداختهاند، اما قابلیت فازیینگ محدود است [41, 179]. از آنجا که سرعت اجرا برای فازیینگ حیاتی است، یک مسیر احتمالی برای برنامههای سختفازی (hard-fuzzing) افزایش سرعت اجرای آنها است.
- انواع بیشتر باگها (More types of bugs): فازیینگ تاکنون در شناسایی باگهایی مانند نقض حافظه، باگهای همزمانی یا باگهای پیچیدگی الگوریتمی موفق بوده است (بخش ۵.۲). با این حال، در شناسایی بسیاری از انواع دیگر باگها، مانند افزایش سطح دسترسی (privilege escalation) یا باگهای منطقی، با دشواری مواجه است. چالش اصلی، طراحی شاخصهای مناسب برای این باگهاست تا بتوان آنها را بهصورت خودکار در طول فازیینگ ثبت کرد.
- از آنجا که این شاخصها بازتابدهنده ویژگیهای باگهای مربوطه هستند، طراحی آنها نیازمند درک عمیق از هر دو حوزه فازیینگ و نوع باگ هدف است. برای مثال، برنامهها حتی در صورت وقوع باگهای منطقی ممکن است بدون هیچ خطا یا استثنایی اجرا شوند. بنابراین، برای طراحی شاخصهای خودکار برای باگهای منطقی، نیاز به درک عمیق از نیازمندیهای عملکردیای است که کد بر اساس آنها توسعه یافته است.
پاورقی
[1] Internet of Things
[2] Computer and Communications Security
[3] Network and Distributed System Security Symposium
[4] Security and Privacy
[5] Usenix Security Symposium
[6] Automated Software Engineering
[7] International Conference on Software Engineering
[8] Foundation of Software Engineering/European Software Engineering Conference
[9] Program Under Test
[10] minimal set cover problem
[11] Integer Linear Programming Problem
[12] Weighted Coupon Collector’s Problem
[13] Variant of the Adversarial Multi-armed Bandit Model
[14] deep learning
[15] Particle Swarm Optimization
[16] abstract syntax tree
[17] Recurrent neural network
منابع
[1] Yousra Aafer, Wei You, Yi Sun, Yu Shi, Xiangyu Zhang, and Heng Yin. 2021. Android SmartTVs vulnerability discovery via log-guided fuzzing. In 30th USENIX Security Symposium (USENIX Security’21). 2759–2776.
[2] Humberto Abdelnur, Radu State, Obes Jorge Lucangeli, and Olivier Festor. 2010. Spectral Fuzzing: Evaluation & Feedback. Technical Report. https://hal.inria.fr/inria-00452015.
[3] Humberto J. Abdelnur, Radu State, and Olivier Festor. 2007. KiF: A stateful SIP fuzzer. In Proceedings of the 1st International Conference on Principles, Systems and Applications of IP Telecommunications (Iptcomm’07). 47–56.
[4] Rahul Agarwal, Liqiang Wang, and Scott D. Stoller. 2005. Detecting potential deadlocks with static analysis and run-time monitoring. In Haifa Verification Conference. Springer, 191–207.
[5] Cornelius Aschermann, Patrick Jauernig, Tommaso Frassetto, Ahmad-Reza Sadeghi, Thorsten Holz, and Daniel Teuchert. 2019. NAUTILUS: Fishing for deep bugs with grammars. In The Network and Distributed System Security Symposium (NDSS’19). 1–15.
[6] C. Aschermann, S. Schumilo, A. Abbasi, and T. Holz. 2020. IJON: Exploring deep state spaces via fuzzing. In IEEE Symposium on Security and Privacy (S&P’20). IEEE Computer Society, Los Alamitos, CA, 874–889.
[7] Cornelius Aschermann, Sergej Schumilo, Tim Blazytko, Robert Gawlik, and Thorsten Holz. 2019. REDQUEEN: Fuzzing with input-to-state correspondence. In The Network and Distributed System Security Symposium (NDSS’19). 1–15.
[8] Vaggelis Atlidakis, Patrice Godefroid, and Marina Polishchuk. 2019. RESTler: Stateful REST API fuzzing. In 2019 IEEE/ACM 41st International Conference on Software Engineering (ICSE’19). IEEE, 748–758.
[9] Peter Auer, Nicolo Cesa-Bianchi, and Paul Fischer. 2002. Finite-time analysis of the multiarmed bandit problem. Machine Learning 47, 2 (2002), 235–256.
[10] Domagoj Babić, Stefan Bucur, Yaohui Chen, Franjo Ivančić, Tim King, Markus Kusano, Caroline Lemieux, László Szekeres, and Wei Wang. 2019. Fudge: Fuzz driver generation at scale. In Proceedings of the 2019 27th ACM Joint Meeting on European Software Engineering Conference and Symposium on the Foundations of Software Engineering (ESEC/FSE’19). 975–985.
[11] Greg Banks, Marco Cova, Viktoria Felmetsger, Kevin Almeroth, Richard Kemmerer, and Giovanni Vigna. 2006. SNOOZE: Toward a stateful network protocol fuzzer. In International Conference on Information Security. Springer, 343–358.
[12] Osbert Bastani, Rahul Sharma, Alex Aiken, and Percy Liang. 2017. Synthesizing program input grammars. In Proceedings of the 38th ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI’17). 95–110.
[13] Petra Berenbrink and Thomas Sauerwald. 2009. The weighted coupon collector’s problem and applications. In International Computing and Combinatorics Conference. Springer, 449–458.
[14] Donald A. Berry and Bert Fristedt. 1985. Bandit Problems: Sequential Allocation of Experiments (Monographs on Statistics and Applied Probability). London: Chapman and Hall, 5, 7 (1985), 71–87.
[15] William Blair, Andrea Mambretti, Sajjad Arshad, Michael Weissbacher, William Robertson, Engin Kirda, and Manuel Egele. 2020. HotFuzz: Discovering algorithmic denial-of-service vulnerabilities through guided micro-fuzzing. In The Network and Distributed System Security Symposium (NDSS’20). 1–19.
[16] Tim Blazytko, Cornelius Aschermann, Moritz Schlögel, Ali Abbasi, Sergej Schumilo, Simon Wörner, and Thorsten Holz. 2019. GRIMOIRE: Synthesizing structure while fuzzing. In 28th USENIX Security Symposium (USENIX Security’19). 1985–2002.
[17] Marcel Böhme. 2018. STADS: Software testing as species discovery. ACM Transactions on Software Engineering and Methodology (TOSEM) 27, 2 (2018), 1–52.
[18] Marcel Böhme, Cristian Cadar, and Abhik Roychoudhury. 2020. Fuzzing: Challenges and reflections. IEEE Software 38, 3 (2020), 79–86.
[19] Marcel Böhme and Brandon Falk. 2020. Fuzzing: On the exponential cost of vulnerability discovery. In Proceedings of the 28th ACM Joint Meeting on European Software Engineering Conference and Symposium on the Foundations of Software Engineering (ESEC/FSE’20). 713–724.
[20] Marcel Böhme, Danushka Liyanage, and Valentin Wüstholz. 2021. Estimating residual risk in greybox fuzzing. In ACM European Software Engineering Conference and Symposium on the Foundations of Software Engineering (ESEC/FSE’21). 230–241.
[21] Marcel Böhme, Valentin J. M. Manès, and Sang Kil Cha. 2020. Boosting fuzzer efficiency: An information theoretic perspective. In Proceedings of the 28th ACM Joint Meeting on European Software Engineering Conference and Symposium on the Foundations of Software Engineering (ESEC/FSE’20). 678–689.
[22] Marcel Böhme, Van-Thuan Pham, Manh-Dung Nguyen, and Abhik Roychoudhury. 2017. Directed greybox fuzzing. In The ACM Conference on Computer and Communications Security (CCS’17). ACM, 2329–2344.
[23] Marcel Böhme, Van-Thuan Pham, and Abhik Roychoudhury. 2016. Coverage-based greybox fuzzing as Markov chain. In The ACM Conference on Computer and Communications Security (CCS’16). ACM, 1032–1043.
[24] Luca Borzacchiello, Emilio Coppa, and Camil Demetrescu. 2021. Fuzzing symbolic expressions. In 2021 IEEE/ACM 43rd International Conference on Software Engineering (ICSE’21). IEEE, 711–722.
[25] Tegan Brennan, Seemanta Saha, and Tevfik Bultan. 2020. JVM fuzzing for JIT-induced side-channel detection. In Proceedings of the ACM/IEEE 42nd International Conference on Software Engineering (ICSE’20). 1011–1023.
[26] Chad Brubaker, Suman Jana, Baishakhi Ray, Sarfraz Khurshid, and Vitaly Shmatikov. 2014. Using frankencerts for automated adversarial testing of certificate validation in SSL/TLS implementations. In IEEE Symposium on Security and Privacy (S&P’14). IEEE, 114–129.
[27] Yan Cai and W. K. Chan. 2012. MagicFuzzer: Scalable deadlock detection for large-scale applications. In 2012 34th International Conference on Software Engineering (ICSE’12). IEEE, 606–616.
[28] Yan Cai, Biyun Zhu, Ruijie Meng, Hao Yun, Liang He, Purui Su, and Bin Liang. 2019. Detecting concurrency memory corruption vulnerabilities. In Proceedings of the 2019 27th ACM Joint Meeting on European Software Engineering Conference and Symposium on the Foundations of Software Engineering (ESEC/FSE’19). 706–717.
[29] Sang Kil Cha, Maverick Woo, and David Brumley. 2015. Program-adaptive mutational fuzzing. In IEEE Symposium on Security and Privacy (S&P’15). IEEE, 725–741.
[30] Oliver Chang, Jonathan Metzman, Max Moroz, Martin Barbella, and Abhishek Arya. 2016. OSS-Fuzz: Continuous Fuzzing for Open Source Software. Retrieved January 19, 2021, from https://github.com/google/oss-fuzz.
[31] Anne Chao and Chun-Huo Chiu. 2016. Species richness: Estimation and comparison. Wiley StatsRef: Statistics Reference Online, 26.
[32] Anne Chao and Robert K. Colwell. 2017. Thirty years of progeny from Chao’s inequality: Estimating and comparing richness with incidence data and incomplete sampling. SORT-Statistics and Operations Research Transactions Vol. 1 (2017), 3–54.
[33] Anne Chao and Lou Jost. 2012. Coverage-based rarefaction and extrapolation: Standardizing samples by completeness rather than size. Ecology 93, 12 (2012), 2533–2547.
[34] Daming D. Chen, Maverick Woo, David Brumley, and Manuel Egele. 2016. Towards automated dynamic analysis for linux-based embedded firmware. In The Network and Distributed System Security Symposium (NDSS’16), Vol. 1. 1–16.
[35] Hongxu Chen, Shengjian Guo, Yinxing Xue, Yulei Sui, Cen Zhang, Yuekang Li, Haijun Wang, and Yang Liu. 2020. MUZZ: Thread-aware grey-box fuzzing for effective bug hunting in multithreaded programs. In 29th USENIX Security Symposium (USENIX Security’20). 2325–2342.
[36] Jiongyi Chen, Wenrui Diao, Qingchuan Zhao, Chaoshun Zuo, Zhiqiang Lin, Xiao Feng Wang, Wing Cheong Lau, et al. 2018. IoTFUZZER: Discovering memory corruptions in IoT through app-based fuzzing. In The Network and Distributed System Security Symposium (NDSS’18). 1–15.
[37] Peng Chen and Hao Chen. 2018. Angora: Efficient fuzzing by principled search. In IEEE Symposium on Security and Privacy (S&P’18). 711–725.
[38] Peng Chen, Jianzhong Liu, and Hao Chen. 2019. Matryoshka: Fuzzing deeply nested branches. In The ACM Conference on Computer and Communications Security (CCS’19). 499–513.
[39] Yuanliang Chen, Yu Jiang, Fuchen Ma, Jie Liang, Mingzhe Wang, Chijin Zhou, Xun Jiao, and Zhuo Su. 2019. EnFuzz: Ensemble fuzzing with seed synchronization among diverse fuzzers. In 28th USENIX Security Symposium (USENIX Security’19). 1967–1983.
[40] Yaohui Chen, Peng Li, Jun Xu, Shengjian Guo, Rundong Zhou, Yulong Zhang, Tao Wei, et al. 2020. SAVIOR: Towards bug-driven hybrid testing. In IEEE Symposium on Security and Privacy (S&P’20). IEEE Computer Society, Los Alamitos, CA, 1580–1596.
[41] Yuqi Chen, Christopher M. Poskitt, Jun Sun, Sridhar Adepu, and Fan Zhang. 2019. Learning-guided network fuzzing for testing cyber-physical system defences. In 2019 34th IEEE/ACM International Conference on Automated Software Engineering (ASE’19). IEEE, 962–973.
[42] Yuting Chen, Ting Su, Chengnian Sun, Zhendong Su, and Jianjun Zhao. 2016. Coverage-directed differential testing of JVM implementations. In Proceedings of the 37th ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI’16). 85–99.
[43] Yongheng Chen, Rui Zhong, Hong Hu, Hangfan Zhang, Yupeng Yang, Dinghao Wu, and Wenke Lee. 2021. One engine to Fuzz’em all: Generic language processor testing with semantic validation. In IEEE Symposium on Security and Privacy (S&P’21). 1–17.
[44] Wen Cheng, Wang Haijun, Li Yuekang, Qin Shengchao, Liu Yang, Xu Zhiwu, Chen Hongxu, et al. 2020. MemLock: Memory usage guided fuzzing. In IEEE/ACM 42nd International Conference on Software Engineering (ICSE’20). 765–777.
[45] Siddhartha Chib and Edward Greenberg. 1995. Understanding the metropolis-hastings algorithm. American Statistician 49, 4 (1995), 327–335.
[46] Mingi Cho, Seoyoung Kim, and Taekyoung Kwon. 2019. Intriguer: Field-level constraint solving for hybrid fuzzing. In The ACM Conference on Computer and Communications Security (CCS’19). 515–530.
[47] Jaeseung Choi, Joonun Jang, Choongwoo Han, and Sang Kil Cha. 2019. Grey-box concolic testing on binary code. In 2019 IEEE/ACM 41st International Conference on Software Engineering (ICSE’19). IEEE, 736–747.
[48] Maria Christakis, Peter Müller, and Valentin Wüstholz. 2016. Guiding dynamic symbolic execution toward unverified program executions. In Proceedings of the 38th International Conference on Software Engineering (ICSE’16). 144–155.
[49] Alessandro Cimatti, Alberto Griggio, Bastiaan Joost Schaafsma, and Roberto Sebastiani. 2013. The mathsat5 SMT solver. In International Conference on Tools and Algorithms for the Construction and Analysis of Systems (TACAS’13). Springer, 93–107.
[50] Koen Claessen and John Hughes. 2000. QuickCheck: A lightweight tool for random testing of Haskell programs. In Proceedings of the 5th ACM SIGPLAN International Conference on Functional Programming (ICFP’00). 268–279.
[51] James Clause, Wanchun Li, and Alessandro Orso. 2007. Dytan: A generic dynamic taint analysis framework. In Proceedings of the 2007 International Symposium on Software Testing and Analysis (ISSTA’07). 196–206.
[52] Robert K. Colwell, Anne Chao, Nicholas J. Gotelli, Shang-Yi Lin, Chang Xuan Mao, Robin L. Chazdon, and John T. Longino. 2012. Models and estimators linking individual-based and sample-based rarefaction, extrapolation and comparison of assemblages. Journal of Plant Ecology 5, 1 (2012), 3–21.
[53] Jake Corina, Aravind Machiry, Christopher Salls, Yan Shoshitaishvili, Shuang Hao, Christopher Kruegel, and Giovanni Vigna. 2017. Difuze: Interface aware fuzzing for kernel drivers. In The ACM Conference on Computer and Communications Security (CCS’17). ACM, 2123–2138.
[54] Leonardo De Moura and Nikolaj Bjørner. 2008. Z3: An efficient SMT solver. In International Conference on Tools and Algorithms for the Construction and Analysis of Systems (TACAS’08). Springer, 337–340.
[55] Joeri De Ruiter and Erik Poll. 2015. Protocol state fuzzing of TLS implementations. In 24th USENIX Security Symposium (USENIX Security’15). 193–206.
[56] Kyle Dewey, Jared Roesch, and Ben Hardekopf. 2014. Language fuzzing using constraint logic programming. In Proceedings of the 29th ACM/IEEE International Conference on Automated Software Engineering (ASE’14). 725–730.
[57] Kyle Dewey, Jared Roesch, and Ben Hardekopf. 2015. Fuzzing the Rust typechecker using CLP. In 2015 30th IEEE/ACM International Conference on Automated Software Engineering (ASE’15). IEEE, 482–493.
[58] Sushant Dinesh, Nathan Burow, Dongyan Xu, and Mathias Payer. 2020. Retrowrite: Statically instrumenting cots binaries for fuzzing and sanitization. In 2020 IEEE Symposium on Security and Privacy (S&P’20). IEEE, 1497–1511.
[59] Sung Ta Dinh, Haehyun Cho, Kyle Martin, Adam Oest, Kyle Zeng, Alexandros Kapravelos, Gail-Joon Ahn, et al. 2021. Favocado: Fuzzing the binding code of Javascript engines using semantically correct test cases. In The Network and Distributed System Security Symposium (NDSS’21). 1–15.
[60] Marco Dorigo, Mauro Birattari, and Thomas Stutzle. 2006. Ant colony optimization. IEEE Computational Intelligence Magazine 1, 4 (2006), 28–39.
[61] Adam Doupé, Ludovico Cavedon, Christopher Kruegel, and Giovanni Vigna. 2012. Enemy of the state: A state-aware black-box web vulnerability scanner. In 21st USENIX Security Symposium (USENIX Security’12). 523–538.
[62] Shawn Embleton, Sherri Sparks, and Ryan Cunningham. 2006. Sidewinder: An evolutionary guidance system for malicious input crafting. Black Hat USA.
[63] Xiaotao Feng, Ruoxi Sun, Xiaogang Zhu, Minhui Xue, Sheng Wen, Dongxi Liu, Surya Nepal, and Yang Xiang. 2021. Snipuzz: Black-box fuzzing of IoT firmware via message snippet inference. InThe ACM Conference on Computer and Communications Security (CCS’21), 337–350.
[64] Paul Fiterau-Brostean, Bengt Jonsson, Robert Merget, Joeri de Ruiter, Konstantinos Sagonas, and Juraj Somorovsky. 2020. Analysis of DTLS implementations using protocol state fuzzing. In 29th USENIX Security Symposium (USENIX Security’20). 2523–2540.
[65] Shuitao Gan, Chao Zhang, Peng Chen, Bodong Zhao, Xiaojun Qin, Dong Wu, and Zuoning Chen. 2020. GREYONE: Data flow sensitive fuzzing. In 29th USENIX Security Symposium (USENIX Security’20). 2577–2594.
[66] Shuitao Gan, Chao Zhang, Xiaojun Qin, Xuwen Tu, Kang Li, Zhongyu Pei, and Zuoning Chen. 2018. CollAFL: Path sensitive fuzzing. In IEEE Symposium on Security and Privacy (S&P’18). IEEE, 679–696.
[67] Vijay Ganesh, Tim Leek, and Martin Rinard. 2009. Taint-based directed whitebox fuzzing. In Proceedings of the 31st International Conference on Software Engineering. IEEE Computer Society, 474–484.
[68] Xiang Gao, Ripon K. Saha, Mukul R. Prasad, and Abhik Roychoudhury. 2020. Fuzz testing based data augmentation to improve robustness of deep neural networks. In 2020 IEEE/ACM 42nd International Conference on Software Engineering (ICSE’20). IEEE, 1147–1158.
[69] Hugo Gascon, Christian Wressnegger, Fabian Yamaguchi, Daniel Arp, and Konrad Rieck. 2015. Pulsar: Stateful black-box fuzzing of proprietary network protocols. In International Conference on Security and Privacy in Communication Systems (SecureComm’15). Springer, 330–347.
[70] Patrice Godefroid, Bo-Yuan Huang, and Marina Polishchuk. 2020. Intelligent REST API data fuzzing. In Proceedings of the 28th ACM Joint Meeting on European Software Engineering Conference and Symposium on the Foundations of Software Engineering (ESEC/FSE’20). 725–736.
[71] Patrice Godefroid, Adam Kiezun, and Michael Y. Levin. 2008. Grammar-based whitebox fuzzing. In Proceedings of the 29th ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI’08). ACM, 206–215.
[72] Patrice Godefroid, Nils Klarlund, and Koushik Sen. 2005. DART: Directed automated random testing. In Proceedings of the 2005 ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI’05). 213–223.
[73] Patrice Godefroid, Michael Y. Levin, and David A. Molnar. 2008. Automated whitebox fuzz testing. In The Network and Distributed System Security Symposium (NDSS’08), Vol. 8. 151–166.
[74] Patrice Godefroid, Hila Peleg, and Rishabh Singh. 2017. Learn&fuzz: Machine learning for input fuzzing. In Proceedings of the 32nd IEEE/ACM International Conference on Automated Software Engineering (ASE’17). IEEE Press, 50–59.
[75] Gustavo Grieco, Martín Ceresa, and Pablo Buiras. 2016. QuickFuzz: An automatic random fuzzer for common file formats. In Proceedings of the 9th International Symposium on Haskell (Haskell’16). 13–20.
[76] Istvan Haller, Asia Slowinska, Matthias Neugschwandtner, and Herbert Bos. 2013. Dowsing for overflows: A guided fuzzer to find buffer boundary violations. In USENIX Security Symposium. 49–64.
[77] HyungSeok Han and Sang Kil Cha. 2017. IMF: Inferred model-based fuzzer. In The ACM Conference on Computer and Communications Security (CCS’17). ACM, 2345–2358.
[78] HyungSeok Han, DongHyeon Oh, and Sang Kil Cha. 2019. CodeAlchemist: Semantics-aware code generation to find vulnerabilities in Javascript engines. In The Network and Distributed System Security Symposium (NDSS’19). 1–15.
[79] Jingxuan He, Mislav Balunović, Nodar Ambroladze, Petar Tsankov, and Martin Vechev. 2019. Learning to fuzz from symbolic execution with application to smart contracts. In The ACM Conference on Computer and Communications Security (CCS’19). 531–548.
[80] Christian Holler, Kim Herzig, and Andreas Zeller. 2012. Fuzzing with code fragments. In 21st USENIX Security Symposium (USENIX Security’12). 445–458.
[81] H. Huang, P. Yao, R. Wu, Q. Shi, and C. Zhang. 2020. Pangolin: Incremental hybrid fuzzing with polyhedral path abstraction. In IEEE Symposium on Security and Privacy (S&P’20). IEEE Computer Society, Los Alamitos, CA, 1144–1158.
[82] Kim Hyungsub, Ozmen Muslum Ozgur, Bianchi Antonio, Celik Z. Berkay, and Xu Dongyan. 2021. PGFUZZ: Policy-guided fuzzing for robotic vehicles. In The Network and Distributed System Security Symposium (NDSS’21). 1–18.
[83] Kyriakos K. Ispoglou, Daniel Austin, Vishwath Mohan, and Mathias Payer. 2020. FuzzGen: Automatic fuzzer generation. In 29th USENIX Security Symposium (USENIX Security’20). 2271–2287.
[84] Dae R. Jeong, Kyungtae Kim, Basavesh Shivakumar, Byoungyoung Lee, and Insik Shin. 2019. Razzer: Finding kernel race bugs through fuzzing. In IEEE Symposium on Security and Privacy (S&P’19). IEEE, 754–768.
[85] jfoote. 2020. The exploitable GDB plugin. Retrieved February 7, 2020, from https://github.com/jfoote/exploitable.
[86] Bo Jiang, Ye Liu, and W. K. Chan. 2018. Contractfuzzer: Fuzzing smart contracts for vulnerability detection. In 2018 33rd IEEE/ACM International Conference on Automated Software Engineering (ASE’18). IEEE, 259–269.
[87] Zu-Ming Jiang, Jia-Ju Bai, Kangjie Lu, and Shi-Min Hu. 2020. Fuzzing error handling code using context-sensitive software fault injection. In 29th USENIX Security Symposium (USENIX Security’20). USENIX Association, 2595–2612.
[88] Wang Jinghan, Song Chengyu, and Heng Yin. 2021. Reinforcement learning-based hierarchical seed scheduling for greybox fuzzing. In The Network and Distributed System Security Symposium (NDSS’21). 1–17.
[89] William Johansson, Martin Svensson, Ulf E. Larson, Magnus Almgren, and Vincenzo Gulisano. 2014. T-Fuzz: Model-based fuzzing for robustness testing of telecommunication protocols. In 2014 IEEE 7th International Conference on Software Testing, Verification and Validation (ICST’14). IEEE, 323–332.
[90] Pallavi Joshi, Chang-Seo Park, Koushik Sen, and Mayur Naik. 2009. A randomized dynamic program analysis technique for detecting real deadlocks. In Proceedings of the 30th ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI’09). 110–120.
[91] Jinho Jung, Stephen Tong, Hong Hu, Jungwon Lim, Yonghwi Jin, and Taesoo Kim. 2021. WINNIE: Fuzzing windows applications with harness synthesis and fast cloning. In The Network and Distributed System Security Symposium (NDSS’21). 1–17.
[92] 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 (ESEC/FSE’15). ACM, 782–792.
[93] John G. Kemeny and J. Laurie Snell. 1976. Markov Chains, Vol. 6. Springer-Verlag, New York.
[94] James Kennedy and Russell Eberhart. 1995. Particle swarm optimization. In Proceedings of International Conference on Neural Networks (ICNN’95), Vol. 4. IEEE, 1942–1948.
[95] Kyungtae Kim, Dae R. Jeong, Chung Hwan Kim, Yeongjin Jang, Insik Shin, and Byoungyoung Lee. 2020. HFL: Hybrid fuzzing on the Linux kernel. In The Network and Distributed System Security Symposium (NDSS’20). 1–17.
[96] George Klees, Andrew Ruef, Benji Cooper, Shiyi Wei, and Michael Hicks. 2018. Evaluating fuzz testing. In Proceedings of the 2018 ACM SIGSAC Conference on Computer and Communications Security (CCS’18). ACM, 2123–2138.
[97] Zhifeng Lai, Shing-Chi Cheung, and Wing Kwong Chan. 2010. Detecting atomic-set serializability violations in multi- threaded programs through active randomized testing. In Proceedings of the 32nd ACM/IEEE International Conference on Software Engineering (ICSE’10). 235–244.
[98] Gwangmu Lee, Woochul Shim, and Byoungyoung Lee. 2021. Constraint-guided directed greybox fuzzing. In 30th USENIX Security Symposium (USENIX Security’21). 1–18.
[99] Suyoung Lee, HyungSeok Han, Sang Kil Cha, and Sooel Son. 2020. Montage: A neural network language model guided Javascript engine fuzzer. In 29th USENIX Security Symposium (USENIX Security’20). USENIX Association, 1–18.
[100] Seungsoo Lee, Changhoon Yoon, Chanhee Lee, Seungwon Shin, Vinod Yegneswaran, and Phillip A. Porras. 2017. DELTA: A security assessment framework for software-defined networks. In The Network and Distributed System Security Symposium (NDSS’17). 1–15.
[101] Caroline Lemieux and Koushik Sen. 2018. Fairfuzz: A targeted mutation strategy for increasing greybox fuzz testing coverage. In Proceedings of the 33rd ACM/IEEE International Conference on Automated Software Engineering (ASE’18). 475–485.
[102] Jun Li, Bodong Zhao, and Chao Zhang. 2018. Fuzzing: A survey. Cybersecurity 1, 1 (2018), 1–13.
[103] Yuekang Li, Bihuan Chen, Mahinthan Chandramohan, Shang-Wei Lin, Yang Liu, and Alwen Tiu. 2017. Steelix: Program-state based binary fuzzing. In Proceedings of the 2017 12th Joint Meeting on Foundations of Software Engineering (ESEC/FSE’17). ACM, 627–637.
[104] Yuwei Li, Shouling Ji, Yuan Chen, Sizhuang Liang, Wei-Han Lee, Yueyao Chen, Chenyang Lyu, et al. 2021. UniFuzz: A holistic and pragmatic metrics-driven platform for evaluating fuzzers. In 30th USENIX Security Symposium (USENIX Security’21). 1–18.
[105] Yuekang Li, Yinxing Xue, Hongxu Chen, Xiuheng Wu, Cen Zhang, Xiaofei Xie, Haijun Wang, and Yang Liu. 2019. Cerebro: Context-aware adaptive fuzzing for effective vulnerability detection. In Proceedings of the 2019 27th ACM Joint Meeting on European Software Engineering Conference and Symposium on the Foundations of Software Engineering (ESEC/FSE’19). 533–544.
[106] Chieh-Jan Mike Liang, Nicholas D. Lane, Niels Brouwers, Li Zhang, Börje F. Karlsson, Hao Liu, Yan Liu, Jun Tang, Xiang Shan, Ranveer Chandra, et al. 2014. Caiipa: Automated large-scale mobile app testing through contextual fuzzing. In Proceedings of the 20th Annual International Conference on Mobile Computing and Networking (MobiCom’14). 519–530.
[107] Hongliang Liang, Xiaoxiao Pei, Xiaodong Jia, Wuwei Shen, and Jian Zhang. 2018. Fuzzing: State of the art. IEEE Transactions on Reliability 67, 3 (2018), 1199–1218.
[108] Daniel Liew, Cristian Cadar, Alastair F. Donaldson, and J. Ryan Stinnett. 2019. Just fuzz it: Solving floating-point constraints using coverage-guided fuzzing. In Proceedings of the 2019 27th ACM Joint Meeting on European Software Engineering Conference and Symposium on the Foundations of Software Engineering (ESEC/FSE’19). 521–532.
[109] Guanjun Lin, Sheng Wen, Qing-Long Han, Jun Zhang, and Yang Xiang. 2020. Software vulnerability detection using deep neural networks: A survey. Proceedings of the IEEE 108, 10 (2020), 1825–1848.
[110] Baozheng Liu, Chao Zhang, Guang Gong, Yishun Zeng, Haifeng Ruan, and Jianwei Zhuge. 2020. FANS: Fuzzing Android native system services via automated interface analysis. In 29th USENIX Security Symposium (USENIX Security’20). USENIX Association, 307–323.
[111] Peng Liu, Xiangyu Zhang, Marco Pistoia, Yunhui Zheng, Manoel Marques, and Lingfei Zeng. 2017. Automatic text input generation for mobile testing. In 2017 IEEE/ACM 39th International Conference on Software Engineering (ICSE’17). IEEE, 643–653.
[112] Xiao Liu, Xiaoting Li, Rupesh Prajapati, and Dinghao Wu. 2019. Deepfuzz: Automatic generation of syntax valid C programs for fuzz testing. In Proceedings of the AAAI Conference on Artificial Intelligence, Vol. 33. 1044–1051.
[113] LLVM. 2021. The LLVM Compiler Infrastructure. Retrieved March 2021 from https://llvm.org/.
[114] Shan Lu, Soyeon Park, Eunsoo Seo, and Yuanyuan Zhou. 2008. Learning from mistakes: A comprehensive study on real world concurrency bug characteristics. In Proceedings of the 13th International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS’08). 329–339.
[115] Weisi Luo, Dong Chai, Xiaoyue Run, Jiang Wang, Chunrong Fang, and Zhenyu Chen. 2021. Graph-based fuzz testing for deep learning inference engines. In 2021 IEEE/ACM 43rd International Conference on Software Engineering (ICSE’21). IEEE, 288–299.
[116] Chenyang Lyu, Shouling Ji, Chao Zhang, Yuwei Li, Wei-Han Lee, and Yu Song. 2019. MOPT: Optimized mutation scheduling for fuzzers. In 28th USENIX Security Symposium (USENIX Security’19). USENIX Association, 1949–1966.
[117] Lei Ma, Cyrille Artho, Cheng Zhang, Hiroyuki Sato, Johannes Gmeiner, and Rudolf Ramler. 2015. GRT: Program analysis-guided random testing (t). In 2015 30th IEEE/ACM International Conference on Automated Software Engineering (ASE’15). IEEE, 212–223.
[118] Valentin J. M. Manès, Soomin Kim, and Sang Kil Cha. 2020. Ankou: Guiding grey-box fuzzing towards combinatorial difference. In Proceedings of the ACM/IEEE 42nd International Conference on Software Engineering (ICSE’20). 1024–1036.
[119] Valentin Jean Marie Manès, HyungSeok Han, Choongwoo Han, Sang Kil Cha, Manuel Egele, Edward J. Schwartz, and Maverick Woo. 2019. The art, science, and engineering of fuzzing: A survey. IEEE Transactions on Software Engineering 47 (2019), 2312–2331.
[120] Muhammad Numair Mansur, Maria Christakis, Valentin Wüstholz, and Fuyuan Zhang. 2020. Detecting critical bugs in SMT solvers using blackbox mutational fuzzing. In Proceedings of the 28th ACM Joint Meeting on European Software Engineering Conference and Symposium on the Foundations of Software Engineering (ESEC/FSE’20). 701–712.
[121] Ke Mao, Mark Harman, and Yue Jia. 2016. Sapienz: Multi-objective automated testing for android applications. In Proceedings of the 25th International Symposium on Software Testing and Analysis (ISSTA’16). 94–105.
[122] Paul Dan Marinescu and Cristian Cadar. 2013. KATCH: High-coverage testing of software patches. In Proceedings of the 2013 9th Joint Meeting on Foundations of Software Engineering (ESEC/FSE’13). 235–245.
[123] Björn Mathis, Vitalii Avdiienko, Ezekiel O. Soremekun, Marcel Böhme, and Andreas Zeller. 2017. Detecting information flow by mutating input data. In 2017 32nd IEEE/ACM International Conference on Automated Software Engineering (ASE’17). IEEE, 263–273.
[124] Xiaozhu Meng and Barton P. Miller. 2016. Binary code is not easy. In Proceedings of the 25th International Symposiumon Software Testing and Analysis (ISSTA’16). ACM, 24–35.
[125] Nicholas Metropolis and Stanislaw Ulam. 1949. The Monte Carlo method. Journal of the American Statistical Association 44, 247 (1949), 335–341.
[126] Jonathan Metzman, Abhishek Arya, and Laszlo Szekeres. 2020. FuzzBench: Fuzzer Benchmarking as a Service. https://security.googleblog.com/2020/03/fuzzbench-fuzzer-benchmarking-as-service.html.
[127] Tomáš Mikolov, Martin Karafiát, Lukáš Burget, Jan Černock`y, and Sanjeev Khudanpur. 2010. Recurrent neural network based language model. In 11th Annual Conference of the International Speech Communication Association (INTERSPEECH’10). 1045–1048.
[128] Barton Miller and Jeff Hollingsworth. 2019. Dyninst: An API for program binary analysis and instrumentation. Retrieved June 2019 from https://dyninst.org/dyninst.
[129] Barton P. Miller, Louis Fredriksen, and Bryan So. 1990. An empirical study of the reliability of UNIX utilities. Communications of the ACM 33, 12 (1990), 32–44.
[130] Charlie Miller. 2008. Fuzz by number - More data about fuzzing than you ever wanted to know. In CanSecWest.
[131] MITRE. 2020. 2020 CWE Top 25 Most Dangerous Software Weaknesses. https://cwe.mitre.org/top25/archive/2020/2020_cwe_top25.html.
[132] David Molnar, Xue Cong Li, and David A. Wagner. 2009. Dynamic test generation to find integer bugs in x86 binary Linux programs. In 18th USENIX Security Symposium (USENIX Security’09), Vol. 9. 67–82.
[133] Stefan Nagy and Matthew Hicks. 2019. Full-speed fuzzing: Reducing fuzzing overhead through coverage-guided tracing. In IEEE Symposium on Security and Privacy (S&P’19). 787–802.
[134] Stefan Nagy, Anh Nguyen-Tuong, Jason D. Hiser, Jack W. Davidson, and Matthew Hicks. 2021. Breaking through binaries: Compiler-quality instrumentation for better binary-only fuzzing. In 30th USENIX Security Symposium (USENIX Security’21). 1–19.
[135] James Newsome and Dawn Xiaodong Song. 2005. Dynamic taint analysis for automatic detection, analysis, and signature generation of exploits on commodity software. In The Network and Distributed System Security Symposium (NDSS’05), Vol. 5. Citeseer, 3–4.
[136] Hoang Lam Nguyen, Nebras Nassar, Timo Kehrer, and Lars Grunske. 2020. MoFuzz: A fuzzer suite for testing model driven software engineering tools. In 2020 35th IEEE/ACM International Conference on Automated Software Engineering (ASE’20). IEEE, 1103–1115.
[137] Tai D. Nguyen, Long H. Pham, Jun Sun, Yun Lin, and Quang Tran Minh. 2020. sFuzz: An efficient adaptive fuzzer for solidity smart contracts. In Proceedings of the ACM/IEEE 42nd International Conference on Software Engineering (ICSE’20). 778–788.
[138] Shirin Nilizadeh, Yannic Noller, and Corina S. Pasareanu. 2019. DifFuzz: Differential fuzzing for side-channel analysis. In 2019 IEEE/ACM 41st International Conference on Software Engineering (ICSE’19). IEEE, 176–187.
[139] Oleksii Oleksenko, Bohdan Trach, Mark Silberstein, and Christof Fetzer. 2020. SpecFuzz: Bringing spectre-type vulnerabilities to the surface. In 29th USENIX Security Symposium (USENIX Security’20). USENIX Association, 1481–1498.
[140] Sebastian Österlund, Kaveh Razavi, Herbert Bos, and Cristiano Giuffrida. 2020. ParmeSan: Sanitizer-guided greybox fuzzing. In 29th USENIX Security Symposium (USENIX Security’20). USENIX Association, 2289–2306.
[141] Carlos Pacheco, Shuvendu K. Lahiri, Michael D. Ernst, and Thomas Ball. 2007. Feedback-directed random test generation. In 29th International Conference on Software Engineering (ICSE’07). IEEE, 75–84.
[142] Shankara Pailoor, Andrew Aday, and Suman Jana. 2018. Moonshine: Optimizing OS fuzzer seed selection with trace distillation. In 27th USENIX Security Symposium (USENIX Security’18). 729–743.
[143] Jianfeng Pan, Guanglu Yan, and Xiaocao Fan. 2017. Digtool: A virtualization-based framework for detecting kernel vulnerabilities. In 26th USENIX Security Symposium (USENIX Security’17). 149–165.
[144] Chang-Seo Park and Koushik Sen. 2008. Randomized active atomicity violation detection in concurrent programs. In Proceedings of the 16th ACM SIGSOFT International Symposium on Foundations of Software Engineering (SIGSOFT’08/FSE-16). 135–145.
[145] S. Park, W. Xu, I. Yun, D. Jang, and T. Kim. 2020. Fuzzing JavaScript engines with aspect-preserving mutation. In IEEE Symposium on Security and Privacy (S&P’20). IEEE Computer Society, Los Alamitos, CA, 1211–1225.
[146] Terence Parr. [n.d.]. ANTLR: ANother Tool for Language Recognition. Retrieved January 2021 from https://www.antlr.org/.
[147] Peachtech. 2021. Peach: The Peach Fuzzer Platform. Retrieved January 2021 from https://www.peach.tech/products/peach-fuzzer/.
[148] Kexin Pei, Yinzhi Cao, Junfeng Yang, and Suman Jana. 2017. Deepxplore: Automated whitebox testing of deep learning systems. In Proceedings of the 26th Symposium on Operating Systems Principles (SOSP’17). 1–18.
[149] Hui Peng and Mathias Payer. 2020. USBFuzz: A framework for fuzzing USB drivers by device emulation. In 29th USENIX Security Symposium (USENIX Security’20). USENIX Association, 2559–2575.
[150] Hui Peng, Yan Shoshitaishvili, and Mathias Payer. 2018. T-Fuzz: Fuzzing by program transformation. In IEEE Symposium on Security and Privacy (S&P’18). IEEE, 697–710.
[151] Theofilos Petsios, Adrian Tang, Salvatore Stolfo, Angelos D. Keromytis, and Suman Jana. 2017. NEZHA: Efficient domain-independent differential testing. In IEEE Symposium on Security and Privacy (S&P’17). IEEE, 615–632.
[152] Theofilos Petsios, Jason Zhao, Angelos D. Keromytis, and Suman Jana. 2017. Slowfuzz: Automated domainindependent detection of algorithmic complexity vulnerabilities. In The ACM Conference on Computer and Communications Security (CCS’17). ACM, 2155–2168.
[153] Van-Thuan Pham, Marcel Böhme, and Abhik Roychoudhury. 2016. Model-based whitebox fuzzing for program binaries. In 2016 31st IEEE/ACM International Conference on Automated Software Engineering (ASE’16). IEEE, 543–553.
[154] Van-Thuan Pham, Marcel Böhme, and Abhik Roychoudhury. 2020. AFLNET: A greybox fuzzer for network protocols. In IEEE International Conference on Software Testing, Verification and Validation (ICST’20). 1–6.
[155] Van-Thuan Pham, Wei Boon Ng, Konstantin Rubinov, and Abhik Roychoudhury. 2015. Hercules: Reproducing crashes in real-world application binaries. In 2015 IEEE/ACM 37th IEEE International Conference on Software Engineering (ICSE’15). IEEE, 891–901.
[156] Rasmus V. Rasmussen and Michael A. Trick. 2008. Round robin scheduling–a survey. European Journal of Operational Research 188, 3 (2008), 617–636.
[157] Sanjay Rawat, Vivek Jain, Ashish Kumar, Lucian Cojocar, Cristiano Giuffrida, and Herbert Bos. 2017. VUzzer: Application-aware evolutionary fuzzing. In The Network and Distributed System Security Symposium (NDSS’17). 1–15.
[158] Alexandre Rebert, Sang Kil Cha, Thanassis Avgerinos, Jonathan Foote, David Warren, Gustavo Grieco, and David Brumley. 2014. Optimizing seed selection for fuzzing. In 23rd USENIX Security Symposium (USENIX Security’14). 861–875.
[159] Nilo Redini, Andrea Continella, Dipanjan Das, Giulio De Pasquale, Noah Spahn, Aravind Machiry, Antonio Bianchi, Christopher Kruegel, and Giovanni Vigna. 2021. DIANE: Identifying fuzzing triggers in apps to generate underconstrained inputs for IoT devices. In IEEE Symposium on Security and Privacy (S&P’21). 1–17.
[160] Prateek Saxena, Steve Hanna, Pongsin Poosankam, and Dawn Song. 2010. FLAX: Systematic discovery of clientside validation vulnerabilities in rich web applications. In The Network and Distributed System Security Symposium (NDSS’10). 1–17.
[161] Fred B. Schneider. 1990. Implementing fault-tolerant services using the state machine approach: A tutorial. ACM Computing Surveys (CSUR) 22, 4 (1990), 299–319.
[162] Sergej Schumilo, Cornelius Aschermann, Ali Abbasi, Simon Wörner, and Thorsten Holz. 2020. HYPER-CUBE: High-dimensional hypervisor fuzzing. In The Network and Distributed System Security Symposium (NDSS’20). 1–16.
[163] Sergej Schumilo, Cornelius Aschermann, Ali Abbasi, Simon Wörner, and Thorsten Holz. 2021. NYX: Greybox hypervisor fuzzing using fast snapshots and affine types. In 30th USENIX Security Symposium (USENIX Security’21). 1–18.
[164] Sergej Schumilo, Cornelius Aschermann, Robert Gawlik, Sebastian Schinzel, and Thorsten Holz. 2017. kAFL: Hardware-assisted feedback fuzzing for OS kernels. In 26th USENIX Security Symposium (USENIX Security’17). 167–182.
[165] Koushik Sen. 2007. Concolic testing. In Proceedings of the 22nd IEEE/ACM International Conference on Automated Software Engineering (ASE’07). 571–572.
[166] Koushik Sen. 2007. Effective random testing of concurrent programs. In Proceedings of the 22nd IEEE/ACM International Conference on Automated Software Engineering (ASE’07). 323–332.
[167] Koushik Sen. 2008. Race directed random testing of concurrent programs. In Proceedings of the 29th ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI’08). 11–21.
[168] Konstantin Serebryany, Derek Bruening, Alexander Potapenko, and Dmitry Vyukov. 2012. AddressSanitizer: A fast address sanity checker. In 2012 USENIX Annual Technical Conference (USENIX ATC’12). 309–318.
[169] Hossain Shahriar and Mohammad Zulkernine. 2012. Mitigating program security vulnerabilities: Approaches and challenges. ACM Computing Surveys (CSUR) 44, 3 (2012), 1–46.
[170] Claude E. Shannon. 1948. A mathematical theory of communication. Bell System Technical Journal 27, 3 (1948), 379–423.
[171] Dongdong She, Rahul Krishna, Lu Yan, Suman Jana, and Baishakhi Ray. 2020. MTFuzz: Fuzzing with a multi-task neural network. In Proceedings of the 28th ACM Joint Meeting on European Software Engineering Conference and Symposium on the Foundations of Software Engineering (ESEC/FSE’20). 737–749.
[172] Dongdong She, Kexin Pei, Dave Epstein, Junfeng Yang, Baishakhi Ray, and Suman Jana. 2019. NEUZZ: Efficient fuzzing with neural program smoothing. In IEEE Symposium on Security and Privacy (S&P’19). 803–817.
[173] Juraj Somorovsky. 2016. Systematic fuzzing and testing of TLS libraries. In The ACM Conference on Computer and Communications Security (CCS’16). 1492–1504.
[174] Dokyung Song, Felicitas Hetzelt, Dipanjan Das, Chad Spensky, Yeoul Na, Stijn Volckaert, Giovanni Vigna, Christopher Kruegel, Jean-Pierre Seifert, and Michael Franz. 2019. Periscope: An effective probing and fuzzing framework for the hardware-os boundary. In The Network and Distributed System Security Symposium (NDSS’19). 1–15.
[175] Dokyung Song, Julian Lettner, Prabhu Rajasekaran, Yeoul Na, Stijn Volckaert, Per Larsen, and Michael Franz. 2019. SoK: Sanitizing for security. In IEEE Symposium on Security and Privacy (S&P’19). 1275–1295.
[176] Suhwan Song, Chengyu Song, Yeongjin Jang, and Byoungyoung Lee. 2020. CrFuzz: Fuzzing multi-purpose programs through input validation. In Proceedings of the 28th ACM Joint Meeting on European Software Engineering Conference and Symposium on the Foundations of Software Engineering (ESEC/FSE’20). 690–700.
[177] 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 The Network and Distributed System Security Symposium (NDSS’16). 1–16.
[178] Laszlo Szekeres, Mathias Payer, Tao Wei, and Dawn Song. 2013. Sok: Eternal war in memory. In IEEE Symposium on Security and Privacy (S&P’13). 48–62.
[179] Dimitrios Tychalas, Hadjer Benkraouda, and Michail Maniatakos. 2021. ICSFuzz: Manipulating I/Os and repurposing binary code to enable instrumented fuzzing in ICS control applications. In 30th USENIX Security Symposium (USENIX Security’21). 1–16.
[180] Spandan Veggalam, Sanjay Rawat, Istvan Haller, and Herbert Bos. 2016. IFuzzer: An evolutionary interpreter fuzzer using genetic programming. In European Symposium on Research in Computer Security (ESORICS’16). Springer, 581–601.
[181] Vasudev Vikram, Rohan Padhye, and Koushik Sen. 2021. Growing a test corpus with bonsai fuzzing. In 2021 IEEE/ACM 43rd International Conference on Software Engineering (ICSE’21). IEEE, 723–735.
[182] Martin Vuagnoux. 2005. Autodafé: An act of software torture. In Proceedings of the 22th Chaos Communication Congress. Chaos Computer Club, 47–58.
[183] Dmitry Vyukov. 2021. syzkaller. Retrieved May 2021 from https://github.com/google/syzkaller.
[184] Haijun Wang, Xiaofei Xie, Yi Li, Cheng Wen, Yuekang Li, Yang Liu, Shengchao Qin, Hongxu Chen, and Yulei Sui. 2020. Typestate-guided fuzzer for discovering use-after-free vulnerabilities. In 2020 IEEE/ACM 42nd International Conference on Software Engineering (ICSE’20). IEEE, 999–1010.
[185] Junjie Wang, Bihuan Chen, Lei Wei, and Yang Liu. 2017. Skyfire: Data-driven seed generation for fuzzing. In IEEE Symposium on Security and Privacy (S&P’17). IEEE, 579–594.
[186] Junjie Wang, Bihuan Chen, Lei Wei, and Yang Liu. 2019. Superion: Grammar-aware greybox fuzzing. In 2019 IEEE/ACM 41st International Conference on Software Engineering (ICSE’19). IEEE, 724–735.
[187] Tielei Wang, Tao Wei, Guofei Gu, and Wei Zou. 2010. TaintScope: A checksum-aware directed fuzzing tool for automatic software vulnerability detection. In IEEE Symposium on Security and Privacy (S&P’10). IEEE, 497–512.
[188] Yanhao Wang, Xiangkun Jia, Yuwei Liu, Kyle Zeng, Tiffany Bao, Dinghao Wu, and Purui Su. 2020. Not all coverage measurements are equal: Fuzzing by coverage accounting for input prioritization. In The Network and Distributed System Security Symposium (NDSS’20). 1–17.
[189] Richard Wartell, Yan Zhou, Kevin W. Hamlen, Murat Kantarcioglu, and Bhavani Thuraisingham. 2011. Differentiating code from data in x86 binaries. In Joint European Conference on Machine Learning and Knowledge Discovery in Databases. Springer, 522–536.
[190] Jiayi Wei, Jia Chen, Yu Feng, Kostas Ferles, and Isil Dillig. 2018. Singularity: Pattern fuzzing for worst case complexity.In Proceedings of the 2018 26th ACM Joint Meeting on European Software Engineering Conference and Symposium on the Foundations of Software Engineering (ESEC/FSE’18). 213–223.
[191] Svante Wold, Kim Esbensen, and Paul Geladi. 1987. Principal component analysis. Chemometrics and Intelligent Laboratory Systems 2, 1–3 (1987), 37–52.
[192] Maverick Woo, Sang Kil Cha, Samantha Gottlieb, and David Brumley. 2013. Scheduling black-box mutational fuzzing. In Proceedings of the 2013 ACM SIGSAC Conference on Computer and Communications Security (CCS’13). 511–522.
[193] Valentin Wüstholz and Maria Christakis. 2020. Harvey: A greybox fuzzer for smart contracts. In Proceedings of the 28th ACM Joint Meeting on European Software Engineering Conference and Symposium on the Foundations of Software Engineering (ESEC/FSE’20). 1398–1409.
[194] M. Xu, S. Kashyap, H. Zhao, and T. Kim. 2020. Krace: Data race fuzzing for kernel file systems. In IEEE Symposium on Security and Privacy (S&P’20). IEEE Computer Society, Los Alamitos, CA, 1396–1413.
[195] Wen Xu, Sanidhya Kashyap, Changwoo Min, and Taesoo Kim. 2017. Designing new operating primitives to improve fuzzing performance. In The ACM Conference on Computer and Communications Security (CCS’17). ACM, 2313–2328.
[196] Wen Xu, Hyungon Moon, Sanidhya Kashyap, Po-Ning Tseng, and Taesoo Kim. 2019. Fuzzing file systems via two-dimensional input space exploration. In IEEE Symposium on Security and Privacy (S&P’19). 818–834.
[197] Wen Xu, Soyeon Park, and Taesoo Kim. 2020. FREEDOM: Engineering a State-of-the-Art DOM Fuzzer. In The ACM Conference on Computer and Communications Security (CCS’20). 971–986.
[198] Shengbo Yan, Chenlu Wu, Hang Li, Wei Shao, and Chunfu Jia. 2020. PathAFL: Path-coverage assisted fuzzing. In Proceedings of the 15th ACM ASIA Conference on Computer and Communications Security (ASIACCS’20). 598–609.
[199] Dingning Yang, Yuqing Zhang, and Qixu Liu. 2012. Blendfuzz: A model-based framework for fuzz testing programs with grammatical inputs. In IEEE 11th International Conference on Trust, Security and Privacy in Computing and Communications (TrustCom’12). IEEE, 1070–1076.
[200] Wei You, Xuwei Liu, Shiqing Ma, David Perry, Xiangyu Zhang, and Bin Liang. 2019. SLF: Fuzzing without valid seed inputs. In 2019 IEEE/ACM 41st International Conference on Software Engineering (ICSE’19). IEEE, 712–723.
[201] 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 IEEE Symposium on Security and Privacy (S&P’19). IEEE, 769–786.
[202] Wei You, Peiyuan Zong, Kai Chen, XiaoFeng Wang, Xiaojing Liao, Pan Bian, and Bin Liang. 2017. SemFuzz: Semanticsbased automatic generation of proof-of-concept exploits. In The ACM Conference on Computer and Communications Security (CCS’17). ACM, 2139–2154.
[203] Tai Yue, Pengfei Wang, Yong Tang, Enze Wang, Bo Yu, Kai Lu, and Xu Zhou. 2020. EcoFuzz: Adaptive energy-saving greybox fuzzing as a variant of the adversarial multi-armed bandit. In 29th USENIX Security Symposium (USENIX Security’20). USENIX Association, 2307–2324.
[204] Insu Yun, Sangho Lee, Meng Xu, Yeongjin Jang, and Taesoo Kim. 2018. QSYM: A practical concolic execution enginetailored for hybrid fuzzing. In 27th USENIX Security Symposium (USENIX Security’18). 745–761.
[205] Jonas Zaddach, Luca Bruno, Aurelien Francillon, and Davide Balzarotti. 2014. AVATAR: A framework to support dynamic security analysis of embedded systems’ firmwares. In The Network and Distributed System Security Symposium (NDSS’14), Vol. 23. 1–16.
[206] Michał Zalewski. 2021. AFL (American fuzzy lop). Retrieved January 21, 2021, from https://github.com/google/AFL.
[207] Qian Zhang, Jiyuan Wang, Muhammad Ali Gulzar, Rohan Padhye, and Miryung Kim. 2020. BigFuzz: Efficient fuzz testing for data analytics using framework abstraction. In 2020 35th IEEE/ACM International Conference on Automated Software Engineering (ASE’20). IEEE, 722–733.
[208] Yangyong Zhang, Lei Xu, Abner Mendoza, Guangliang Yang, Phakpoom Chinprutthiwong, and Guofei Gu. 2019. Life after speech recognition: Fuzzing semantic misinterpretation for voice assistant applications. In The Network and Distributed System Security Symposium (NDSS’19). 1–15.
[209] Zhuo Zhang, Wei You, Guanhong Tao, Yousra Aafer, Xuwei Liu, and Xiangyu Zhang. 2021. STOCHFUZZ: Sound and cost-effective fuzzing of stripped binaries by incremental and stochastic rewriting. In IEEE Symposium on Security and Privacy (S&P’21). 1–18.
[210] Lei Zhao, Yue Duan, Heng Yin, and Jifeng Xuan. 2019. Send hardest problems my way: Probabilistic path prioritization for hybrid fuzzing. In The Network and Distributed System Security Symposium (NDSS’19). 1–15.
[211] Yaowen Zheng, Ali Davanian, Heng Yin, Chengyu Song, Hongsong Zhu, and Limin Sun. 2019. FIRM-AFL: High-Throughput greybox fuzzing of IoT firmware via augmented process emulation. In 28th USENIX Security Symposium (USENIX Security’19). USENIX Association, 1099–1114.
[212] Rui Zhong, Yongheng Chen, Hong Hu, Hangfan Zhang, Wenke Lee, and Dinghao Wu. 2020. SQUIRREL: Testing database management systems with language validity and coverage feedback. In The ACM Conference on Computer and Communications Security (CCS’20). 955–970.
[213] Chijin Zhou, Mingzhe Wang, Jie Liang, Zhe Liu, and Yu Jiang. 2020. Zeror: Speed up fuzzing with coverage-sensitive tracing and scheduling. In 2020 35th IEEE/ACM International Conference on Automated Software Engineering (ASE’20).IEEE, 858–870.
[214] Xiaogang Zhu and Marcel Böhme. 2021. Regression greybox fuzzing. In The ACM Conference on Computer and Communications Security (CCS’21). 2169–2182.
[215] Xiaogang Zhu, Xiaotao Feng, Tengyun Jiao, Sheng Wen, Yang Xiang, Seyit Camtepe, and Jingling Xue. 2019. A feature-oriented corpus for understanding, evaluating and improving fuzz testing. In Proceedings of the 2019 ACM Asia Conference on Computer and Communications Security (Asia CCS’19). 658–663.
[216] Xiaogang Zhu, Xiaotao Feng, Xiaozhu Meng, Sheng Wen, Seyit Camtepe, Yang Xiang, and Kui Ren. 2020. CSI-Fuzz: Full-speed edge tracing using coverage sensitive instrumentation. IEEE Transactions on Dependable and Secure Computing 19 (2020), 912–923.
[217] Peiyuan Zong, Tao Lv, Dawei Wang, Zizhuang Deng, Ruigang Liang, and Kai Chen. 2020. FuzzGuard: Filtering out unreachable inputs in directed grey-box fuzzing through deep learning. In 29th USENIX Security Symposium (USENIX Security’20). 2255–2269.