موضوع مقاله: برنامه‌نویسی بازگشت محور | مخاطب: عمومی | لحن: دانشنامه‌ای | ساختار: عنوان، مقدمه، 3 بخش، جمع‌بندی | مقاله: | # برنامه‌نویسی بازگشت محور | مقدمه: برنامه‌نویسی بازگشت محور یکی از تکنیک‌هایی می‌باشد برای انجام exploit در زمان‌هایی که مکانیزم‌های امنیتی مانند مکانیزم‌هایی که جلوگیری از اجرای کد در قسمت‌های مختلف حافظه پیاده‌سازی شده‌اند استفاده می‌شود. | ## بخش 1: برنامه‌نویسی بازگشت محور | در این تکنیک حمله کنند بعد از به دست گرفتن control flow برنامه، لیستی از دستورات اسمبلی مناسب داخل برنامه را پیدا کرده که به آنها ابزارک گفته می‌شود، که هرکدام از این ابزارکها قسمتی از کار اصلی مخرب را انجام می‌دهند، و معمولاً این ابزارکها با دستور return خاتمه پیدا می‌کنند و محل آنها می‌تواند داخل خود کد برنامهٔ مورد هدف باشد یا داخل کد کتابخانه‌های بارگذاری شده در حافظه. حمله کننده به ترکیب این ابزارکها و پیدا کردن ترتیب مناسب برای پرش به هرکدام کار مخرب خود را انجام می‌دهد. اما بسیاری از سیستم‌های عامل و کامپایلرها برای جلوگیری از اینگونه حملات مکانیزم‌های امنیتی مختلفی را معرفی کردند که در این تکنیک محل‌هایی از حافظه که داده‌ها در آنها ذخیره می‌شوند مانند stack که قابلیت write نیز دارند نباید قابلیت اجرایی داشته باشند، تکنیکی که بعدها به W^X معروف شد که به معنای این می‌باشد که محل‌هایی از حافظه که قابلیت write دارند نباید قابلیت executable نیز داشته باشند زیرا حمله کننده می‌تواند با تغییر مقادیر این محل‌ها کنترل برنامه را به دست بگیرد. با این مکانیزم امنیتی دیگر حمله کننده‌ها نمی‌توانند به محل‌هایی از حافظه که قابلیت write در آنها می‌باشد مانند stack برای اجرای کد خود پرش کنند و در نتیجه نمی‌توانند payload خود را داخل stack نوشته و برای اجرایش به آن پرش کنند، در نتیجه حمله کننده‌ها برای دور زدن این مکانیزم‌های امنیتی به تکنیک‌های دیگری رو آوردند که از کدهای موجود داخل برنامه و کتابخانه‌ها برای اجرای کارهای مخرب خود استفاده می‌کند. در کل حمله کنندگان دو انتخاب برای پرش دارند، یکی استفاده از کدهای کتابخانه‌های لود شده در حافظه که به روش Ret2Lib معروف است و دیگری استفاده از کدهای خود برنامهٔ مورد هدف. Ret2Lib در این روش حمله کننده از کدهای موجود در کتابخانه‌های بارگذاری شده در حافظه برای انجام اعمال مخرب خود استفاده می‌کند، یعنی به جای پرش به داخل خود stack و اجرای payload از داخل آن، به یک سری از توابع داخل کتابخانه‌های بارگذاری شده پرش می‌کند. Borrowed Code Chunk با ظهور پردازشگرهای x64 نحوهٔ پاس دادن ارگومان‌ها به توابع تغییر کرد، و به جای اینکه ارگومان‌ها داخل stack قرار داده شوند، داخل یک سری از رجیسترها قرار داده می‌شوند، در نتیجه دیگر حمله کننده‌ها نمی‌توانستند به راحتی به توابع کتابخانه‌ای پرش کرده و ارگومان را داخل stack قرار دهند و همچنین توسعه‌دهندگان کتابخانه‌ها نیز بعضی از توابع مورد هدف حمله کننده‌ها را از کد خود حذف کردند، در نتیجه انجام حملات ret2lib پس از این تغییرات بسیار دشوارتر شد. برای دور زدن این محدودیت‌ها حمله کننده‌ها به جای پرش مستقیم به توابع، از قسمت‌هایی از کدهای موجود در توابع استفاده کرده و به آنها پرش می‌کردند که کارهای مورد نیاز آنها را انجام دهد، برای مثال به قسمت‌هایی پرش می‌کردند که مقادیر داخل stack را در داخل رجیسترهای مورد هدف قرار می‌دهد و در نتیجه با اینکار آرگومان‌هایی مورد نیاز را به توابع پاس می‌دادند، باقی حمله نیز مانند ret2lib انجام می‌شد. در واقع برنامه‌نویسی بازگشت محور یک زبان کامل و کارا را در اختیار حمله کننده می‌گذارد تا هر نوع عمل مورد نیاز را توسط آن انجام دهد و در سال ۲۰۰۷، Hovav Shacham نشان داده که تمامی اعمال مهم برنامه‌نویسی را با این روش می‌توان انجام داد. اینگونه حمله نسبت به دیگر حملات هم از لحاظ قدرت و هم از لحاظ دور زدن مکانیزهای امنیتی برتری دارد. حمله به معماری x86 با اینکه حملهٔ برنامه‌نویسی بازگشت محور در هر معماری قابل انجام است، تمرکز مقالهٔ Shacham روی معماری X86 می‌باشد. | ## بخش 2: برنامه‌نویسی بازگشت محور | حملهٔ برنامه‌نویسی بازگشت محور در x86 از این خاصیت معماری استفاده می‌کند که هر ترتیبی از بایت‌های به احتمال بالا می‌توانند به عنوان دستورات x86 استفاده شوند. در نتیجه می‌توان به دنبال بایت‌هایی مانند 0xC3 گشت که دستور ret می‌باشد، و بایت‌های قبل آن را برای استفاده به عنوان دستور چک کرد و در صورتی که کدهای قابل اجرا و مفید باشند، آنرا می‌توان به عنوان یک ابزارک در نظر گرفت و به لیست ابزارکهای قابل استفاده اضافه کرد. در این روش حمله ابزارکهایی از کد خود برنامه را به دقت انتخاب می‌کند، به گونه‌ای که با اجرای پشت سرهم آنها کار مخربش انجام شود. بنابرین حمله کننده آدرس‌های این ابزارکهای که معمولاً نیز با دستور ret ختم می‌شوند را پیدا می‌کند، و آدرس‌های آنها را داخل stack به ترتیب اجرا قرار می‌دهد. بنابرین آدرس return address اصلی پس از حمله به آدرس اولین ابزارک تغییر پیدا می‌کند (برعکس حملهٔ بالا که به آدرس یک تابع در یک کتابخانه تغییر پیدا می‌کند) و بعد از آن نیز داخل stack به ترتیب آدرس ابزارکهای بعدی قرار داده می‌شود، در نتیجه برنامه پس از پرش به ابزارک اول و اجرای کد آن، با رسیدن به دستور ret، به ابزارک بعدی که آدرس آن داخل stack قرار داده شده پرش می‌کند و به همین ترتیب همهٔ ابزارکها اجرا می‌شوند. همچنین ابزاری نوشته شده‌است که به صورت خودکار این ابزارک‌های داخل برنامه را پیدا کرده، و ترتیب‌های مناسبی از آنها را پیدا می‌کند که یک shell را ایجاد کرده و به حمله کننده بدهند، نام این ابزار ROPابزارک می‌باشد. به تصادفی سازی آدرس‌ها یا ASLR ASLR که در واقع محل بارگذاری ماژول‌های مختلف برنامه را در حافظه در هر بار اجرا تغییر می‌دهد نیز نسبت به این حمله می‌تواند شکست بخورد و آسیب‌پذیر است، در سیستم‌های ۳۲ بیتی فقط ۱۶ بیت از آدرس حافظه قابلیت تصادفی شدن دارند، و این ۱۶ بیت را می‌توان با حملهٔ Brute Force شکست داد. در سیستم‌های ۶۴ بیت نیز ۴۰ بیت از ۶۴ بیت آدرس قابل استفاده برای تصادفی کردن هستند که حملهٔ Brute Force برای ۴۰ بیت نیز ممکن می‌باشد ولی به راحتی قابل تشخیص است به دلیل فرستاده شدن تعداد درخواست‌های بسیار بالا به برنامه. همچنین حتی با وجود تصادفی سازی ایده‌آل نیز در صورتی که محتوای قسمت‌های خاصی از حافظه لو برود می‌توان ASLR را دور زد، برای مثال در صورتی که آدرس شروغ libc با استفاده از حملات heap به دست بیاید می‌توان ASLR را دور زد. در نتیجه در صورتی که دستوری پیدا شود که اعمال pop و jmp را به ترتیب انجام می‌دهد می‌توان از آن به عنوان ret استفاده کرد. در نتیجه در این روش بعضی مکانیزم‌های دفاعی که فقط به دنبال ret در ابزارکها هستند دور زده می‌شوند، اما در صورتی که پرش‌ها نیز چک شوند این روش قابل شناسایی است. | ## بخش 3: برنامه‌نویسی بازگشت محور | ASLR در این روش آدرس ماژول‌های مختلف برنامه مانند توابع کتابخانه‌ای لود شده و stack و آدرس لود شدن خود برنامه با هر بار اجرای برنامه تغییر می‌کنند، در نتیجه حمله کننده قبل از اجرا نمی‌تواند آدرس دقیق محل‌هایی که قرار است به آنها پرش کند را بداند و در نتیجه آدرس ابزارکها با هر بار اجرای برنامه تغییر می‌کنند، اما همچنان می‌توان این روش را با bruteforce شکست داد به خصوص در سیستم‌های ۳۲ بیتی، همچنین در صورتی که در برنامه نشط اطلاعات وجود داشته باشد و برای مثال آدرس شروع بعضی توابع یا کتابخانه‌ها قابل به دست آمدن باشد می‌توان ASLR را دور زد. البته ماژول‌هایی که قابلیت random سازی برای آدرس شروع آنها موجود است بسته به نحوهٔ کامپایل شدن آنها و همچنین سربار قابل تحمل در سیستم می‌باشد و برای مثال ممکن است در مواردی فقط آدرس شروع کتابخانه‌ها تصادفی باشد. یک روش دیگر که توسط kBouncer استفاده می‌شود این است که چک می‌شود که محلی که آدرس return به آن اشاره می‌کند آیا دستور قبلی آن آدرس دستور call بوده‌است یا نه که سربار زیادی را متحمل سیستم عامل خواهد کرد و همچنین در مقابل حملاتی که از دستور Jmp استفاده می‌کنند مقاوم تیست. تصادفی سازی کد باینری در این روش در سیستم‌هایی که قابلیت کامپایل کردن به صورت on-the-fly را دارند، که یعنی به هنگام پخش کردن کد کامپایل انجام می‌شود، هر نمونه از کد کامپایل شده نسبت به دیگری تفاوت‌های مختلفی دارد و در نتیجه هر نسخهٔ کامپایل شده با نسخهٔ دیگر متفاوت است و باعث می‌شود که اگر حمله‌ای روی یک نمونه کار کند روی نمونه‌های دیگر آن برنامه کار نکند، که این روش به خصوص در هنگام آپدیت کردن دستگاه‌ها به کار می‌آید. اما ضعف این روش این است که قبل از پخش کد تست روی آن برای اطمینان از اجرای صحیح آن نمی‌توان انجام شود، در نتیجه این روش در الگوریتم‌های پیچیده بهتر است استفاده نشود. البته W^X در مقابل برنامه‌نویسی بازگشت محور مقاوم نیست اما مانند ASLR می‌تواند حمله را سخت‌تر کرده و برنامه را در مقابل حملات مقاوم تر کند. البته با توجه به محدودیت‌های حافظه‌ای که بعضی از سیستم‌های نهفته دارند این روش در همهٔ آنها قابل پیاده‌سازی نیست. این روش باعث می‌شود که از حملاتی که به محل‌های دیگری که خارج جدول هستند بازگشت می‌کنند جلوگیری شود. نویسندگان این روش ادعا می‌کنند که روششان باعث ضعیف شدن برنامه‌نویسی بازگشت محور و تضعیف آن به حملات ret2lib می‌شود. | ## جمع‌بندی | قبل از انجام عملیات‌های حساس مانند مانند بازگشت به آدرس ذخیره شده می‌توان با چک کردن امضا به تغییرات ناخواسته یا استفاده‌های نادرست پی برد.