چکیده (Abstract)
آسیب پذیریهای امنیتی یکی از علل اصلی تهدیدات سایبری میباشند. پژوهشگران برای کشف و رفع این آسیب پذیریها، روشهای مختلفی را پیشنهاد دادهاند که در این میان، فازینگ (Fuzzing) به عنوان یکی از پرکاربردترین تکنیکها شناخته میشود. در سالهای اخیر، راه حلهای فازینگ، مانند AFL، پیشرفتهای چشمگیری در کشف آسیب پذیریها داشتهاند. این مقاله به خلاصهای از پیشرفتهای اخیر میپردازد، تحلیل میکند که چگونه این پیشرفتها فرآیند فازینگ را بهبود میبخشند و به آینده کار در زمینه فازینگ توجه میکند.
ابتدا دلایل محبوبیت فازینگ را با مقایسه تکنیکهای مختلف کشف آسیب پذیری تحلیل میکنیم. سپس راه حلهای فازینگ را ارائه میدهیم و به تفصیل یکی از رایجترین انواع فازینگ یعنی فازینگ مبتنی بر پوشش (coverage-based fuzzing) را مورد بررسی قرار میدهیم. در ادامه تکنیکهای دیگری که میتوانند فرآیند فازینگ را هوشمندتر و کارآمدتر سازند، معرفی میکنیم. سرانجام، برخی از کاربردهای فازینگ را نشان میدهیم و روندهای جدید فازینگ و جهتگیریهای بالقوه آینده را مورد بحث قرار میدهیم.
کلیدواژهها: کشف آسیب پذیری، امنیت نرم افزار، فازینگ، فازینگ مبتنی بر پوشش
مقدمه (Introduction)
آسیبپذیریها به عامل ریشهای تهدیدات علیه امنیت فضای سایبری تبدیل شدهاند. بر اساس تعریف ارائهشده در RFC 2828، آسیبپذیری به نقص یا ضعفی در طراحی، پیادهسازی، بهرهبرداری یا مدیریت یک سامانه گفته میشود که میتواند مورد سوءاستفاده قرار گیرد و منجر به نقض سیاستهای امنیتی آن سامانه شود. حمله به آسیبپذیریها، بهویژه آسیبپذیریهای روز صفر (Zero-Day Vulnerabilities)، میتواند خسارات بسیار جدی به همراه داشته باشد.
حمله باجافزاری WannaCry که در ماه مه سال ۲۰۱۷ رخ داد و از یک آسیبپذیری در پروتکل Server Message Block (SMB) سوءاستفاده میکرد، گزارش شده است که تنها در مدت یک روز بیش از ۲۳۰ هزار رایانه را در بیش از ۱۵۰ کشور آلوده کرده است. این حمله موجب بروز مشکلات جدی در مدیریت بحران و تحمیل خسارات گسترده به صنایع مختلف از جمله بخشهای مالی، انرژی و خدمات درمانی شد.
با توجه به خسارات گستردهای که آسیبپذیریها ایجاد میکنند، تلاشهای فراوانی در راستای توسعه روشهای کشف آسیبپذیری برای نرمافزارها و سامانههای اطلاعاتی صورت گرفته است. در این زمینه، تکنیکهایی نظیر تحلیل ایستا (Static Analysis)، تحلیل پویا (Dynamic Analysis)، اجرای نمادین (Symbolic Execution) و فازینگ (Fuzzing) پیشنهاد شدهاند.
در مقایسه با سایر روشها، فازینگ به دانش اندکی درباره هدف مورد آزمون نیاز دارد و بهراحتی میتواند برای برنامههای کاربردی بزرگ مقیاسپذیر شود. از این رو، فازینگ به محبوبترین راهکار کشف آسیبپذیری، بهویژه در صنعت، تبدیل شده است.
مفهوم فازینگ (Fuzzing) نخستین بار در دهه ۱۹۹۰ مطرح شد. اگرچه ایده و مفهوم بنیادی فازینگ در طول چند دهه توسعه تقریباً بدون تغییر باقی مانده است، اما شیوه اجرای آن دستخوش تحولهای چشمگیری شده است. با این حال، سالها تجربه عملی نشان داده است که فازینگ در مراحل اولیه عمدتاً موفق به کشف باگهای سادهی خرابی حافظه (Memory Corruption Bugs) میشود و به نظر میرسد تنها بخش بسیار کوچکی از کد هدف را پوشش میدهد.
علاوه بر این، ماهیت تصادفی و تا حدی کورکورانه فازینگ موجب کاهش کارایی آن در کشف باگها میشود. به همین دلیل، راهکارهای متعددی برای بهبود اثربخشی (Effectiveness) و کارایی (Efficiency) فازینگ ارائه شدهاند.
ترکیب مدل فازینگ مبتنی بر بازخورد (Feedback-Driven Fuzzing) با الگوریتمهای ژنتیک (Genetic Algorithms) چارچوبی انعطافپذیرتر و قابلسفارشیسازیتر برای فازینگ فراهم کرده و فرایند فازینگ را هوشمندتر و کارآمدتر ساخته است. با ظهور AFL (American Fuzzy Lop) بهعنوان یک نقطه عطف، فازینگ مبتنی بر بازخورد، بهویژه فازینگ هدایتشده بر اساس پوشش کد (Coverage-Guided Fuzzing)، پیشرفتهای چشمگیری را تجربه کرده است.
با الهام از AFL، در سالهای اخیر راهکارها و بهبودهای مؤثر متعددی پیشنهاد شدهاند. در نتیجه، فازینگ امروزی تفاوت قابلتوجهی با فازینگ چند سال گذشته دارد. از این رو، مرور و جمعبندی پژوهشها و دستاوردهای اخیر در حوزه فازینگ و همچنین ترسیم مسیرهای پژوهشی آینده، امری ضروری به نظر میرسد.
در این مقاله، تلاش میکنیم پیشرفتهترین راهکارهای فازینگ (State-of-the-Art Fuzzing Solutions) را مرور کرده و بررسی کنیم که این راهکارها چگونه اثربخشی و کارایی فرایند کشف آسیبپذیری را بهبود میبخشند. همچنین نشان میدهیم که چگونه تکنیکهای سنتی میتوانند در افزایش اثربخشی و کارایی فازینگ نقش داشته باشند و فازرها (Fuzzers) را هوشمندتر سازند. سپس، نمایی کلی از نحوه کشف آسیبپذیری توسط فازرهای پیشرفته در اهداف مختلف ارائه میکنیم؛ از جمله برنامههای مبتنی بر فرمت فایل (File Format Applications)، هسته سیستمعامل (Kernel) و پروتکلها (Protocols). در نهایت، تلاش میکنیم روندها و گرایشهای نوظهور در توسعه فناوری فازینگ را شناسایی و تبیین کنیم.
در بخش «پیشزمینه» (Background)، دانش پایه مربوط به تکنیکهای کشف آسیبپذیری ارائه میشود. بخش «فازینگ» (Fuzzing) معرفی جامعی از فازینگ، شامل مفاهیم بنیادی و چالشهای کلیدی آن، ارائه میدهد. در بخش «فازینگ مبتنی بر پوشش» (Coverage-Based Fuzzing)، این رویکرد فازینگ و مهمترین پژوهشها و دستاوردهای پیشرفته مرتبط با آن معرفی میشوند. در بخش «تکنیکهای ادغامشده در فازینگ» (Techniques Integrated in Fuzzing)، بررسی میشود که چگونه سایر تکنیکها میتوانند به بهبود عملکرد فازینگ کمک کنند. همچنین، بخش «فازینگ برای کاربردهای مختلف» (Fuzzing Towards Different Applications) چندین حوزه کاربردی فازینگ را معرفی میکند. در بخش «روندهای نوین فازینگ» (New Trends of Fuzzing)، گرایشها و مسیرهای احتمالی آینده در توسعه فناوری فازینگ مورد بحث و جمعبندی قرار میگیرند. در نهایت، مقاله در بخش «نتیجهگیری» (Conclusion) جمعبندی و خاتمه مییابد.
پیشینه (Background)
در این بخش، معرفی مختصری از تکنیکهای سنتی کشف آسیبپذیری ارائه میکنیم که شامل تحلیل ایستا (Static Analysis)، تحلیل پویا (Dynamic Analysis)، تحلیل آلودگی داده (Taint Analysis)، اجرای نمادین (Symbolic Execution) و فازینگ (Fuzzing) هستند. سپس، مزایا و معایب هر یک از این تکنیکها را جمعبندی میکنیم.
تحلیل ایستا (Static analysis)
تحلیل ایستا (Static Analysis) به تحلیل برنامهها بدون اجرای واقعی آنها گفته میشود. در عوض، تحلیل ایستا معمولاً بر روی کد منبع (Source Code) و در برخی موارد بر روی کد شیء یا آبجکت (Object Code) نیز انجام میشود. با تحلیل ویژگیهای واژگانی (Lexical)، دستور زبان (Grammar) و معنایی (Semantic)، و همچنین از طریق تحلیل جریان داده (Data Flow Analysis) و بررسی مدل (Model Checking)، تحلیل ایستا میتواند باگهای پنهان را شناسایی کند.
مزیت اصلی تحلیل ایستا، سرعت بالای کشف آسیبپذیریها است. یک تحلیلگر میتواند بهسرعت کد هدف را با استفاده از ابزارهای تحلیل ایستا بررسی کرده و اقدامات لازم را در زمان مناسب انجام دهد. با این حال، تحلیل ایستا در عمل با نرخ بالای مثبت کاذب (False Positive Rate) مواجه است. به دلیل نبود مدلهای کشف آسیبپذیری که استفاده از آنها ساده باشد، ابزارهای تحلیل ایستا مستعد تولید تعداد زیادی مثبت کاذب (False Positives) هستند. از این رو، اعتبارسنجی و تشخیص نتایج واقعی از میان خروجیهای تحلیل ایستا همچنان کاری دشوار به شمار میرود.
تحلیل پویا (Dynamic analysis)
در مقابل تحلیل ایستا (Static Analysis)، در تحلیل پویای برنامهها (Dynamic Analysis)، تحلیلگر باید برنامه هدف را در سامانههای واقعی یا شبیهسازها (Emulators) اجرا کند. با پایش وضعیتهای اجرایی (Running States) و تحلیل اطلاعات بهدستآمده در زمان اجرا (Runtime Knowledge)، ابزارهای تحلیل پویا میتوانند با دقت بالایی باگهای برنامه را شناسایی کنند.
مزیت اصلی تحلیل پویا، دقت بالای آن است؛ با این حال، این روش دارای معایبی نیز هست. نخست، فرایند اشکالزدایی (Debugging)، تحلیل و اجرای برنامههای هدف در تحلیل پویا مستلزم دخالت گسترده نیروی انسانی است که به کاهش کارایی منجر میشود. علاوه بر این، این میزان از دخالت انسانی نیازمند سطح بالایی از مهارت فنی در تحلیلگران است. بهطور خلاصه، تحلیل پویا با محدودیتهایی همچون سرعت پایین، کارایی کم، نیاز به تخصص فنی بالا از سوی آزمونگران، مقیاسپذیری ضعیف (Poor Scalability) و دشواری در اجرای آزمونهای گسترده (Large-Scale Testing) مواجه است.
اجرای نمادین (Symbolic execution)
اجرای نمادین (Symbolic Execution) یکی دیگر از تکنیکهای کشف آسیبپذیری است که بسیار امیدبخش تلقی میشود. در این روش، ورودیهای برنامه بهصورت نمادین (Symbolic) مدلسازی میشوند و برای هر مسیر اجرایی (Execution Path) مجموعهای از قیود (Constraints) نگهداری میشود. پس از اتمام اجرا، از حلکنندههای قیود (Constraint Solvers) برای حل این قیود و تعیین ورودیهایی که منجر به پیمایش آن مسیر اجرایی میشوند، استفاده میگردد. از نظر فنی، اجرای نمادین میتواند هر مسیر اجرایی موجود در یک برنامه را پوشش دهد و در آزمون برنامههای کوچک نیز نتایج مطلوبی از خود نشان داده است. با این حال، این روش با محدودیتهای متعددی نیز مواجه است. نخست، مسئله انفجار مسیرها (Path Explosion Problem)؛ به این معنا که با افزایش مقیاس برنامه، تعداد حالتهای اجرایی بهصورت انفجاری رشد میکند و از توانایی حل حلکنندههای قیود (Constraint Solvers) فراتر میرود. بهعنوان یک راهحل میانی، اجرای نمادین انتخابی (Selective Symbolic Execution) پیشنهاد شده است. دوم، مسئله تعامل با محیط (Environment Interactions) است. در اجرای نمادین، هنگامی که اجرای برنامه هدف با مؤلفههایی خارج از محیط اجرای نمادین تعامل میکند، مانند فراخوانیهای سیستمی (System Calls)، مدیریت سیگنالها (Handling Signals) و موارد مشابه، ممکن است مشکلاتی در حفظ سازگاری (Consistency) به وجود آید. پژوهشهای پیشین نشان دادهاند که اجرای نمادین همچنان در مقیاسپذیری برای برنامههای کاربردی بزرگ (Large Applications) با چالشهای جدی روبهرو است.
فازینگ (Fuzzing)
فازینگ (Fuzzing) در حال حاضر محبوبترین تکنیک کشف آسیبپذیری به شمار میرود. فازینگ نخستین بار در دهه ۱۹۹۰ توسط بارتون میلر (Barton Miller) در دانشگاه ویسکانسین (University of Wisconsin) مطرح شد. از نظر مفهومی، یک آزمون فازینگ با تولید حجم زیادی از ورودیهای عادی و غیرعادی برای برنامههای هدف (Target Applications) آغاز میشود و سپس با تزریق این ورودیهای تولیدشده به برنامه هدف و پایش حالتهای اجرایی (Execution States)، تلاش میکند رفتارهای غیرعادی و استثناها (Exceptions) را شناسایی کند.
در مقایسه با سایر تکنیکها، فازینگ بهسادگی قابل استقرار بوده و از قابلیت توسعهپذیری (Extensibility) و کاربردپذیری (Applicability) مناسبی برخوردار است. همچنین میتواند هم در حضور کد منبع (Source Code) و هم بدون دسترسی به آن اجرا شود. افزون بر این، از آنجا که آزمون فازینگ در محیط اجرای واقعی انجام میشود، از دقت (Accuracy) بالایی برخوردار است. از سوی دیگر، فازینگ به دانش اندکی درباره برنامههای هدف نیاز دارد و بهراحتی میتواند برای برنامههای بزرگمقیاس (Large-Scale Applications) مقیاسپذیر شود.
اگرچه فازینگ با محدودیتهایی نظیر کارایی پایین (Low Efficiency) و پوشش کد پایین (Low Code Coverage) مواجه است، اما مزایای آن بر معایبش غلبه کردهاند. به همین دلیل، فازینگ در حال حاضر به مؤثرترین و کارآمدترین تکنیک پیشرفته (State-of-the-Art) برای کشف آسیبپذیری تبدیل شده است.
جدول ۱ مزایا و معایب تکنیکهای مختلف را نشان میدهد.
جدول 1. مزایا و معایب تکنیکهای مختلف
Scalability | Accuracy | Easy to start? | Technique |
Relatively good | low | easy | Static analysis |
uncertain | high | hard | Dynamic analysis |
bad | high | hard | Symbolic execution |
good | high | easy | Fuzzing |
در این بخش، تلاش میکنیم دیدگاهی جامع درباره فازینگ (Fuzzing) ارائه دهیم که شامل دانش پایه مربوط به تکنیکهای اساسی و همچنین چالشهای موجود در بهبود فازینگ است.
فرآیند کار فازینگ (Working process of fuzzing)
یک آزمون فازینگ (Fuzzing Test) با تولید مجموعهای از ورودیهای برنامه، موسوم به موارد آزمون (Testcases)، آغاز میشود. کیفیت موارد آزمون تولیدشده تأثیر مستقیمی بر اثربخشی فرایند آزمون دارد. این ورودیها باید تا حد امکان با الزامات برنامه هدف از نظر قالب ورودی (Input Format) سازگار باشند. از سوی دیگر، لازم است به اندازه کافی مخدوش (Malformed) یا غیرمعتبر باشند تا پردازش آنها با احتمال بالایی موجب بروز خطا یا شکست در اجرای برنامه شود.
بسته به نوع برنامه هدف، ورودیها میتوانند شامل فایلهایی با قالبهای مختلف، دادههای ارتباطات شبکه (Network Communication Data)، باینریهای اجرایی (Executable Binaries) با ویژگیهای مشخص و موارد مشابه باشند. چگونگی تولید موارد آزمونی که به اندازه کافی مخدوش باشند، یکی از چالشهای اصلی در طراحی فازرها (Fuzzers) محسوب میشود. به طور کلی، در فازرهای پیشرفته (State-of-the-Art Fuzzers) از دو نوع مولد استفاده میشود: مولدهای مبتنی بر تولید (Generation-Based Generators) و مولدهای مبتنی بر جهش (Mutation-Based Generators).
فازرها (Fuzzers) در حین اجرای برنامههای هدف وضعیت اجرا (Execution State) را پایش میکنند و در انتظار استثناها (Exceptions) و کرشها (Crashes) هستند. روشهای متداول پایش استثنا (Exception Monitoring) شامل نظارت بر سیگنالهای خاص سیستم (System Signals)، کرشها و سایر نقضها (Violations) است.
برای نقضهایی که رفتارهای غیرعادی آشکار ندارند، ابزارهای متعددی از جمله AddressSanitizer، DataFlowSanitizer، ThreadSanitizer و LeakSanitizer و غیره قابل استفاده میباشند. زمانی که نقضها (Violations) شناسایی میشوند، فازرها موارد آزمون متناظر را برای بازپخش (Replay) و تحلیل بعدی (Analysis) ذخیره میکنند.
تحلیلگران در مرحله تحلیل، تلاش میکنند مکان (Location) و علت ریشهای نقضهای ثبت شده را تعیین کنند. این تحلیل معمولاً با کمک دیباگرها (Debuggers) مانند GDB، WinDbg یا سایر ابزارهای تحلیل باینری (Binary Analysis Tools) مانند IDA Pro و OllyDbg انجام میشود.
ابزارهای ابزارگذاری باینری (Binary Instrumentation Tools) مانند Pin نیز میتوانند برای پایش وضعیت دقیق اجرای موارد آزمون جمعآوریشده (Collected Testcases) استفاده شوند؛ از جمله اطلاعات رشتهها (Thread Information)، دستورالعملها (Instructions)، اطلاعات ثباتها (Register Information) و موارد دیگر. تحلیل خودکار کرش نیز یکی از حوزههای مهم پژوهشی محسوب میشود.
انواع فازرها (Types of Fuzzers)
فازرها (Fuzzers) را میتوان به روشهای مختلفی طبقهبندی کرد. یک فازر میتواند به دو دسته فازر مبتنی بر تولید (Generation-Based Fuzzer) و فازر مبتنی بر جهش (Mutation-Based Fuzzer) تقسیم شود (Van Sprundel 2005). در فازر مبتنی بر تولید (Generation-Based Fuzzer)، دانش ساختار ورودی برنامه (Program Input Knowledge) مورد نیاز است. برای فازینگ قالب فایل (File Format Fuzzing)، معمولاً یک فایل پیکربندی (Configuration File) ارائه میشود که قالب فایل (File Format) را از پیش تعریف میکند. موارد آزمون (Testcases) بر اساس این فایل پیکربندی تولید میشوند.
با داشتن دانش قالب فایل، موارد آزمون تولیدشده توسط فازرهای مبتنی بر تولید (Generation-Based Fuzzers) راحتتر میتوانند اعتبارسنجی (Validation) برنامهها را پشت سر بگذارند و احتمال بیشتری دارند که کدهای عمیقتر (Deeper Code) در برنامههای هدف را آزمایش کنند. با این حال، بدون داشتن مستندات مناسب (Friendly Documentation)، تحلیل قالب فایل (File Format Analysis) کاری دشوار است.
بنابراین فازرهای مبتنی بر جهش (Mutation-Based Fuzzers) سادهتر برای شروع و کاربردیتر هستند و بهطور گسترده در فازرهای پیشرفته (State-of-the-Art Fuzzers) استفاده میشوند. در این نوع فازرها، یک مجموعه از ورودیهای اولیه معتبر (Valid Initial Inputs) مورد نیاز است. موارد آزمون از طریق جهش (Mutation) ورودیهای اولیه و همچنین موارد آزمونی که در طول فرایند فازینگ (Fuzzing Process) تولید میشوند، ایجاد میگردند. مقایسه فازرهای مبتنی بر تولید (Generation-Based Fuzzers) و فازرهای مبتنی بر جهش (Mutation-Based Fuzzers) در جدول ۲ ارائه شده است.
با توجه به میزان وابستگی به کد منبع برنامه (Program Source Code) و سطح تحلیل برنامه (Degree of Program Analysis)، فازرها (Fuzzers) را میتوان به سه دسته فازر جعبهسفید (White-Box Fuzzer)، فازر جعبهخاکستری (Gray-Box Fuzzer) و فازر جعبهسیاه (Black-Box Fuzzer) طبقهبندی کرد.
فازرهای جعبهسفید (White-Box Fuzzers) فرض میکنند که به کد منبع برنامه (Source Code) دسترسی دارند؛ بنابراین اطلاعات بیشتری از طریق تحلیل کد منبع (Source Code Analysis) و بررسی اینکه موارد آزمون (Testcases) چگونه بر وضعیت اجرای برنامه (Program Execution State) تأثیر میگذارند، قابل استخراج است. فازرهای جعبهسیاه (Black-Box Fuzzers) بدون هیچگونه دانش از جزئیات داخلی برنامه هدف (Target Program Internals) عملیات فازینگ (Fuzzing) را انجام میدهند.
فازرهای جعبهخاکستری نیز بدون دسترسی به کد منبع (Source Code) کار میکنند، اما اطلاعات داخلی برنامههای هدف را از طریق تحلیل برنامه (Program Analysis) به دست میآورند. نمونههایی از فازرهای رایج جعبهسفید، جعبهخاکستری و جعبهسیاه در جدول ۳ ارائه شده است. بر اساس راهبردهای کاوش برنامهها (Strategies of Exploring Programs)، فازرها را میتوان به دو دسته فازینگ هدفمند (Directed Fuzzing) و فازینگ مبتنی بر پوشش (Coverage-Based Fuzzing) طبقهبندی کرد.
یک فازر هدفمند (Directed Fuzzer) به دنبال تولید موارد آزمون است که کد هدف (Target Code) و مسیرهای هدف (Target Paths) در برنامهها را پوشش دهند. در مقابل، یک فازر مبتنی بر پوشش (Coverage-Based Fuzzer) تلاش میکند موارد آزمونی تولید کند که بیشترین میزان پوشش کد (Code Coverage) در برنامهها را به دست آورند.
فازرهای هدفمند (Directed Fuzzers) معمولاً انتظار دارند آزمون برنامهها با سرعت بیشتری انجام شود، در حالی که فازرهای مبتنی بر پوشش (Coverage-Based Fuzzers) به دنبال آزمون جامعتر هستند و تلاش میکنند تا حد امکان باگهای بیشتری (Bugs) را شناسایی کنند.
در هر دو نوع فازر هدفمند (Directed Fuzzers) و فازرهای مبتنی بر پوشش (Coverage-Based Fuzzers)، استخراج اطلاعات مسیرهای اجرایی (Executed Paths Information) یک مسئله کلیدی (Key Problem) محسوب میشود. فازرها (Fuzzers) را میتوان بر اساس وجود یا عدم وجود بازخورد (Feedback) بین پایش وضعیت اجرای برنامه (Monitoring of Program Execution State) و تولید موارد آزمون (Testcase Generation) به فازینگ کور (Dumb Fuzzing) و فازینگ هوشمند (Smart Fuzzing) طبقهبندی کرد.
فازرهای هوشمند (Smart Fuzzers) تولید موارد آزمون (Testcases) را بر اساس اطلاعات جمعآوریشده درباره اینکه موارد آزمون چگونه بر رفتار برنامه (Program Behavior) تأثیر میگذارند، تنظیم و اصلاح میکنند. در فازرهای مبتنی بر جهش (Mutation-Based Fuzzers)، اطلاعات بازخوردی (Feedback Information) میتواند برای تعیین اینکه کدام بخش از موارد آزمون باید جهش یابد (Mutated) و همچنین نحوه انجام این جهش مورد استفاده قرار گیرد. در مقابل، فازرهای گنگ (Dumb Fuzzers) سرعت آزمونگیری (Testing Speed) بالاتری دارند، در حالی که فازرهای هوشمند موارد آزمون با کیفیتتری تولید میکنند و بهرهوری (Efficiency) بالاتری دارند.
چالشهای کلیدی در فازینگ (Key Challenges in Fuzzing)
فازرهای سنتی (Traditional Fuzzers) معمولاً در عمل از راهبرد فازینگ مبتنی بر حالت تصادفی (Random-Based Fuzzing Strategy) استفاده میکنند. محدودیتهای تکنیکهای تحلیل برنامه (Program Analysis Techniques) باعث شده است که فازرها هنوز به اندازه کافی هوشمند (Smart) نباشند. بنابراین آزمون فازینگ (Fuzzing Test) همچنان با چالشهای متعددی مواجه است. در ادامه برخی از چالشهای کلیدی (Key Challenges) ارائه میشود.
چالش چگونگی جهش ورودیهای اولیه (Seed Inputs Mutation Challenge). راهبرد تولید مبتنی بر جهش (Mutation-Based Generation Strategy) بهدلیل سهولت استفاده و راهاندازی آسان، بهطور گسترده در فازرهای پیشرفته (State-of-the-Art Fuzzers) به کار گرفته میشود. با این حال، اینکه چگونه موارد آزمون بهگونهای جهش داده و تولید شوند که بتوانند مسیرهای بیشتری از برنامه (Program Paths) را پوشش دهند و احتمال تحریک باگها (Bugs) را افزایش دهند، یک چالش کلیدی (Key Challenge) محسوب میشود (Yang et al. 2007).
بهطور مشخص، فازرهای مبتنی بر جهش (Mutation-Based Fuzzers) هنگام انجام جهش باید به دو پرسش پاسخ دهند: (1) کجا جهش انجام شود (Where to Mutate) و (2) چگونه جهش انجام شود (How to Mutate). تنها جهش در برخی موقعیتهای کلیدی (Key Positions) میتواند بر جریان کنترل اجرا (Control Flow of Execution) تأثیر بگذارد. بنابراین، اینکه این موقعیتهای کلیدی در موارد آزمون چگونه شناسایی شوند، از اهمیت بالایی برخوردار است.
علاوه بر این، روش انجام جهش روی این موقعیتهای کلیدی (Key Positions) نیز یک مسئله مهم دیگر است؛ یعنی اینکه چگونه مقدارهایی تعیین شوند که بتوانند تست را به سمت مسیرهای جالب (Interesting Paths) در برنامه هدایت کنند. بهطور خلاصه، جهش کور (Blind Mutation) موارد آزمون باعث اتلاف جدی منابع آزمون (Testing Resources) میشود و طراحی یک راهبرد جهش بهتر (Better Mutation Strategy) میتواند بهطور قابلتوجهی بهرهوری (Efficiency) فازینگ را بهبود دهد.
چالش پوشش کم کد (Low Code Coverage Challenge). پوشش کد بالاتر (Higher Code Coverage) نشاندهنده پوشش بیشتر وضعیتهای اجرای برنامه (Program Execution States) و انجام آزمونی جامعتر (Thorough Testing) است. کارهای پیشین نشان دادهاند که پوشش بهتر (Better Coverage) منجر به افزایش احتمال کشف باگها (Bugs) میشود.
با این حال، اکثر موارد آزمون (Testcases) تنها همان چند مسیر محدود (Few Paths) را پوشش میدهند، در حالی که بخش زیادی از کد (Code) قابل دسترسی (Reachable) باقی نمیماند. در نتیجه، دستیابی به پوشش بالا (High Coverage) صرفاً از طریق تولید حجم زیادی از موارد آزمون (Large Amounts of Testcase Generation) و تزریق آنها به منابع آزمون (Testing Resources) انتخاب مناسبی نیست. فازرهای مبتنی بر پوشش (Coverage-Based Fuzzers) تلاش میکنند این مشکل را با استفاده از تکنیکهای تحلیل برنامه (Program Analysis Techniques)، مانند ابزارگذاری برنامه (Program Instrumentation)، حل کنند. جزئیات بیشتر در بخش بعدی ارائه خواهد شد.
چالش عبور از اعتبارسنجی (Passing the Validation Challenge). برنامهها (Programs) معمولاً پیش از تحلیل و پردازش (Parsing and Handling) ورودیها (Inputs) را اعتبارسنجی (Validation) میکنند. این مرحله اعتبارسنجی بهعنوان یک سازوکار حفاظتی (Guard Mechanism) برای برنامهها عمل میکند و هم منابع محاسباتی (Computing Resources) را حفظ میکند و هم از برنامه در برابر ورودیهای نامعتبر (Invalid Inputs) و آسیبهای ناشی از ورودیهای مخرب (Maliciously Constructed Inputs) محافظت مینماید.
موارد آزمون نامعتبر (Invalid Testcases) معمولاً نادیده گرفته (Ignored) یا حذف (Discarded) میشوند. مقادیر جادویی (Magic Numbers)، رشتههای جادویی (Magic Strings)، بررسی نسخه (Version Number Check) و جمعآزماها (Checksums) از جمله سازوکارهای رایج اعتبارسنجی در برنامهها هستند.
موارد آزمون تولیدشده توسط فازرهای جعبهسیاه (Black-Box Fuzzers) و فازرهای جعبهخاکستری (Gray-Box Fuzzers) معمولاً بهدلیل راهبرد تولید کور (Blind Generation Strategy) در عبور از این مرحله اعتبارسنجی با مشکل مواجه میشوند که این موضوع منجر به کاهش شدید بهرهوری فازینگ (Low Efficiency in Fuzzing) میگردد. بنابراین، اینکه چگونه بتوان از این مرحله اعتبارسنجی عبور کرد (How to Pass Validation)، یکی دیگر از چالشهای کلیدی (Key Challenge) محسوب میشود.
روشهای مختلفی به عنوان راهکارهای مقابله (Countermeasures) برای این چالشها پیشنهاد شدهاند که هم شامل تکنیکهای سنتی (Traditional Techniques) مانند ابزارگذاری برنامه (Program Instrumentation) و تحلیل آلودگی (Taint Analysis) هستند، و هم شامل تکنیکهای جدید (New Techniques) مانند شبکههای عصبی بازگشتی (Recurrent Neural Networks / RNN) و حافظه کوتاهمدت بلند (Long Short-Term Memory / LSTM) میشوند (Godefroid et al. 2017; Rajpal et al. 2017). اینکه این تکنیکها چگونه میتوانند بر چالشهای مطرح شده غلبه کنند (Compromise the Challenges)، در بخش «تکنیکهای ادغام شده در فازینگ (Techniques Integrated in Fuzzing)» مورد بحث قرار خواهد گرفت.
فازینگ مبتنی بر پوشش (Coverage-Based Fuzzing)
راهبرد فازینگ مبتنی بر پوشش (Coverage-Based Fuzzing Strategy) بهطور گسترده در فازرهای پیشرفته استفاده میشود و اثربخشی (Effectiveness) و کارایی (Efficiency) بالایی از خود نشان داده است. برای دستیابی به یک فازینگ عمیق و جامع برنامه (Deep and Thorough Program Fuzzing)، فازرها باید تلاش کنند تا حد امکان تعداد بیشتری از وضعیتهای اجرای برنامه (Program Execution States) را پیمایش کنند.
با این حال، معیار ساده و دقیقی (Simple Metric) برای سنجش وضعیتهای برنامه وجود ندارد، زیرا رفتار برنامهها ذاتاً غیرقطعی (Uncertain) هستند. علاوه بر این، یک معیار مناسب باید در حین اجرای فرایند (Process Execution) بهسادگی قابل اندازهگیری باشد. بنابراین، اندازهگیری پوشش کد (Code Coverage Measurement) به عنوان یک راهحل تقریبی (Approximate Alternative Solution) در نظر گرفته میشود.
در این چارچوب، افزایش پوشش کد (Increase in Code Coverage) نشاندهنده کشف وضعیتهای جدید برنامه (New Program States) تلقی میشود. همچنین، با استفاده از ابزارگذاری داخلی (Compiled-in Instrumentation) و ابزارگذاری خارجی (External Instrumentation)، پوشش کد (Code Coverage) به راحتی قابل اندازهگیری است.
با این حال، پوشش کد (Code Coverage) یک معیار تقریبی (Approximate Measurement) محسوب میشود، زیرا در عمل ثابت بودن پوشش کد (Constant Code Coverage) لزوماً به معنای ثابت بودن تعداد وضعیتهای برنامه (Program States) نیست و ممکن است بخشی از اطلاعات از دست برود (Information Loss). در این بخش، با استفاده از AFL (American Fuzzy Lop / AFL) بهعنوان مثال، به بررسی فازینگ مبتنی بر پوشش (Coverage-Based Fuzzing) پرداخته میشود.
شمارش پوشش کد (Code Coverage Counting)
در تحلیل برنامه (Program Analysis)، برنامه از بلوکهای پایه (Basic Blocks) تشکیل میشود. بلوکهای پایه (Basic Blocks) قطعاتی از کد (Code Snippets) هستند که تنها یک نقطه ورود (Single Entry Point) و یک نقطه خروج (Single Exit Point) دارند. دستورات (Instructions) درون این بلوکها بهصورت ترتیبی (Sequentially) اجرا میشوند و هر دستور تنها یکبار در هر اجرای بلوک اجرا میگردد.
در اندازهگیری پوشش کد (Code Coverage Measurement)، روشهای پیشرفته معمولاً بلوک پایه (Basic Block) را بهعنوان بهترین سطح دانهبندی (Granularity) در نظر میگیرند. دلایل این انتخاب شامل موارد زیر است: (۱) بلوک پایه (Basic Block) کوچکترین واحد منسجم (Smallest Coherent Unit) در اجرای برنامه محسوب میشود. (۲) اندازهگیری در سطح تابع (Function) یا دستور (Instruction) میتواند منجر به از دست رفتن اطلاعات (Information Loss) یا ایجاد افزونگی (Redundancy) شود. (۳) بلوک پایه (Basic Block) را میتوان از طریق آدرس اولین دستور (Address of First Instruction) شناسایی کرد و اطلاعات مربوط به آن نیز بهسادگی از طریق ابزارگذاری کد (Code Instrumentation) استخراج میشود.
در حال حاضر، دو انتخاب پایه برای اندازهگیری بر اساس بلوکهای پایه (Basic Blocks) وجود دارد: نخست، شمارش ساده بلوکهای پایه اجراشده (Executed Basic Blocks) و دوم، شمارش انتقالات بلوکهای پایه (Basic Block Transitions).
در روش دوم، برنامه بهصورت یک گراف (Graph) در نظر گرفته میشود؛ بهطوریکه رأسها (Vertices) نمایانگر بلوکهای پایه (Basic Blocks) هستند و یالها (Edges) نشاندهنده انتقال بین بلوکهای پایه (Transition Between Basic Blocks) هستند. بنابراین، روش دوم یالها (Edges) را ثبت میکند، در حالی که روش اول رأسها (Vertices) را ثبت مینماید.
با این حال، آزمایشها نشان میدهد که صرفاً شمارش بلوکهای پایه اجراشده (Executed Basic Blocks) منجر به از دست رفتن اطلاعات (Information Loss) قابل توجهی میشود. همانطور که در شکل ۲ نشان داده شده است، اگر ابتدا مسیر برنامه (Program Path) به صورت (BB1, BB2, BB3, BB4) اجرا شود و سپس مسیر (BB1, BB2, BB4) در اجرای بعدی مشاهده گردد، اطلاعات مربوط به یال جدید (BB2, BB4) از دست میرود (Lost Edge Information).
جدول 2. مقایسه فازرهای مبتنی بر تولید و فازرهای مبتنی بر جهش
Ability to Pass Validation | Coverage | Prior Knowledge | Esay to Start? | |
Strong | High | Needed, hard to acquire | Hard | Generation Based |
Weak | Low, affected by initial inputs | Not Needed | Easy | Mutation Based |
جدول 3. فازرهای جعبه سفید، جعبه خاکستری و جعبه سیاه رایج
Black Box Fuzzers | Gray Box Fuzzers | White Box Fuzzers | |
Spike (Bowne 2015), Sulley (Amini 2017), Peach (PeachTech 2017) | Generation Based | ||
Sage (Godefroid et al. 2012), Libfuzzer (libfuzzer 2017) | AFL (Zalewski 2017a), Driller (Stephens et al. 2016), Vuzzer (Rawat et al. 2017), TaintScope (Wang et al. 2010), Mayhem (Cha et al. 2012) | Miller (Takanen et al. 2008) | Mutation Based |
فازر AFL نخستین ابزار فازینگ است که روش اندازهگیری مبتنی بر یال (Edge Measurement Method) را به فازینگ مبتنی بر پوشش (Coverage-Based Fuzzing) معرفی کرد. در این بخش، AFL به عنوان یک مثال بررسی میشود تا نشان داده شود فازرهای مبتنی بر پوشش (Coverage-Based Fuzzers) چگونه در طول فرایند فازینگ (Fuzzing Process) اطلاعات پوشش (Coverage Information) را بهدست میآورند.
AFL اطلاعات پوشش (Coverage Information) را از طریق ابزارگذاری سبک (Lightweight Program Instrumentation) به دست میآورد. بر اساس اینکه کد منبع (Source Code) در دسترس باشد یا خیر، AFL دو حالت ابزارگذاری (Instrumentation Mode) ارائه میدهد: ابزارگذاری درونکامپایل (Compile-in Instrumentation) و ابزارگذاری خارجی (External Instrumentation).
در حالت ابزارگذاری درونکامپایل (Compile-in Instrumentation Mode)، AFL دو حالت GCC و LLVM را ارائه میدهد که بسته به کامپایلر مورد استفاده (Compiler)، هنگام تولید باینری (Binary Generation) قطعههای کد (Code Snippets) را ابزارگذاری (Instrument) میکنند. در حالت ابزارگذاری خارجی (External Instrumentation Mode)، AFL حالت QEMU را ارائه میدهد که در آن هنگام ترجمه بلوکهای پایه (Basic Blocks) به بلوکهای TCG، قطعههای کد ابزارگذاری میشوند.
لیست ۱ یک نمای کلی از قطعه کد ابزارگذاری شده (Instrumented Code Snippet) را نشان میدهد (Zalewski 2017b). در فرایند ابزارگذاری (Instrumentation)، یک شناسه تصادفی (Random ID)، یعنی متغیر cur_location، در بلوکهای پایه (Basic Blocks) تزریق میشود. متغیر shared_mem (Shared Memory Array) یک ناحیه حافظه مشترک ۶۴ کیلوبایتی (64 KB Shared Memory Region) است که هر بایت آن به یک وقوع (Hit) از یک یال مشخص (Specific Edge) به صورت (BB_src, BB_dst) نگاشت میشود. هنگامی که یک انتقال بین بلوکهای پایه (Basic Block Transition) رخ میدهد، یک مقدار هش (Hash Value) محاسبه میشود و مقدار بایت متناظر در آرایه بیتمپ (Bitmap Array) بهروزرسانی (Update) میگردد. شکل ۳ نگاشت بین مقدار هش (Hash) و بیتمپ (Bitmap) را نشان میدهد.
لیست 1. ابزارگذاری AFL:
;cur_location = <COMPILE_TIME_RANDOM>
; shared_mem[cur_location ^ prev_location]++; prev_location = cur_location >> 1
فرآیند کاری فازینگ مبتنی بر پوشش (Working process of coverage-based fuzzing
الگوریتم ۱ فرایند کلی یک فازر مبتنی بر پوشش (Coverage-Based Fuzzer) را نشان میدهد. آزمون با مجموعهای از ورودیهای بذر اولیه (Initial Seed Inputs) آغاز میشود. اگر مجموعه ورودیهای بذر اولیه (Seed Input Set) در اختیار نباشد، فازر (Fuzzer) خود آن را ایجاد میکند.
در حلقه اصلی فازینگ (Main Fuzzing Loop)، فازر بهصورت تکراری یک ورودی بذر (Seed) «جالب» (Interesting Seed) را برای مراحل بعدی جهش (Mutation) و تولید موارد آزمون (Testcase Generation) انتخاب میکند. سپس برنامه هدف (Target Program) تحت پایش فازر (Fuzzer Monitoring) با موارد آزمون تولیدشده اجرا میشود.
موارد آزمونی که باعث کرش (Crash) میشوند جمعآوری میگردند و سایر موارد «جالب» (Interesting Testcases) به مجموعه بذرها (Seed Pool) افزوده میشوند. در فازینگ مبتنی بر پوشش (Coverage-Based Fuzzing)، موارد آزمونی که به یالهای جدید در جریان کنترل (New Control Flow Edges) دست پیدا میکنند، بهعنوان موارد جالب (Interesting) در نظر گرفته میشوند. حلقه اصلی فازینگ (Main Fuzzing Loop) در یک زمانبندی از پیش تعیینشده (Pre-configured Timeout) یا در صورت دریافت سیگنال توقف (Abort Signal) متوقف میشود.
در طول فرایند فازینگ (Fuzzing Process)، فازرها اجرای برنامه را از طریق روشهای مختلف، رهگیری (Tracking) میکنند. بهطور کلی، فازرها اجرای برنامه را با دو هدف اصلی پایش میکنند: پوشش کد (Code Coverage) و نقضهای امنیتی (Security Violations). اطلاعات پوشش کد (Code Coverage Information) برای دستیابی به کاوش کاملتر وضعیتهای برنامه (Thorough Program State Exploration) استفاده میشود، در حالی که پایش نقضهای امنیتی (Security Violation Tracking) برای کشف بهتر باگها (Bug Finding) به کار میرود.
همانطور که در زیربخشهای قبلی توضیح داده شد، AFL پوشش کد (Code Coverage) را از طریق ابزارگذاری کد (Code Instrumentation) و بیتمپ AFL (AFL Bitmap) دنبال میکند. پایش نقضهای امنیتی (Security Violations Tracking) نیز میتواند با استفاده از ابزارهای مختلف سنیتایزر (Sanitizers) انجام شود؛ از جمله AddressSanitizer ،ThreadSanitizer و LeakSanitizer و سایر موارد مشابه.
شکل ۴ فرایند کاری AFL (American Fuzzy Lop / AFL) را نشان میدهد که یک فازر مبتنی بر پوشش (Coverage-Based Fuzzer) بسیار نماینده (Representative) است. برنامه هدف (Target Application) پیش از اجرا برای جمعآوری اطلاعات پوشش (Coverage Collection) ابزارگذاری (Instrumentation) میشود.
همانطور که پیشتر اشاره شد، AFL (American Fuzzy Lop / AFL) از هر دو نوع ابزارگذاری در زمان کامپایل (Compile-Time Instrumentation) و ابزارگذاری خارجی (External Instrumentation) پشتیبانی میکند که شامل حالتهای GCC، LLVM و QEMU است. همچنین باید مجموعهای از ورودیهای بذر اولیه (Initial Seed Inputs) فراهم شود. در حلقه اصلی فازینگ (Main Fuzzing Loop)، مراحل زیر انجام میشود:
(1) فازر (Fuzzer) یک بذر (Seed) «مطلوب» (Favorite Seed) را از مجموعه بذرها (Seed Pool) بر اساس راهبرد انتخاب بذر (Seed Selection Strategy) انتخاب میکند؛ در AFL، بذرهای سریعتر (Fastest) و کوچکتر (Smallest) ترجیح داده میشوند.
(2) فایلهای بذر (Seed Files) بر اساس راهبرد جهش (Mutation Strategy) دچار تغییر (Mutation) میشوند و مجموعهای از موارد آزمون (Testcases) تولید میگردد. AFL در حال حاضر از مجموعهای از تغییرات تصادفی (Random Modifications) و روشهای ترکیب موارد آزمون (Testcase Splicing) استفاده میکند؛ از جمله: تغییرات بیت متوالی (Sequential Bit Flip) با طولها و گامهای مختلف، افزودن و کمکردن متوالی اعداد صحیح کوچک (Sequential Addition/Subtraction of Small Integers)، و درج مقادیر صحیح «مهم» شناخته شده (Interesting Integers) مانند 0، 1، INT_MAX و غیره (Zalewski 2017b).
(3) موارد آزمون (Testcases) اجرا میشوند و اجرای برنامه تحت پایش (Tracking) قرار میگیرد. اطلاعات پوشش کد (Coverage Information) جمعآوری میشود تا موارد آزمون «جالب» (Interesting Testcases) مشخص شوند؛ یعنی مواردی که به یالهای جدید در جریان کنترل (New Control Flow Edges) دست پیدا میکنند. این موارد جالب (Interesting Testcases) به مجموعه بذرها (Seed Pool) اضافه میشوند تا در دور بعدی اجرا مورد استفاده قرار گیرند.
پرسشهای کلیدی (Key Questions)
مقدمههای پیشین نشان میدهد که برای اجرای یک فازینگ مبتنی بر پوشش (Coverage-Based Fuzzing) کارآمد و مؤثر، پرسشهای متعددی باید حل شوند. در این زمینه، پژوهشها و بررسیهای زیادی انجام شده است. ما در این زیربخش، برخی از کارهای پیشرفته (State-of-the-Art Works) را خلاصه و ارائه میکنیم، همانطور که در جدول ۴ نشان داده شده است.
A. چگونه ورودیهای اولیه را به دست آوریم؟
اکثر فازرهای مبتنی بر پوشش از استراتژی تولید موارد آزمایشی مبتنی بر جهش استفاده میکنند که به شدت به کیفیت ورودیهای اولیه وابسته است. ورودیهای اولیه خوب میتوانند به طور قابل توجهی کارایی و اثربخشی فازینگ را بهبود بخشند. به طور خاص (1) ارائه ورودیهای اولیه با قالب مناسب میتواند زمانهای CPU زیادی را که در ساخت آن صرف میشود، صرفه جویی کند، (2) ورودیهای اولیه مناسب میتوانند نیازهای قالبهای فایل پیچیده را برآورده کنند که در مرحله جهش سخت است حدس زد، (3) جهش بر اساس ورودیهای اولیه با قالب مناسب احتمال بیشتری دارد که موارد آزمایشی تولید کند که بتوانند به مسیرهای عمیقتر و دشوارتر دسترسی پیدا کنند، (4) ورودیهای اولیه خوب میتوانند در چندین آزمون دوباره استفاده شوند.
روشهای رایج جمع آوری ورودیهای اولیه شامل استفاده از معیارهای استاندارد، جستجو در وب میشوند. برنامههای متن باز معمولا با یک معیار استاندارد منتشر میشوند که برای تست پروژهها به طور رایگان قابل استفاده است. این معیار ارائه شده بر اساس ویژگیها و عملکردهای برنامهها ساخته شده است که طبیعی است که یک مجموعه خوب از ورودیهای اولیه را بسازد. با توجه به تنوع ورودیهای برنامه هدف، جستجو از اینترنت سادهترین روش است. شما میتوانید به راحتی فایلهایی با قالبهای خاص را دانلود کنید. علاوه بر این، برای برخی از فرمتهای فایل معمولی، پروژههای آزمایشی زیادی در شبکه وجود دارد که مجموعه دادههای آزمایشی رایگان را ارائه میدهند. همچنین، استفاده از نمونههای PoC موجود نیز ایده خوبی است. با این حال، تعداد زیاد ورودیهای اولیه باعث هدر رفتن زمان در اولین اجرای آزمایشی میشود، بنابراین نگرانی دیگری به وجود میآید: چگونه ابتدا مجموعه ورودیها را استفاده کنیم. AFL ابزاری را ارائه میدهد که حداقل مجموعهای از ورودیها را استخراج میکند که همان پوشش کد را دست مییابد.
B. چگونه موارد آزمایشی تولید کنیم؟
کیفیت موارد آزمایشی یکی از عوامل مهمی است که بر کارایی و اثربخشی آزمون فازینگ تأثیر میگذارد. اولا، موارد آزمایشی خوب میتوانند وضعیتهای بیشتری از اجرای برنامه را اکتشاف کرده و کد بیشتری را در زمان کمتری پوشش دهند. علاوه بر این، موارد آزمایشی خوب میتوانند موقعیتهای آسیبپذیر بالقوه را هدف قرار دهند و کشف سریعتر باگها برنامه را به ارمغان آورند. از این رو، اینکه چگونه موارد آزمایشی خوبی بر مبنای ورودیهای اولیه تولید کنیم، یک نگرانی مهم است. راوات و همکاران (2017)، Vuzzer را پیشنهاد کردند که یک فازر خاکستری آگاه از برنامه است که با تجزیه و تحلیل ایستا و پویا ترکیب میشود.
جهش ورودیهای اولیه شامل دو سؤال کلیدی است: جهش بایدکجا انجام شود و چه مقداری برای جهش استفاده کنیم. به طور خاص، Vuzzer مقادیر فوری، مقادیر جادویی و سایر رشتههای مشخصه را استخراج میکند که کنترل جریان را از طریق تحلیل ایستا قبل از حلقه اصلی فازینگ تحت تأثیر قرار میدهد. در حین اجرای برنامه، Vuzzer از تکنیک تحلیل آلودگی پویا برای جمعآوری اطلاعاتی که بر شاخههای کنترل جریان تأثیر میگذارد، شامل مقدار خاص و جابجایی مربوطه استفاده میکند.
جدول 4. مقایسه تکنیکهای مختلف
Initial inputs get | Inputs mutation | Seed selection | Testing efficiency |
Standard benchmarks; | Vuzzer (Rawat et al. 2017)
| AFLFast (Bohme et al. 2017)
| Forkserver
|
Crawling from Internet;
| Skyfire (Wang et al. 2017)
| Vuzzer | Intel PT (Schumilo et al. 2017)
|
POC samples; | Learn & Fuzz (Godefroid et al. 2017) Faster Fuzzing (Nichols et al. 2017) Work (Rajpal et al. 2017) | AFLGO (2017) QTEP (Wang et al. 2017) SlowFuzz (Petsios et al. 2017) | (Icamtuf 2014) Work (Xu et al. 2017) |
با بهرهگیری از جهش (Mutation) بر روی مقادیر جمعآوریشده و همچنین اعمال جهش در نقاطی که بهصورت خودکار شناسایی شدهاند، VUzzer قادر است موارد آزمایشی (Test Cases) تولید کند که احتمال بیشتری برای تحقق شروط انشعاب (Branch Conditions) و عبور از اعتبارسنجیهای مبتنی بر مقادیر جادویی (Magic Values) دارند. با این حال، VUzzer همچنان قادر به عبور از سایر انواع مکانیزمهای اعتبارسنجی موجود در برنامهها، نظیر جمعآزماهای مبتنی بر هش (Hash-Based Checksums)، نیست.
علاوه بر این، مؤلفههای ابزارگذاری (Instrumentation)، تحلیل آلودگی (Taint Analysis) و حلقه اصلی فازینگ (Main Fuzzing Loop) در VUzzer بر پایه چارچوب Pin پیادهسازی شدهاند. این موضوع در مقایسه با AFL منجر به سرعت اجرای آزمون (Testing Throughput) نسبتاً پایینتری میشود، زیرا سربار ناشی از ابزارگذاری پویا (Dynamic Instrumentation Overhead) قابل توجه است.
Wang و همکاران (2017) سامانه Skyfire را به عنوان یک راهکار دادهمحور برای تولید بذر (Seed) در فرایند فازینگ معرفی کردند. Skyfire با یادگیری یک دستور زبان احتمالی حساس به زمینه (Probabilistic Context-Sensitive Grammar – PCSG) از ورودیهای گردآوریشده (Crawled Inputs)، دانش استخراج شده را برای تولید ورودیهای ساختاریافته و معتبر (Well-Structured Inputs) به کار میگیرد. نتایج ارزیابی تجربی نشان میدهد که موارد آزمایشی (Test Cases) تولید شده توسط Skyfire در مقایسه با موارد آزمایشی تولیدشده توسط AFL، پوشش کد (Code Coverage) بیشتری ایجاد کرده و تعداد بیشتری آسیبپذیری و باگ (Bug) را کشف میکنند.
این پژوهش همچنین نشان میدهد که کیفیت موارد آزمایشی یا بذرها (Seed) یکی از عوامل کلیدی مؤثر بر کارایی (Efficiency) و اثربخشی (Effectiveness) فرایند فازینگ است؛ بهطوریکه تولید ورودیهای معنادار و منطبق با ساختار مورد انتظار برنامه میتواند احتمال دستیابی به مسیرهای اجرایی عمیقتر و کشف خطاهای بیشتر را بهطور چشمگیری افزایش دهد.
با توسعه و کاربرد گسترده تکنیکهای یادگیری ماشین (machine learning)، برخی پژوهشها تلاش کردهاند از این تکنیکها برای کمک به تولید موارد آزمایشی (Test Case) استفاده کنند. Godefroid و همکاران (2017) از Microsoft Research از تکنیکهای یادگیری ماشین آماری مبتنی بر شبکههای عصبی برای تولید خودکار موارد آزمون بهره بردند. بهطور مشخص، آنها ابتدا با استفاده از تکنیکهای یادگیری ماشین، قالب ورودی را از مجموعهای از ورودیهای معتبر یاد میگیرند و سپس از دانش آموختهشده برای هدایت فرایند تولید موارد آزمون استفاده میکنند. آنها این فرایند فازینگ را بر روی تجزیهکننده PDF در مرورگر Edge مایکروسافت به نمایش گذاشتند. اگرچه نتایج آزمایش چندان امیدوارکننده نبود، اما همچنان تلاشی ارزشمند به شمار میرود.
Rajpal و همکاران (2017) از مایکروسافت از شبکههای عصبی برای یادگیری از اکتشافات پیشین فازینگ استفاده کردند و پیشبینی نمودند که کدام بایتها در فایلهای ورودی باید دچار جهش (Mutation) شوند. Nichols و همکاران (2017) از مدلهای شبکه مولد تخاصمی (GAN) برای کمک به مقداردهی مجدد سیستم با فایلهای بذر جدید استفاده کردند. نتایج آزمایشها نشان میدهد که GAN نسبت به LSTM سریعتر و مؤثرتر است و به کشف تعداد بیشتری از مسیرهای کد کمک میکند.
C. چگونه بذر از مجموعه بذرها انتخاب میشود؟
فازرها در ابتدای هر دور جدید از حلقه اصلی فازینگ، بهطور مکرر یک بذر (Seed) را از مخزن بذرها (seed pool) انتخاب کرده و آن را دچار جهش (Mutation) میکنند. نحوه انتخاب بذر از این مخزن یکی دیگر از مسائل باز و مهم در حوزه فازینگ است. پژوهشهای پیشین نشان دادهاند که یک راهبرد مناسب برای انتخاب بذر میتواند بهطور قابلتوجهی کارایی فازینگ را افزایش داده و به کشف سریعتر و بیشتر آسیبپذیریها کمک کند. با استفاده از راهبردهای مناسب انتخاب بذر، فازرها میتوانند (۱) بذرهایی را در اولویت قرار دهند که سودمندتر هستند؛ از جمله بذرهایی که پوشش کد بیشتری ایجاد میکنند یا احتمال بیشتری برای فعالسازی آسیبپذیریها دارند. (۲) از اتلاف منابع محاسباتی ناشی از اجرای مکرر مسیرهای مشابه جلوگیری کرده و بهرهوری را افزایش دهند. (۳) بذرهایی را به صورت بهینه انتخاب کنند که کدهای عمیقتر و مستعدتر به آسیبپذیری را پوشش میدهند و در نتیجه به شناسایی سریعتر آسیبپذیریهای پنهان کمک میکنند. AFL برای دستیابی به سرعت بالاتر در آزمونگیری، معمولاً موارد آزمون (Test Case) کوچکتر و سریعتر را ترجیح میدهد.
Böhme و همکاران (2017) فازر AFLFast را به عنوان یک فازر جعبهخاکستری مبتنی بر پوشش (Coverage-Based Greybox Fuzzer) معرفی کردند. آنها مشاهده کردند که بخش عمدهای از موارد آزمایشی (Test Cases) روی تعداد محدودی از مسیرهای اجرایی متمرکز میشوند. برای مثال، در یک برنامه پردازش PNG، بیشتر موارد آزمون تولیدشده از طریق جهش تصادفی نامعتبر هستند و مسیرهای مدیریت خطا را فعال میکنند.
AFLFast مسیرهای اجرایی را به دو دسته مسیرهای پرتکرار (High-Frequent) و کمتکرار (Low-Frequent) تقسیم میکند. در طول فرایند فازینگ، AFLFast فراوانی اجرای مسیرها را اندازهگیری کرده، به بذرهایی که تعداد دفعات کمتری فاز شدهاند اولویت میدهد و انرژی بیشتری را به بذرهایی اختصاص میدهد که مسیرهای کمتکرار را پیمایش میکنند.
Rawat و همکاران (2017) با ترکیب تحلیل ایستا (Static Analysis) و تحلیل پویا (Dynamic Analysis)، مسیرهای عمیق و دشوار برای دسترسی را شناسایی کرده و به بذرهایی که به این مسیرهای عمیق دست پیدا میکنند اولویت میدهند. راهبرد انتخاب بذر در VUzzer میتواند به کشف آسیبپذیریهایی که در مسیرهای اجرایی عمیق پنهان شدهاند کمک کند.
AFLGo (Böhme و همکاران، 2017) و QTEP (Wang و همکاران، 2017) از یک راهبرد انتخاب هدایت شده (Directed Selection Strategy) استفاده میکنند. AFLGo برخی بخشهای آسیبپذیر کد را به عنوان مکانهای هدف (Target Locations) تعریف میکند و موارد آزمونی را بهصورت بهینه انتخاب میکند که به این مکانهای هدف نزدیکتر باشند. در مقاله AFLGo چهار نوع کد آسیبپذیر به عنوان هدف معرفی شدهاند که شامل وصلهها (Patch)، کرشهای برنامه (Crash) که اطلاعات ردیابی کافی ندارند، نتایج تأییدشده توسط ابزارهای تحلیل ایستا و قطعات کد مرتبط با اطلاعات حساس میشوند.
با استفاده از یک الگوریتم هدایتشده مناسب، AFLGo میتواند منابع آزمونگیری بیشتری را به بخشهای جالب و مهم کد اختصاص دهد.
QTEP نیز از تحلیل ایستای کد برای شناسایی کدهای مستعد خطا (Fault-Prone) استفاده کرده و به بذرهایی که بخش بیشتری از این کدهای مستعد خطا را پوشش میدهند اولویت میدهد.
هر دو روش AFLGo و QTEP بهشدت به اثربخشی ابزارهای تحلیل ایستا وابسته هستند. با این حال، نرخ مثبت کاذب (False Positive) در ابزارهای تحلیل ایستای فعلی همچنان بالا است و این ابزارها هنوز نمیتوانند اعتبارسنجی کاملاً دقیقی ارائه دهند.
ویژگیهای آسیبپذیریهای شناختهشده نیز میتوانند در راهبرد انتخاب Seed مورد استفاده قرار گیرند. SlowFuzz (Petsios و همکاران، 2017) بر آسیبپذیریهای پیچیدگی الگوریتمی (Algorithmic Complexity Vulnerabilities) تمرکز دارد؛ آسیبپذیریهایی که معمولاً با مصرف بسیار بالای منابع محاسباتی همراه هستند. ازاینرو، SlowFuzz به بذرهایی اولویت میدهد که منابع بیشتری مانند زمان پردازنده (CPU Time) و حافظه را مصرف میکنند.
با این حال، جمعآوری اطلاعات مربوط به مصرف منابع سربار قابلتوجهی ایجاد کرده و کارایی فرایند فازینگ را کاهش میدهد. برای مثال، SlowFuzz برای اندازهگیری زمان پردازنده، تعداد دستورالعملهای اجراشده را شمارش میکند. علاوه بر این، SlowFuzz به اطلاعات بسیار دقیقی درباره میزان مصرف منابع نیاز دارد.
D.چگونه میتوان برنامهها را به طور کارآمد مورد آزمون قرار داد؟
برنامههای هدف به طور مکرر توسط فازرها در حلقه اصلی فازینگ راهاندازی و خاتمه مییابند. همانطور که میدانیم، برای فازینگ برنامههای کاربری، ایجاد و اتمام فرآیند زمان زیادی از CPU را مصرف میکند. ایجاد و اتمام مکرر فرآیند به شدت میتواند کارایی فازینگ را کاهش دهد.
در نتیجه، کارهای قبلی به انجام بسیاری از بهینه سازیها پرداختهاند. هر دو ویژگیهای سیستم سنتی و ویژگیهای جدید در این بهینه سازیها مورد استفاده قرار گرفتهاند. AFL از روش forkserver استفاده میکند، که یک کلون مشابه از برنامه قبلا بارگذاری شده ایجاد میکند و از این کلون برای هر بار اجرای منفرد استفاده خواهد کرد. علاوه بر این، AFL حالت پایدار (persistent mode) را نیز ارائه میدهد که به جلوگیری از بار اضافی ناشی از ()syscall execve و فرآیند لینکینگ کمک میکند و حالت موازی (parallel mode) که به موازیسازی تست در سیستمهای چند هستهای کمک میکند. فناوری Trace پردازنده اینتل (PT) (جیمز 2013) در فازینگ هسته برای کاهش بار ناشی از ردیابی پوشش استفاده میشود. ژو و همکاران (2017) به حل گلوگاههای عملکردی فازینگ موازی بر روی ماشینهای چند هستهای میپردازند. آنها با طراحی و پیادهسازی سه عملگر جدید سیستم عاملی، نشان میدهند که کار آنها میتواند به طور قابل توجهی فازرهای پیشرفتهای مانند AFL و LibFuzzer را تسریع بخشد.
تکنیکهای ترکیب شده در فازینگ (Techniques integrated in fuzzing)
برنامههای مدرن اغلب از ساختارهای داده بسیار پیچیده استفاده میکنند و عملیات تجزیه (Parsing) این ساختارهای داده پیچیده، احتمال بروز آسیبپذیریها را افزایش میدهد. راهبردهای فازینگ کور (Blind Fuzzing) که از روشهای جهش تصادفی استفاده میکنند، منجر به تولید حجم زیادی از موارد آزمون نامعتبر (Invalid Test Cases) و کاهش کارایی فازینگ میشوند.
در حال حاضر، فازرهای پیشرفته (State-of-the-Art Fuzzers) عموماً از راهبردهای فازینگ هوشمند (Smart Fuzzing) بهره میبرند. فازرهای هوشمند از طریق تکنیکهای تحلیل برنامه، اطلاعات مربوط به جریان کنترل (Control Flow) و جریان داده (Data Flow) را جمعآوری کرده و سپس از این اطلاعات برای بهبود فرایند تولید موارد آزمون استفاده میکنند. موارد آزمون تولیدشده توسط فازرهای هوشمند هدفمندتر هستند و احتمال بیشتری دارند که الزامات برنامه در زمینه ساختار داده و شروط منطقی را برآورده کنند. شکل ۵ نمایی کلی از فازینگ هوشمند را نشان میدهد.
برای ساخت یک فازر هوشمند، تکنیکهای متنوعی در فرایند فازینگ ادغام میشوند. همانطور که در بخشهای پیشین اشاره شد، فازینگ در عمل با چالشهای متعددی مواجه است. در این بخش، تلاش میکنیم تکنیکهای بهکاررفته در پژوهشهای پیشین و نحوه استفاده از این تکنیکها برای مقابله با چالشهای موجود در فرایند فازینگ را جمعبندی کنیم.
ما تکنیکهای اصلی ادغامشده در فازینگ را در جدول ۵ خلاصه کردهایم. برای هر تکنیک، تعدادی از پژوهشهای شاخص و نماینده نیز در جدول فهرست شدهاند. در این میان، هم از تکنیکهای سنتی مانند تحلیل ایستا (Static Analysis)، تحلیل آلودگی داده (Taint Analysis)، ابزاربندی کد (Code Instrumentation) و اجرای نمادین (Symbolic Execution) و هم از تکنیکهای نسبتاً جدید مانند یادگیری ماشین (Machine Learning) استفاده شده است. ما دو مرحله کلیدی در فرایند فازینگ، یعنی مرحله تولید موارد آزمایشی (Test Case Generation) و مرحله اجرای برنامه (Program Execution) را انتخاب کرده و نحوه بهبود فرایند فازینگ توسط این تکنیکهای ادغامشده را جمعبندی میکنیم.
تولید موارد آزمایشی (Testcase generation)
همانگونه که پیشتر اشاره شد، موارد آزمون (Test Cases) در فازینگ از طریق روشهای مبتنی بر تولید (Generation-Based) یا مبتنی بر جهش (Mutation-Based) ایجاد میشوند. چگونگی تولید موارد آزمونی که الزامات ساختارهای داده پیچیده را برآورده کنند و احتمال بیشتری برای فعالسازی مسیرهای دشوارِ قابلدسترسی (Hard-to-Reach Paths) داشته باشند، یکی از چالشهای اصلی در فازینگ محسوب میشود. پژوهشهای پیشین برای مقابله با این چالش، راهکارهای متنوعی را ارائه کردهاند که با بهرهگیری از تکنیکهای مختلف در فرایند فازینگ ادغام شدهاند.
در فازینگ مبتنی بر تولید (Generation-Based Fuzzing)، مولد (Generator) موارد آزمون را بر اساس دانش مربوط به قالب دادههای ورودی تولید میکند. اگرچه برای برخی از قالبهای رایج فایل مستندات در دسترس است، اما تعداد بسیار بیشتری از قالبها فاقد مستندات هستند. چگونگی بهدستآوردن اطلاعات مربوط به قالب ورودیها همچنان یک مسئله باز و دشوار به شمار میرود. برای حل این مشکل، از تکنیکهای یادگیری ماشین و روشهای مبتنی بر قالب (Format-Based Methods) استفاده شده است.
پژوهش Godefroid و همکاران (2017) از تکنیکهای یادگیری ماشین، بهطور مشخص شبکههای عصبی بازگشتی (Recurrent Neural Networks – RNNs)، برای یادگیری گرامر فایلهای ورودی استفاده میکند و سپس از گرامر آموختهشده برای تولید موارد آزمونی که با قالب مورد انتظار سازگار هستند بهره میبرد.
پژوهش Wang و همکاران (2017) از روشهای مبتنی بر قالب استفاده میکند. بهطور مشخص، این پژوهش یک گرامر احتمالی حساس به زمینه (Probabilistic Context-Sensitive Grammar) تعریف کرده و دانش مربوط به قالب ورودی را استخراج میکند تا ورودیهای بذر با ساختار و قالب صحیح تولید شوند.
بیشتر فازرهای پیشرفته امروزی از راهبرد فازینگ مبتنی بر جهش (Mutation-Based Fuzzing) استفاده میکنند. در این رویکرد، موارد آزمون از طریق تغییر بخشی از ورودیهای بذر در فرایند جهش تولید میشوند. در یک فرایند فازینگ مبتنی بر جهش کور (Blind Mutation Fuzzing)، جهشدهندهها (Mutators) بهصورت تصادفی بایتهای بذر را با مقادیر تصادفی یا چند مقدار ویژه تغییر میدهند که ناکارآمدی این روش به اثبات رسیده است. ازاینرو، تعیین محل اعمال تغییر و همچنین مقدار مورد استفاده در جهش، یکی دیگر از چالشهای کلیدی در فازینگ محسوب میشود.
در فازینگ مبتنی بر پوشش (Coverage-Based Fuzzing)، بایتهایی که میتوانند بر انتقال جریان کنترل (Control Flow Transfer) تأثیر بگذارند، باید در اولویت تغییر قرار گیرند. برای شناسایی این بایتهای کلیدی در Seedها، از تکنیک تحلیل آلودگی داده (Taint Analysis) استفاده میشود تا تأثیر بایتهای ورودی بر جریان کنترل ردیابی شود.
با این حال، شناسایی مکانهای کلیدی تنها آغاز کار است. فرایند فازینگ اغلب در برخی شاخهها (Branches) متوقف میشود؛ از جمله در اعتبارسنجیها (Validations) و بررسیهای مختلف (Checks). برای مثال، بایتهای جادویی (Magic Bytes) و سایر مقایسههای مقداری که در شرطهای تصمیمگیری استفاده میشوند.
برای عبور از این موانع، از تکنیکهایی مانند مهندسی معکوس (Reverse Engineering) و تحلیل آلودگی داده استفاده میشود. با پیمایش کد دودویی (Binary Code)، استخراج مقادیر فوری (Immediate Values) از عبارات شرطی و استفاده از این مقادیر بهعنوان مقادیر کاندید در فرایند جهش، فازرها میتوانند از برخی اعتبارسنجیها و بررسیهای کلیدی، مانند بررسی بایتهای جادویی و کنترل نسخه، عبور کنند.
پژوهش Rawat و همکاران (2017) از این رویکرد بهره میگیرد. همچنین، برای حل چالشهای قدیمی از تکنیکهای جدیدی مانند یادگیری ماشین نیز استفاده شده است. پژوهشگران مایکروسافت از روشهای یادگیری ماشین، از جمله شبکههای عصبی عمیق (DNN)، استفاده کردهاند تا بر اساس تجربیات حاصل از اجرایهای پیشین فازینگ و با بهرهگیری از LSTM، پیشبینی کنند که کدام بایتها باید دچار جهش شوند و چه مقادیری در فرایند جهش مورد استفاده قرار گیرند.
جدول 5. تکنیکهای ادغامشده در فازینگ
Program Execution | Testing Generation | |||
Path Exploration | Guiding | Mutation | Generation | Techniques |
* | * | * | Static analysis | |
* | * | Taint analysis | ||
* | * | * | Instrumentation | |
* | Symbolic execution | |||
* | * | Machin Learning | ||
* | Format Method | |||
اجرای برنامه (Program execution)
در حلقه اصلی فازینگ (Main Fuzzing Loop)، برنامههای هدف (Target Programs) بهصورت تکراری اجرا میشوند. اطلاعات وضعیت اجرای برنامه (Program Execution Status Information) استخراج شده و برای بهبود فرایند اجرای برنامه مورد استفاده قرار میگیرد. دو مسئله کلیدی (Key Problems) در فاز اجرای (Execution Phase) عبارتاند از: اینکه چگونه فرایند فازینگ (Fuzzing Process) هدایت شود (How to Guide the Fuzzing Process) و چگونه مسیرهای جدید (New Paths) کشف و پیمایش شوند (How to Explore New Paths).
فرایند فازینگ (Fuzzing Process) معمولاً بهگونهای هدایت میشود که پوشش کد (Code Coverage) افزایش یابد و باگها (Bugs) سریعتر کشف شوند؛ بنابراین اطلاعات مسیر اجرای برنامه (Path Execution Information) مورد نیاز است. تکنیک ابزارگذاری (Instrumentation Technique) برای ثبت مسیر اجرا (Path Execution) و محاسبه اطلاعات پوشش (Coverage Information) در فازینگ مبتنی بر پوشش (Coverage-Based Fuzzing) به کار میرود. بر اساس اینکه کد منبع (Source Code) در دسترس باشد یا خیر، هم ابزارگذاری درونکامپایل (Compiled-in Instrumentation) و هم ابزارگذاری خارجی (External Instrumentation) مورد استفاده قرار میگیرد.
در فازینگ هدفمند (Directed Fuzzing)، تکنیکهای تحلیل ایستا (Static Analysis Techniques) مانند تشخیص الگو (Pattern Recognition) برای مشخصسازی و شناسایی کد هدف (Target Code) که معمولاً آسیبپذیرتر است (More Vulnerable) استفاده میشوند. همچنین تحلیل ایستا (Static Analysis) میتواند برای جمعآوری اطلاعات جریان کنترل (Control Flow Information)، مانند عمق مسیر (Path Depth)، به کار رود که میتواند بهعنوان یک معیار کمکی در راهبرد هدایت (Guiding Strategy) مورد استفاده قرار گیرد (Rawat et al. 2017).
اطلاعات مسیر اجرا (Path Execution Information) که از طریق ابزارگذاری (Instrumentation) جمعآوری میشود، میتواند به هدایت بهتر فرایند فازینگ (Fuzzing Process) کمک کند. علاوه بر این، برخی ویژگیهای جدید نرمافزاری و سختافزاری نیز برای جمعآوری اطلاعات اجرا مورد استفاده قرار میگیرند.
Intel Processor Trace (Intel PT) یک قابلیت جدید ارائهشده توسط پردازندههای اینتل (Intel Processors) است که میتواند یک ردگیری دقیق و جزئی (Accurate and Detailed Trace) از فعالیت اجرا را همراه با قابلیتهای تحریک (Triggering) و فیلتر کردن (Filtering) فراهم کند تا به جداسازی بخشهای مهم ردیابی کمک کند (James 2013). با توجه به سرعت اجرای بالا (High Execution Speed) و عدم وابستگی به کد منبع (No Source Dependency)، Intel PT میتواند برای ردیابی دقیق و کارآمد اجرا مورد استفاده قرار گیرد. این قابلیت در فازینگ هسته سیستمعامل (OS Kernel Fuzzing) در ابزار KAFL (kAFL) به کار گرفته شده و کارایی بالایی از خود نشان داده است (Schumilo et al. 2017).
یکی دیگر از مسائل مهم در اجرای آزمون (Testing Execution)، کشف مسیرهای جدید (Exploring New Paths) است. فازرها (Fuzzers) باید بتوانند از شرطهای پیچیده (Complex Conditions) در منطق جریان کنترل برنامه (Control Flow of Programs) عبور کنند. تکنیکهای تحلیل برنامه (Program Analysis Techniques) شامل تحلیل ایستا (Static Analysis)، تحلیل آلودگی (Taint Analysis) و موارد مشابه (etc.) میتوانند برای شناسایی نقاط گلوگاهی (Block Points) در اجرا به منظور حل مرحلهای (Consequent Solving) مورد استفاده قرار گیرند.
تکنیک اجرای نمادین (Symbolic Execution) دارای مزیت طبیعی (Natural Advantage) در کشف مسیر (Path Exploration) است. این روش با حل مجموعه قیود (Constraint Set) میتواند مقادیری را محاسبه کند که الزامات خاص شرطی (Specific Conditional Requirements) را فراهم میکنند.
ابزار TaintScope (Wang et al. 2010) از تکنیک اجرای نمادین (Symbolic Execution Technique) برای حل اعتبارسنجی جمعآزما (Checksum Validation) استفاده میکند؛ عاملی که معمولاً فرایند فازینگ را متوقف میکند (Block the Fuzzing Process).
ابزار Driller (Stephens et al. 2016) نیز از اجرای کانکولیک (Concolic Execution) برای عبور از شرطهای کنترلی (Conditional Judgments) استفاده کرده و امکان کشف باگهای عمیقتر (Deeper Bugs) را فراهم میسازد.
پس از سالها توسعه، فازینگ (Fuzzing) بهمراتب ریزدانهتر (Fine-Grained)، انعطافپذیرتر (Flexible) و هوشمندتر (Smarter) از گذشته شده است. فازینگ مبتنی بر بازخورد (Feedback-Driven Fuzzing) یک روش کارآمد برای آزمون هدایتشده (Guided Testing) فراهم میکند؛ بهطوریکه تکنیکهای سنتی (Traditional Techniques) و نوین (New Techniques) نقش حسگرها (Sensors) را ایفا میکنند تا انواع اطلاعات (Various Information) را در طول اجرای آزمون (Testing Execution) جمعآوری کنند و فرایند فازینگ (Fuzzing) را به صورت دقیقتری هدایت نمایند.
فازینگ برای برنامههای مختلف (Fuzzing towards different applications)
فازینگ (Fuzzing) از زمان ظهور خود برای شناسایی آسیبپذیریها (Vulnerabilities) در طیف گستردهای از برنامهها (Massive Applications) مورد استفاده قرار گرفته است. با توجه به ویژگیهای مختلف برنامههای هدف (Target Applications)، فازرهای متفاوت (Different Fuzzers) و راهبردهای مختلف (Different Strategies) در عمل به کار گرفته میشوند. در این بخش، چندین نوع اصلی از برنامههایی که بهطور گسترده مورد فازینگ قرار گرفتهاند (Mainly Fuzzed Types of Applications) ارائه و خلاصه میشوند.
فازینگ قالب فایل (File format fuzzing)
بیشتر برنامهها (Applications) شامل مدیریت فایل (File Handling) هستند و فازینگ (Fuzzing) بهطور گسترده برای کشف باگها (Bugs) در این نوع برنامهها استفاده میشود. آزمون فازینگ (Fuzzing Test) میتواند روی فایلهایی با قالب استاندارد (Standard Format) یا بدون قالب استاندارد (Non-Standard Format) انجام شود.
رایجترین فایلها مانند اسناد (Document Files)، تصاویر (Image Files) و فایلهای چندرسانهای (Media Files) معمولاً دارای قالبهای استاندارد (Standard Formats) هستند. بیشتر پژوهشهای مرتبط با فازینگ (Fuzzing Research) عمدتاً بر فازینگ قالب فایل (File Format Fuzzing) تمرکز دارند و ابزارهای متعددی در این حوزه ارائه شدهاند؛ مانند Peach، فازر پیشرفته AFL (American Fuzzy Lop / AFL) و توسعههای آن (Extensions) (Rawat et al. 2017; Böhme et al. 2017).
در معرفیهای پیشین، انواع مختلفی از فازرهای قالب فایل (File Format Fuzzers) بررسی شدهاند و در این بخش بر سایر ابزارها تأکید بیشتری نمیشود.
یک زیرحوزه مهم از فازینگ قالب فایل (File Format Fuzzing)، فازینگ روی مرورگرهای وب (Web Browsers Fuzzing) است. با توسعه مرورگرهای وب (Web Browsers)، قابلیتهای آنها فراتر از گذشته گسترش یافته و مرورگرها (Browsers) اکنون از فایلهای متنوعتری نسبت به گذشته پشتیبانی میکنند؛ بهگونهای که دامنه فایلهای پردازششده (Handled File Types) از HTML، CSS و JS سنتی (Traditional HTML, CSS, JS Files) به انواع دیگری مانند PDF، SVG و سایر قالبهایی که توسط افزونههای مرورگر (Browser Extensions) مدیریت میشوند نیز توسعه یافته است.
بهطور مشخص، مرورگرها صفحات وب (Web Pages) را به یک درخت DOM (DOM Tree / Document Object Model Tree) تبدیل میکنند که ساختار صفحه وب را بهصورت یک درخت از اشیای سند (Document Object Tree) مدلسازی میکند و شامل رویدادها (Events) و پاسخها (Responses) نیز میباشد. بهویژه، فرایند تجزیه DOM (DOM Parsing) و رندر صفحات (Page Rendering) در مرورگرها در حال حاضر از اهداف محبوب فازینگ (Popular Fuzzing Targets) محسوب میشوند.
ابزارهای شناختهشده برای فازینگ مرورگرهای وب (Web Browser Fuzzing Tools) شامل چارچوب Grinder (Grinder Framework)، COMRaider (COMRaider) (Zimmer 2013)، و BF3 (Browser Fuzzer 3 / BF3) (Aldeid 2013) و موارد مشابه هستند.
فازینگ هسته (Kernel fuzzing)
فازینگ روی هسته سیستمعامل (OS Kernel Fuzzing) همواره یک مسئله دشوار (Hard Problem) بوده و با چالشهای متعددی (Many Challenges) همراه است. نخست، برخلاف فازینگ در فضای کاربر (Userland Fuzzing)، کرشها (Crashes) و هنگها (Hangs) در سطح هسته (Kernel) میتوانند کل سیستم را از کار بیندازند (Bring Down the Whole System) و نحوه شناسایی و جمعآوری این کرشها (Catching Crashes) همچنان یک مسئله باز (Open Problem) محسوب میشود.
دوم، مکانیزمهای سطح دسترسی سیستم (System Authority Mechanisms) باعث ایجاد یک محیط اجرایی نسبتاً بسته (Relatively Closed Execution Environment) میشوند؛ با توجه به اینکه فازرها (Fuzzers) معمولاً در حلقه ۳ (Ring 3 / User Mode) اجرا میشوند، نحوه تعامل با هسته (Interaction with Kernels) نیز یک چالش مهم دیگر است. بهترین روش رایج فعلی برای ارتباط با هسته (Communication with Kernel) استفاده از فراخوانیهای API هسته (Kernel API Functions) است.
علاوه بر این، هستههای پرکاربرد مانند هسته ویندوز (Windows Kernel) و هسته macOS (macOS Kernel) متنباز (Closed Source) نیستند و ابزارگذاری (Instrumentation) آنها با سربار عملکردی پایین (Low Performance Overhead) بسیار دشوار است. با توسعه فازینگ هوشمند (Smart Fuzzing)، پیشرفتهای جدیدی در حوزه فازینگ هسته (Kernel Fuzzing) حاصل شده است.
بهطور کلی، هستههای سیستمعامل (OS Kernels) از طریق فراخوانی تصادفی توابع API هسته (Kernel API Functions) با مقادیر پارامتری تصادفی (Randomly Generated Parameter Values) مورد فازینگ (Fuzzing) قرار میگیرند. بر اساس تمرکز فازرها (Focus of Fuzzers)، فازرهای هسته (Kernel Fuzzers) را میتوان به دو دسته تقسیم کرد: فازرهای مبتنی بر دانش (Knowledge-Based Fuzzers) و فازرهای هدایتشده با پوشش (Coverage-Guided Fuzzers).
در فازرهای مبتنی بر دانش (Knowledge-Based Fuzzers)، دانش مربوط به توابع API هسته (Kernel API Functions) در فرایند فازینگ (Fuzzing Process) مورد استفاده قرار میگیرد. بهطور مشخص، فازینگ با فراخوانیهای توابع API هسته (Kernel API Calls) با دو چالش اصلی (Main Challenges) مواجه است: (1) پارامترهای فراخوانیهای API (API Call Parameters) باید دارای مقادیر تصادفی اما در عین حال معتبر (Random yet Well-Formed Values) باشند که مطابق با مشخصات API (API Specification) هستند، و (2) ترتیب فراخوانیهای API هسته (Ordering of Kernel API Calls) باید معتبر (Valid) به نظر برسد (Han and Cha 2017).
کارهای شاخص در این حوزه شامل Trinity (Trinity) (Jones 2010) و IMF (IMF) (Han and Cha 2017) هستند. Trinity یک فازر هسته مبتنی بر نوع (Type-Aware Kernel Fuzzer) است. در Trinity، موارد آزمون (Testcases) بر اساس نوع پارامترها (Parameter Types) تولید میشوند. پارامترهای فراخوانیهای سیستمی (Syscalls Parameters) بر اساس نوع داده (Data Type) تغییر داده میشوند. علاوه بر این، برخی مقادیر شمارشی (Enumeration Values) و بازههای مقداری (Value Ranges) نیز برای کمک به تولید موارد آزمون معتبر (Well-Formed Testcases) ارائه میشوند.
در مقابل، IMF تلاش میکند ترتیب صحیح اجرای APIها (Correct Order of API Execution) و وابستگیهای مقداری بین فراخوانیهای API (Value Dependency Among API Calls) را یاد بگیرد و این دانش یادگرفتهشده (Learned Knowledge) را در تولید موارد آزمون (Testcase Generation) به کار بگیرد.
فازینگ مبتنی بر پوشش (Coverage-Based Fuzzing) در کشف باگهای برنامههای فضای کاربر (Userland Applications) موفقیت چشمگیری داشته است. به همین دلیل، پژوهشگران این روش را برای یافتن آسیبپذیریهای هسته سیستمعامل (Kernel Vulnerabilities) نیز بهکار گرفتهاند. از کارهای شاخص در این حوزه میتوان به syzkaller (Syzkaller) (Vyukov 2015)، TriforceAFL (TriforceAFL) (Hertz 2015) و kAFL (kAFL) (Schumilo et al. 2017) اشاره کرد.
Syzkaller از ابزارگذاری (Instrumentation) در سطح کامپایل (Compilation) استفاده میکند و هسته را روی مجموعهای از ماشینهای مجازی QEMU (QEMU Virtual Machines) اجرا مینماید. در این روش، هم اطلاعات پوشش کد (Code Coverage) و هم نقضهای امنیتی (Security Violations) در طول فازینگ پایش میشوند. TriforceAFL نسخهای اصلاحشده از AFL (American Fuzzy Lop / AFL) است که از طریق شبیهسازی کامل سیستم (Full-System Emulation) با QEMU امکان فازینگ هسته را فراهم میکند.
kAFL (kAFL) نیز از قابلیت سختافزاری جدید اینتل (Intel Processor Trace / Intel PT) برای ردیابی پوشش (Coverage Tracking) استفاده میکند و تنها کدهای مربوط به هسته (Kernel Code) را پایش مینماید. نتایج آزمایشها نشان میدهد که kAFL (kAFL) حدود ۴۰ برابر سریعتر از TriforceAFL است و کارایی فازینگ را بهطور قابل توجهی افزایش میدهد.
فازینگ پروتکلها (Fuzzing of protocols)
در حال حاضر، بسیاری از برنامههای محلی (Local Applications) به سرویسهای شبکهای (Network Services) در قالب مدل B/S (Browser/Server Mode) تبدیل شدهاند. این سرویسها روی شبکه (Network) مستقر میشوند و برنامههای کلاینت (Client Applications) از طریق پروتکلهای شبکه (Network Protocols) با سرورها (Servers) ارتباط برقرار میکنند. بنابراین، آزمون امنیتی پروتکلهای شبکه (Security Testing on Network Protocols) به یک دغدغه مهم دیگر (Important Concern) تبدیل شده است.
مشکلات امنیتی در پروتکلها (Protocol Security Problems) میتوانند آسیبهای جدیتری نسبت به برنامههای محلی ایجاد کنند؛ از جمله محرومسازی از سرویس (Denial of Service / DoS)، نشت اطلاعات (Information Leakage) و موارد مشابه.
فازینگ مشارکتی با پروتکلها (Cooperative Fuzzing with Protocols) در مقایسه با فازینگ قالب فایل (File Format Fuzzing) با چالشهای متفاوتی همراه است. نخست، برخی سرویسها (Services) ممکن است پروتکلهای ارتباطی اختصاصی (Custom Communication Protocols) خود را تعریف کنند که تعیین استانداردهای دقیق پروتکل (Protocol Standards) را دشوار میسازد. علاوه بر این، حتی برای پروتکلهای مستندشده (Documented Protocols) با تعریف استاندارد (Standard Definition)، پیروی دقیق از مشخصات (Specification) مانند اسناد RFC (RFC Documents) همچنان بسیار دشوار است.
از فازرهای شاخص پروتکل (Representative Protocol Fuzzers) میتوان به SPIKE (SPIKE) اشاره کرد که مجموعهای از ابزارها (Set of Tools) را فراهم میکند و به کاربران اجازه میدهد بهسرعت آزمونگرهای فشار (Network Protocol Stress Testers) برای پروتکلهای شبکه ایجاد کنند.
سِرگِی گوربونوف (Serge Gorbunov) و آرنولد روزنبلوم (Arnold Rosenbloom) ابزار AutoFuzz (Gorbunov and Rosenbloom 2010) را پیشنهاد کردند که با ساخت یک اتوماتای متناهی (Finite State Automaton / FSA)، پیادهسازی پروتکل را یاد میگیرد و سپس از این دانش یادگرفتهشده (Learned Knowledge) برای تولید موارد آزمون (Testcases) استفاده میکند.
گِرِگ بنکس (Greg Banks) و همکاران ابزار SNOOZE (Banks et al. 2006) را معرفی کردند که با استفاده از یک رویکرد فازینگ وضعیتمند (Stateful Fuzzing Approach) نقصهای پروتکل (Protocol Flaws) را شناسایی میکند.
همچنین کار جوئری دِ روایتر (Joeri de Ruiter) (De Ruiter and Poll 2015) یک روش فازینگ حالتپروتکلی (Protocol State Fuzzing) ارائه میدهد که در آن وضعیت کاری TLS (TLS Working State) به صورت یک ماشین وضعیت (State Machine) مدلسازی شده و فرایند فازینگ بر اساس جریان منطقی (Logical Flow) انجام میشود. بهطور کلی، کارهای پیشین معمولاً از روشهای وضعیتمند (Stateful Methods) برای مدلسازی فرایند کار پروتکل (Protocol Working Process) استفاده کرده و موارد آزمون (Testcases) را بر اساس مشخصات پروتکل (Protocol Specifications) تولید میکنند.
روندهای جدید فازینگ (New trends of fuzzing)
بهعنوان یک روش خودکار برای شناسایی آسیبپذیریها (Vulnerabilities)، فازینگ (Fuzzing) کارایی (Effectiveness) و بهرهوری (Efficiency) بالایی از خود نشان داده است. با این حال، همانطور که در بخشهای قبلی اشاره شد، همچنان چالشهای زیادی وجود دارد که باید حل شوند. در این بخش، یک معرفی مختصر از درک خود را بهعنوان مرجع ارائه میکنیم.
اول، فازینگ هوشمند (Smart Fuzzing) امکانات بیشتری برای بهبود فرایند فازینگ (Fuzzing Process) فراهم میکند. در کارهای پیشین، تحلیلهای ایستا و پویا (Static and Dynamic Analysis) سنتی برای کمک به بهبود این فرایند در فازینگ ادغام شدهاند. اگرچه تا حدی بهبود حاصل شده است، اما این پیشرفت محدود (Limited) بوده است. با جمعآوری اطلاعات اجرای برنامه هدف (Target Program Execution Information) از روشهای مختلف، فازینگ هوشمند (Smart Fuzzing) کنترل دقیقتری (More Elaborate Control) بر فرایند فازینگ فراهم میکند و راهبردهای متعددی (Fuzzing Strategies) پیشنهاد شدهاند. با درک عمیقتر از انواع مختلف آسیبپذیریها (Vulnerabilities) و بهرهگیری از ویژگیهای آنها در فازینگ، فازینگ هوشمند میتواند به کشف آسیبپذیریهای پیچیدهتر (More Sophisticated Vulnerabilities) کمک کند.
دوم، تکنیکهای جدید (New Techniques) میتوانند از جنبههای مختلف به بهبود کشف آسیبپذیری (Vulnerability Detection) کمک کنند. روشهایی مانند یادگیری ماشین (Machine Learning) و تکنیکهای مرتبط (Related Techniques) برای بهبود تولید موارد آزمون (Testcase Generation) در فازینگ به کار گرفته شدهاند. اینکه چگونه میتوان مزایا و ویژگیهای این تکنیکهای جدید را با فازینگ ترکیب کرد (Combine with Fuzzing)، و چگونه میتوان چالشهای کلیدی فازینگ را به مسائلی تبدیل کرد که این تکنیکها در حل آنها قوی هستند، یک موضوع قابل تأمل (Worthy of Consideration) دیگر است.
سوم، نباید ویژگیهای جدید نرمافزاری و سختافزاری (New System and Hardware Features) نادیده گرفته شوند. کارهای Vyukov (Syzkaller) (Vyukov 2015) و Schumilo (kAFL) (Schumilo et al. 2017) نشان دادهاند که قابلیتهای سختافزاری جدید (New Hardware Features) بهطور قابل توجهی کارایی فازینگ را افزایش دادهاند و الهامبخش (Inspiration) مهمی برای تحقیقات بعدی بودهاند.
نتیجهگیری (Conclusion)
فازینگ (Fuzzing) در حال حاضر مؤثرترین (Most Effective) و کارآمدترین (Most Efficient) راهکار برای کشف آسیبپذیریها (Vulnerability Discovery) محسوب میشود. در این مقاله، یک مرور جامع (Comprehensive Review) و جمعبندی (Summary) از فازینگ و آخرین پیشرفتهای آن ارائه شده است. در ابتدا، فازینگ (Fuzzing) با سایر روشهای کشف آسیبپذیری (Vulnerability Discovery Solutions) مقایسه شده و سپس مفاهیم (Concepts) و چالشهای کلیدی (Key Challenges) آن معرفی شدهاند. در ادامه، فازینگ مبتنی بر پوشش پیشرفته (State-of-the-Art Coverage-Based Fuzzing) بهصورت تأکیدی بررسی شده است که در سالهای اخیر پیشرفت چشمگیری (Great Progress) داشته است. در نهایت، تکنیکهای ادغامشده با فازینگ (Techniques Integrated with Fuzzing)، کاربردها (Applications) و روندهای احتمالی آینده (Possible New Trends) در حوزه فازینگ جمعبندی شدهاند.
اختصارات
AFL: American Fuzzy Lop
BB: Basic Block
DNN: Deep Neural Networks
LSTM: Long Short-Term Memory
POC: Proof of Concept
منابع
Aldeid (2013) Browser fuzzer 3. https://www.aldeid.com/wiki/Bf3. Accessed 25 Dec 2017.
Amini, P (2017) Sulley fuzzing framework. https://github.com/OpenRCE/sulley. Accessed 25 Dec 2017.
Banks, G, Cova M, Felmetsger V, Almeroth K, Kemmerer R, Vigna G (2006) Snooze: toward a stateful network protocol fuzzer In: International Conference on Information Security, 343–358.. Springer, Berlin.
Böhme, M, Pham V-T, Nguyen M-D, Roychoudhury A (2017) Directed greybox fuzzing In: Proceeding CCS ’17 Proceedings of the 2017 ACM SIGSAC Conference on Computer and Communications Security, 2329–2344.. ACM, New York. https://doi.org/10.1145/3133956.3134020.
Böhme, M, Pham VT, Roychoudhury A (2017) Coverage-based greybox fuzzing as markov chain In: Proceedings of the 2016 ACM SIGSAC Conference on Computer and Communications Security, 1032–1043.. ACM.
Bowne, S (2015) Fuzzing with spike. https://samsclass.info/127/proj/p18-spike.htm. Accessed 25 Dec 2017.
Cha, SK, Avgerinos T, Rebert A, Brumley D (2012) Unleashing mayhem on binary code In: Security and Privacy (SP) 2012 IEEE Symposium on, 380–394.. IEEE, San Francisco. https://doi.org/10.1109/SP.2012.31.
De Ruiter, J, Poll E (2015) Protocol state fuzzing of tls implementations In: Proceeding SEC’15 Proceedings of the 24th USENIX Conference on Security Symposium, 193–206.. USENIX Association, Berkeley.
Godefroid, P, Levin MY, Molnar D (2012) Sage: whitebox fuzzing for security testing. Queue 10(1):20.
Godefroid, P, Peleg H, Singh R (2017) Learn & fuzz: Machine learning for input fuzzing In: Proceeding ASE 2017 Proceedings of the 32nd IEEE/ACM International Conference on Automated Software Engineering, 50–59.. IEEE Press, Piscataway.
Gorbunov, S, Rosenbloom A (2010) Autofuzz: Automated network protocol fuzzing framework. IJCSNS 10(8):239.
Han, H, Cha SK (2017) Imf: Inferred model-based fuzzer In: Proceeding CCS ’17 Proceedings of the 2017 ACM SIGSAC Conference on Computer and Communications Security, 2345–2358.. ACM, New York. https://doi.org/10.1145/3133956.3134103.
Hertz, J (2015) Triforceafl. https://github.com/nccgroup/TriforceAFL. Accessed 25 Dec 2017.
James, R (2013) Processor tracing. https://software.intel.com/en-us/blogs/2013/09/18/processor-tracing. Accessed 25 Dec 2017.
Jones, D (2010) trinity. https://github.com/kernelslacker/trinity. Accessed 25 Dec 2017.
King, JC (1976) Symbolic execution and program testing. Commun ACM 19(7):385–394.
lcamtuf (2014) Fuzzing random programs without execve(). https://lcamtuf.blogspot.jp/2014/10/fuzzing-binaries-without-execve.html. Accessed 25 Dec 2017.
libfuzzer (2017) A library for coverage-guided fuzz testing. https://llvm.org/docs/LibFuzzer.html. Accessed 25 Dec 2017.
Liu, B, Shi L, Cai Z, Li M (2012) Software vulnerability discovery techniques: A survey In: Multimedia Information Networking and Security (MINES), 2012 Fourth International Conference on, 152–156.. IEEE, Nanjing. https://doi.org/10.1109/MINES.2012.202.
Luk, C-K, Cohn R, Muth R, Patil H, Klauser A, Lowney G, Wallace S, Reddi VJ, Hazelwood K (2005) Pin: building customized program analysis tools with dynamic instrumentation In: Acm sigplan notices, volume 40, 190–200.. ACM, Chicago.
Nichols, N, Raugas M, Jasper R, Hilliard N (2017) Faster fuzzing: Reinitialization with deep neural models. arXiv preprint arXiv:1711.02807.
PeachTech (2017) Peach. https://www.peach.tech/. Accessed 25 Dec 2017.
Petsios, T, Zhao J, Keromytis AD, Jana S (2017) Slowfuzz: Automated domain-independent detection of algorithmic complexity vulnerabilities In: Proceeding CCS ’17 Proceedings of the 2017 ACM SIGSAC Conference on Computer and Communications Security, 2155–2168.. ACM, New York. https://doi.org/10.1145/3133956.3134073.
Rajpal, M, Blum W, Singh R (2017) Not all bytes are equal: Neural byte sieve for fuzzing. arXiv preprint arXiv:1711.04596.
Rawat, S, Jain V, Kumar A, Cojocar L, Giuffrida C, Bos H (2017) Vuzzer: Application-aware evolutionary fuzzing In: Proceedings of the Network and Distributed System Security Symposium (NDSS). https://www.vusec.net/download/?t=papers/vuzzer_ndss17.pdf.
Schumilo, S, Aschermann C, Gawlik R, Schinzel S, Holz T (2017) kAFL: Hardware-assisted feedback fuzzing for OS kernels. In: Kirda E Ristenpart T (eds)26th USENIX Security Symposium, USENIX Security 2017, 167–182.. USENIX Association, Vancouver.
Serebryany, K, Bruening D, Potapenko A, Vyukov D (2012) Addresssanitizer: A fast address sanity checker In: Proceeding USENIX ATC’12 Proceedings of the 2012 USENIX conference on Annual Technical Conference, 309–318.. USENIX Association, Berkeley.
Serebryany, K, Iskhodzhanov T (2009) Threadsanitizer: data race detection in practice In: Proceedings of the Workshop on Binary Instrumentation and Applications, 62–71.
Shirey, RW (2000) Internet security glossary. https://tools.ietf.org/html/rfc2828. Accessed 25 Dec 2017.
Stephenfewer (2016) Grinder. https://github.com/stephenfewer/grinder. Accessed 25 Dec 2017.
Stephens, N, Grosen J, Salls C, Dutcher A, Wang R, Corbetta J, Shoshitaishvili Y, Kruegel C, Vigna G (2016) Driller: Augmenting fuzzing through selective symbolic execution In: NDSS, volume 16, 1–16, San Diego.
Sutton, M, Greene A, Amini P (2007) Fuzzing: brute force vulnerability discovery. Pearson Education, Upper Saddle River.
Takanen, A, Demott JD, Miller C (2008) Fuzzing for software security testing and quality assurance. Artech House.
The Clang Team (2017) Dataflowsanitizer. https://clang.llvm.org/docs/DataFlowSanitizerDesign.html. Accessed 25 Dec 2017.
The Clang Team (2017) Leaksanitizer. https://clang.llvm.org/docs/LeakSanitizer.html. Accessed 25 Dec 2017.
Van Sprundel, I (2005) Fuzzing: Breaking software in an automated fashion. Decmember 8th.
Vyukov, D (2015) Syzkaller. https://github.com/google/syzkaller. Accessed 25 Dec 2017.
Wang, J, Chen B, Wei L, Liu Y (2017) Skyfire: Data-driven seed generation for fuzzing In: Security and Privacy (SP), 2017 IEEE Symposium on.. IEEE, San Jose. https://doi.org/10.1109/SP.2017.23.
Wang, S, Nam J, Tan L (2017) Qtep: quality-aware test case prioritization In: Proceedings of the 2017 11th Joint Meeting on Foundations of Software Engineering, 523–534.. ACM, New York. https://doi.org/10.1145/3106237.3106258.
Wang, T, Wei T, Gu G, Zou W (2010) Taintscope: A checksum-aware directed fuzzing tool for automatic software vulnerability detection In: Security and privacy (SP) 2010 IEEE symposium on, 497–512.. IEEE, Berkeley. https://doi.org/10.1109/SP.2010.37.
Wichmann, BA, Canning AA, Clutterbuck DL, Winsborrow LA, Ward NJ, Marsh DWR (1995) Industrial perspective on static analysis. Softw Eng J 10(2):69–75.
Wikipedia, Wannacry ransomware attack (2017). https://en.wikipedia.org/wiki/WannaCry_ransomware_attack. Accessed 25 Dec 2017.
Wikipedia (2017) Dynamic program analysis. https://en.wikipedia.org/wiki/Dynamic_program_analysis. Accessed 25 Dec 2017.
Wu, Z-Y, Wang H-C, Sun L-C, Pan Z-L, Liu J-J (2010) Survey of fuzzing. Appl Res Comput 27(3):829–832.
Xu, W, Kashyap S, Min C, Kim T (2017) Designing new operating primitives to improve fuzzing performance In: Proceeding CCS ’17 Proceedings of the 2017 ACM SIGSAC Conference on Computer and Communications Security, 2313–2328.. ACM, New York. https://doi.org/10.1145/3133956.3134046.
Yang, Q, Li JJ, Weiss DM (2007) A survey of coverage-based testing tools. The Computer Journal 52(5):589–597.
Zalewski, M (2017) American fuzzy lop. http://lcamtuf.coredump.cx/afl/. Accessed 25 Dec 2017.
Zalewski, M (2017) Afl technical details. http://lcamtuf.coredump.cx/afl/technical_details.txt. Accessed 25 Dec 2017.
Zimmer, D (2013) Comraider. http://sandsprite.com/tools.php?id=16. Accessed 25 Dec 2017.