بخشی از مقاله
در این مقاله روشی برای خودکارسازی تولید کد بهرهجو برای آسیبپذیری سرریز Heap ارائه شده است. در این روش کاربر با اطلاع از وجود آ سیبپذیری سرریز Heap در کد یک برنامه و م شخص کردن آن میتواند قابلیت بهرهجویی آن آ سیبپذیری را با ا ستفاده از تکنیک Unlink بررسی کند. الگوریتم ارائه شده با دریافت کد یک برنامهی آسیبپذیر و محل وقوع آسیبپذیری، اقدام به تولید کد بهرهجو برای آن آسیبپذیری میکند و در صورت موفقیت در تولید کد بهرهجو، آن را یک آسیبپذیری قابل بهرهجویی اعلام میکند. الگوریتم ارائه شده پس از پیادهسازی، با ا ستفاده از مجموعه کدهای ت ست ارائه شده در پروژه SAMATE مو س سه NIST مورد ارزیابی قرار گرفته ا ست و موفق بوده تا برای 3 مورد از آسیبپذیریهای سرریز Heap آن مجموعه با استفاده از تکنیک Unlink کد بهرهجو ایجاد بکند.
-1 مقدمه
آسیبپذیری نرمافزار نقص یا ضعف در بخشی از برنامه است که میتوان با ا ستفاده از آن خط م شی امنیتی سی ستم را نقض کرد.[1] آسیبپذیریهای نرمافزار از مهمترین موضوعات حوزهی امنیت سایبری هستند که یک رخنهگر میتواند با کشف و استفاده از آنها آسیبهای جدّی و خطرناکی را برای آن نرمافزار، یا سیستمعاملی که آن نرمافزار بر روی آن اجرا شده است، بوجود بیاورد. اثر سؤ و نامطلوب آ سیبپذیریهای نرمافزار به یک اندازه نیست.
برخی از آسیبپذیریهای نرمافزار فقط میتوانند منجر به خرابی عملکرد نرمافزار شده و برخی دیگر منجر به اجرای کد دلخواه بر روی سیستمعامل هدف شوند. بنابراین آ سیبپذیریهای نرمافزار را میتوان با توجه به میزان آ سیبی که دا شته با شند به دو د ستهی آ سیبپذیریهای قابل بهرهجویی و غیر قابل بهرهجو تق سیم کرد. آ سیبپذیریهای قابل بهرهجو آن دسته از آسیبپذیریها هستند که رخنهگر میتواند با استفاده از آن کد دلخواه خود را اجرا کند.
[2] برای اطمینان از امکان بهرهجویی یک آسیبپذیری، لازم است کد بهرهجوی مربوط به آن آسیبپذیری را بدست آورد. از آنجا که نوشتن و ایجاد کد بهرهجو برای یک آسیبپذیری نیازمند دانش، تخصص و زمان بسیاری است، از این رو الگوریتمهایی با عنوان الگوریتمهای خودکار سازی تولید کد بهرهجو مطرح شدهاند که تلاش میکنند با تولید کد بهرهجو برای یک آسیبپذیری، امکان بهرهجویی آن را بررسی کنند.
امروزه با تو جه به آن که م کانیزم های امنیتی و ح فاظتی گستردهای مانند ASLR، W⊕X و [3] DEP برای مقابله با بهرهجویی از آسیبپذیریهای نرمافزار ارائه و پیادهسازی شدهاند، لکن هنوز بهرهجوییهای گ ستردهای از آ سیبپذیریهای نرمافزار وجود دارد که میتوان برای مثال به بهرهجویی از آ سیبپذیری با شناسهی CVE-2017-0144 اشاره کرد که در آوریل سال 2017 میلادی کد بهرهجوی آن با نام EternalBlue منت شر شد و از آن کد بهرهجو در باجگیرافزار WannaCry جهت آلوده سازی بیش از 200 هزار سیستم کامپیوتری در بیش از 150 کشور دنیا استفاده شد.
[4] علاوه بر این روش های متفاوتی برای دور زدن چنین مکانیزم های حفاظتی مانند ROP، JOP و ... معرفی شدهاند و آنچنان توسعه یافتهاند که روشی برای دور زدن مکانیزمهای حفاظتی بصورت خودکار با عنوان [5] Q ارائه شده است. بنابراین لازم ا ست جهت امن سازی نرمافزارها و سی ستمهایی که آنها بر روی آن فعالیت میکنند، علاوه بر استفاده و تقویت مکانیزمهای حفاظتی، آسیبپذیریهای نرمافزار نیز کشف و وصله شوند و در این بین کشف و وصله کردن آسیبپذیریهای با قابلیت بهرهجوییبه دلیل برخورداری از اهمیّت بالاتر و خطر بیشتری که دارا هست ند، اولو یت بالاتری داش ته و ق بل از دیگر آسیبپذیریها باید کشف و وصله شوند.
اولین روش تول ید خود کار کد بهرهجو با نام [6] AEG در سال 2011 و پس از آن دو روش دیگر با نامهای MAYHEM [7] و [8] CRAX در سال 2012 ارائه شد که هر کدام از آنها با محدودیتهایی بخصوص در پشتیبانی از انواع آسیبپذیریها روبروست. یکی از مسائل حل نشدهای که این روشها مطرح کردها ند، ارا ئهی روشی برای تول ید خود کار کد بهرهجو برای آسیبپذیریهای سرریز Heap است.
آسیبپذیری سرریز Heap از جمله آسیبپذیریهای تخریب حافظه است که از خطرناکترین آسیبپذیریهای نرمافزار هستند. این آسیبپذیری میتواند همانند آسیبپذیری سرریز پشته قابلیت اجرای کد دلخواه را به فرد رخنهگر بدهد، لکن برخلاف آ سیبپذیریهای سرریز پ شته، تاکنون روش م شخص و جامعی برای بهرهجویی از آسیبپذیریهای سرریز Heap ارائه نشده است. باتوجه به شرایط رخ دادن یک آسیبپذیری سرریز Heap، نحوه بهرهجویی از آن مختلف خوا هد بود. تاکنون تکن یک هایی برای بهرهجویی از آسیبپذیری سرریز Heap ارائه شده است که یکی از متداولترین آنها تکنیک Unlink است.[9]
م سئلهی حل ن شدهی مورد برر سی در این پژوهش، بد ست آوردن روشی برای بررسی قابلیت بهرهجویی یک آسیبپذیری سرریز Heap است. روش ارائه شده تلاش میکند با تولید کد بهرهجو برای یک آ سیبپذیری سرریز Heap، م شخ صهی قابلیت بهرهجویی آن آسیبپذیری را بررسی کند. این روش با دریافت کد برنامهی مورد نظر و آدرس آ سیبپذیری سرریز Heap سعی میکند با استفاده از تکنیک Unlink برای آن آسیبپذیری کد بهرهجو تولید کند. در روش پیشنهادی ابتدا امکان استفاده از تکنیک Unlink برای آسیبپذیری معرفی شده بررسی میشود و در صورت امکان فرآیند تولید کد بهرهجو شروع میشود. در صورت موفقیت در ایجاد کد بهرهجو، موفقیت یا شکست کد تول یدی در تغییر جر یان کنترلی بر نا مهی ورودی و اجرای کد دلخواه بررسی شده و در صورت اجرای کد دلخواه، آن آسیبپذیری قابل بهرهجویی معرفی میشود.
در ادامه در بخش دوم، مفاهیم پایه مورد نیاز برای بخشهای بعد شرح داده میشود. سپس در بخش سوم روش ارائه شده جهت تولید خودکار کد بهرهجو توضیح داده میشود. در بخش چهارم به پیاده سازی و در بخش پنجم به نحوهی ارزیابی و ت ست پیادهسازی پرداخته میشود. بخش ششم کارهای مرتبط پیشین را مورد برر سی قرار داده و در بخش پایانی مقاله نیز جمعبندی و نتیجهگیری این پژوهش آورده شده است.
-2 مفاهیم پایه
قبل از بیان روش ارائه شده، مفاهیم حافظهی Heap و نحوهی تخصیص آن، آسیبپذیری سرریز Heap، بهرهجویی از آ سیبپذیریها و تکنیکهای بهرهجویی از آ سیبپذیری سرریز Heap توضیح داده میشوند.
-1-2 حافظه Heap
قسمتی از حافظهی سیستم که بصورت پویا توسط برنامهنویس به برنامه تخ صیص داده می شود، حافظهی Heap نام دارد. بر نا مهنویس میتوا ند حاف ظهی Heap را در ز مان اجرای برنامه دریافت کند و هرگاه بخواهد درخوا ست تغییر اندازه یا آزاد کردن آن را بدهد. برنامه نویسان برای تخصیص حافظه Heap از تخصیص دهندههای حافظه که در سیستمعامل وجود دارند استفاده میکنند و با آنها میتوانند پس از رفع نیاز به آن قسمت از حافظه، آن را آزاد کرده تا سیستمعامل با کمبود حافظه مواجه نشود. یکی از رایجترین و پر کاربردترین تخصیصده نده ها، - Doug Lee Malloc - dlmalloc نام دارد که روش ارائه شدهی این پژوهش مبتنی بر آن طراحی شده است.[10]
سیستمعامل به جهت مدیریت بهتر حافظهی Heap، آن را بصورت قطعهای در نظر میگیرد. هر قطعه ممکن است به دو صورت اخت صاص یافته یا آزاد با شد. همی شه دو قطعه آزاد کنار هم ادغام میشوند تا با ایجاد یک قطعه آزاد بزرگتر، احتمال کمبود حافظه را کاهش بدهند. هر قطعه دارای اندازهی مشخص است و ساختار آن مطابق شکل 1 شامل بخشهای سرآیند، پرچمها و داده میشود.
شکل 1 ساختار یک قطعه از حافظه
بخش سرآیند هر قطعه شامل چهار حوزه با نامهای اندازه قط عه قبلی - Prev_Size - ، ا ندازهی قط عه، fd - آدرس قطعهی بعدی و bk آدرس قطعه قبلی است. از آنجا که اندازهی هر قطعه مضربی از 8 بایت است، بنابراین سه بیت کم ارزش حوزههای اندازهی قطعه قبلی و اندازه همیشه صفر خواهد بود، از این رو سیستمعامل از دو بیت کم ارزش حوزهی اندازه جهت نگهداری پرچمهای، Prev_inuse و is_mmaped استفاده میکند. پرچم Prev_inuse وضعیت قطعه قبلی - اختصاص یافته یا آزاد بودن - را مشخص میکند.
سیستم عامل برای مدیریت بهتر قطعات آزاد و یافتن منا سبترین قطعه به هنگام نیاز، آنها را ب صورت مرتب شده بر اساس اندازه، در گروههایی با نام bin نگهداری میکند. در هر bin قطعاتی با بازهی اندازه ای مشخص قرار میگیرد. هر bin یک لیست پیوندی دو طرفه است که اجزای آن قطعات آزاد با اندازهی مناسب با بازهی اندازهای آن bin است. تخصیص دهندهی dlmalloc از دو ماکروی Unlink و Frontlink جهت حذف و درج یک قطعه از bin استفاده میکند. ماکروی Unlink تنها کاری که انجام میدهد، قرار دادن اشارهگر fd یک قطعه مورد نظر به fd، قطعه قبلی و اشارهگر bk قطعه مورد نظر بهbk، قطعه بعدی است. کد این ماکرو در شکل 2 قابل مشاهده است. در کد این ماکرو، آدرس قطعهی مورد نظر برای حذف از bin، با اشارهگر P مشخص میشود.
شکل 2 کد ماکروی Unlink
دو تابع اصلی که هر تخصیصدهندهای با ارائهی آنها به درخواست برنامهنویسان پاسخ میدهند، malloc - size_t n - و free - void_t* p - هستند که اولی برای درخواست یک قطعه با اندازهی مشخص شدهی n و دومی برای آزاد کردن قطعهای با آدرس p است. همانطور که قبلاً گفته شد، هر دو قطعه آزاد کنار هم ادغام میشوند تا یک قطعه بزرگتر را ایجاد کنند، از این رو تخصیصدهندهی dlmalloc پس از هر فراخوانی تابع free، آزاد بودن قطعههای بعدی و قبلی را برر سی میکند و در صورت آزاد بودن هر کدام از آن ها، ماکروی Unlink را روی آن فراخوانی میکند تا پس از خارج کردن آن از bin مربوطه، آن را با قطعه فعلی که آزاد میشود ادغام کرده و یک قطعهی بزرگتر را تشکیل بدهد.
-2-2 آسیبپذیری سرریز Heap
مطابق تعریف [11]، آسیبپذیری نرمافزار نقص یا ضعفی ا ست که با یک ا شتباه در طراحی، پیاده سازی یا پیکربندی یک نرمافزار اتفاق میافتد که ممکن است بتوان با بهرهجویی از آن خط م شی امنیتی ب صورت صریح یا ضمنی نقض شود. در [12] نیز تعریف مشابهی ارائه شده است و در آنجا آسیبپذیری را اشتباه یا نقصی در قسمتی از برنامه تعریف کرده است که به مهاجمان اجازه میدهد عمل بدخواهانهای را انجام دهند. این عمل میتواند افشا یا تغییر اطلاعات حساس، مختل کردن یک سیستم و یا به دست گرفتن کنترل یک برنامه باشد. انواع مختلفی از آ سیبپذیریهای نرمافزار وجود دارد که میزان آ سیب و خطر آنها با هم متفاوت است. از خطرناکترین آسیبپذیریها، مواردی هستند که منجر به تخریب حافظه میشوند، که از جملهی آنها میتوانبه آسیبپذیریهای سرریز بافر و قالب رشته اشاره کرد.
آسیبپذیری سرریز Heap از جمله آسیبپذیریهای سرریز بافر ا ست که در آن، بافر آ سیبپذیر ق سمتی از حافظهی Heap ا ست. آ سیبپذیریهای سرریز بافر به دلیل عدم رعایت اندازهی بافر در نوشتن در آن، صورت میگیرد و باعث میشود پس از ت جاوز از ا ندازهی بافر، دیگر اطلا عات حاف ظه را از بین برده و تخریب کند. فرد بد خواه میتواند این تخریب اطلاعات را هدفمند انجام داده تا م سیر جریان کنترلی برنامه را به م سیر مورد نظرش تغییر بدهد. برای مثال در قطعه کد شکل 3، دو بافر first و second از حافظهی Heap تخصیص داده میشوند و در خط 10، مقدار ورودی کاربر به بافر first منتقل میشود بدون آنکه به اندازهی مقدار ورودی کاربر توجهی بکند، بنابراین در اینجا یک آسیبپذیری سرریز Heap اتفاق میافتد و مهاجم میتواند با دادن مقداری بزرگتر از 12 بایت به برنامه، اطلاعات بافر second و حافظهی سیستم را تخریب کند.