Rainbow یک ماژول پایتون است که برای دو هدف طراحی شدهاست. اولین مورد کمک به توسعه دهندگان توکار برای تست پیاده سازی ها در برابر حملات کانال جانبی اصلی (به همراه ابزار تجزیه و تحلیل کانال جانبی Lascar) و در یک مرحله بعد، در برابر تزریق خطای کنترلشده میباشد.
دومین هدف این است که ابزارهایی برای ردیابی باینری های جعبه سفید فراهم كرده تا آنها را از هم جدا سازد. این كار بسیار شبیه به كانال جانبی Marvels است با این تفاوت كه Rainbow میتواند به راحتی بخشهایی از باینری های تعبیهشده را تغذیه کند.
آسیبپذیری های دستگاه های تعبیه شده یا توكار در همه جا در حال شکوفایی هستند و با افزایش تعداد كاربران، این وضعیت بدتر نیز خواهد شد.
علاوه بر آسیب پذیری های نرمافزاری رایج، باید مراقب توسعه تجهیزات توکار نیز بود، همچنین حملات فیزیکی نیز وجود دارند که به نمایش در میآیند. حملات كانال جانبی تلاش میکنند تا کلیدهای مخفی را با استفاده از توان الکتریکی یا تابش های الکترومغناطیسی بازیابی کنند.
تزریق خطا از پالسهای لیزری یا الکترومغناطیسی و همچنین تغییر ولتاژ برای تغییر رفتار کد اجرا شده بر روی دستگاه در نقاط ویژه استفاده میکند. مقایسه کد PIN مانع از دسترسی به دادههای شما میشود؟ یک مهاجم میتواند یک کد PIN تصادفی را ارسال کند و به طور کامل از این مقایسه صرفنظر کند.
وضعیت توسعه های توكار ایدهآل نیست. هیچ ابزاری برای آزمایش آن ها در برابر حملات در مرحله توسعه وجود ندارد (برخلاف زمانی که محصول نهایی میشود) و این شامل نیاز به خرید یا اجاره تجهیزات گرانقیمت (اوسیلوسكوپ، پروب، لیزر، …) و نیاز به تخصص نمی شود.
پروژه Reassure یك شبیه ساز را به طور خاص برای Cortex - m20 ارائه كرده است، اما مایلیم که این موارد را بیشتر از نظر ابزارسازی و ارائه چیزهای عمومی تر مورد بررسی قرار دهیم.
همچنین در سال 2015 یک پیشنهاد و تعدادی پیش نویس برای دستیابی به ردیابی کانال جانبی و تزریق خطا با موتور Unicorn (همان ابزار پایه Rainbow) وجود داشته است، اما به عنوان یک پیشنویس از کد در ضمیمه باقی مانده است.
به این دلیل Rainbow را ساختیم: به یک ابزار نیاز داشتیم تا به آسانی و باسرعت، كارایی برخی از اقدامات متقابل را تایید نماید. اقداماتی كه نیاز به حملات واقعی در یك دنیای واقعی را دارند.
این ابزار چگونه کار میکند
این ابزار بر روی موتور Unicorn ساخته شدهاست که امكان تقلید جزئیات كد را برای چندین هدف CPU فراهم میكند: x۸۶، x۸۶ _ ۶۴، ARM، M۶۸k، با استفاده از مجموعه صحیح از ترتیب اصلی یا "هوك"، میتوانیم دادههای میانی را از رجیسترها یا دسترسی ها به حافظه به صورت پویا در طول اجرا استخراج کنیم.
این امر شبیهسازی نشت کانال جانبی را ممکن میسازد: کاربر ورودی را برای تابع تقلبی فراهم میکند و این ابزار مقادیر میانی را در طول اجرا منتشر میکند.
راههای دیگری نیز برای ردیابی اجرای یک برنامه وجود دارد، اما در مورد کد توكار یا firmware، مشکلاتی در زمان استفاده از آن ابزارها وجود دارد. استفاده از Unicorn به کاربر اجازه میدهد تا قسمتهای خاصی از کد را درfirmware چک کند و آنها را مورد آزمایش قرار دهد. یک گزینه دیگر میتواند بازنویسی کد برای آزمایش آن به عنوان یک برنامه و استفاده از ابزارهای دیگر موجود (Intel پین، Valgrind)برای ردیابی آنها باشد، اما این كار اشکالاتی نیز دارد:
- باینری تولید شده ممکن است با آنچه در firmware به کار میرود تفاوت داشته باشد و ممکن است شامل همان نقص ها نیز نباشد.
- برای هر پلتفرمی که باید امتحان کنید، باید یک نسخه از ابزارهای فوقالذکر و احتمالا اسكریپت های مختلف وجود داشته باشد.
- شما به سادگی ممکن است به کد منبع دسترسی نداشته باشید.
در مورد تزریق خطا، فرد میتواند به روشهای زیادی اجرا را مجبور کند که از یک دستورالعمل صرفنظر کند، یا از هوك Unicorn برای اجرای یک مقدار بسیار خاص به یک رجیستر و بررسی نحوه رفتار کد استفاده کند.
قابلیت استفاده ساده و آسان
این ابزار تا حد ممكن به صورت معماری - اگنستیك ایجاد شده است، به این معنی که ردیابی همانند تقلید CPU x۸۶ یا یک ARM Cortex عمل می كند. capstone برای شناسایی آنچه که رجیسترها تحتتاثیر یک دستورالعمل قرار میگیرند، استفاده میشود، بنابراین ما میتوانیم دقیقا آنچه را که برای هر دستورالعمل، به طور مستقل از CPU رخ میدهد، انتخاب کنیم.
گام مهم دیگر، فراهم کردن توابع پایه برای بارگذاری باینری های متداول در توسعه تعبیه شده یا توكار است: فایلهای دودویی خام، ELF و قالبهای Intel Hex كه همگی به راحتی با یک فرمان بارگذاری میشوند.
اجرا
در اینجا برخی از ویژگیهای اساسی Rainbow و چگونگی پیادهسازی آنها آورده شدهاست.
ربودن یا هوكینگ (Hooking) دسترسی به حافظه
Unicorn قبلا این نوع هوك را فراهم كرده است:
تابع mem_hook روی هر دستورالعملی که خواندن یا نوشتن حافظه را انجام میدهد، فرا خوانی می شود. داخل این تابع، مقداری كه قرار است نوشته شود یا مقداری که خوانده میشود (که باید به صورت دستی از نشانی ارایهشده توسط Unicorn خوانده شود) را الحاق میکنیم،
هوكینگ مقادیر رجیستر
ما تصمیم گرفتیم که چیزی را اجرا کنیم که هر گونه حرکت رجیستر را ردیابی کند. این بار ما به هوك CODE نیاز داریم که پیش از اجرای هر دستورالعملی فراخوانی شود. برای تعیین اینکه کدام رجیسترها تحتتاثیر قرار خواهد گرفت، ما از نسخه چهارم API regs_access مربوط به Capstone استفاده كردیم. ما دستورالعمل فعلی را جدا کرده و رجیسترهایی را که به طور ضمنی و به طور واضح در ان نوشته شده اند را بازیابی میکنیم. برای مثال
, ldr r0, [sp, #8] w تنها r0 را تغییر خواهد داد.
از آنجایی که این هوك قبل از اجرا فراخوانده میشود، خواندن رجیستر نشت یافته را تا دفعه بعدی كه هوك فراخوانی می شود، به تعویق میاندازیم.
قابلیت تعمیم
این ابزار در اصل برای استفاده ما طراحی شدهاست، که شامل آزمایش بر روی مولفه های امنیت SE میباشد. این بدان معناست که ما باید ردیاب مبتنی بر ARM عمومی (برای مثال) را توسعه دهیم. و آن را به راحتی در شبیهسازی محیطی و همچنین نام گذاری ویژه رجیستر در مورد نشانههای اشكال زدایی، اضافه نماییم.
دوباره، هوكهای Unicorn این کار را به طور یکپارچه انجام میدهند. ابزار ما با در نظر گرفتن این ویژگی ساخته شد ه است. به طوری که برای ایجاد ردیاب یک دستگاه جدید با نقشه حافظه خود، لوازم جانبی، و غیره نیاز به کار کمی دارد.
یک مثال ساده، اضافه كردن یک هوك روی یک تولیدكننده اعداد تصادفی واقعی یا True Random Number Generator است.
مثال: شبیه سازی یك TRNG
ما میتوانیم این کار را یکی از دو روش زیر انجام دهیم. یا ما میدانیم که کد، مقادیر تصادفی خود را از تابع مستقل دریافت خواهد کرد و ما میتوانیم آن را به دام اندازیم و یا اینكه آدرس رجیستر TRNG را شناسایی کرده و قبل از خوانده شدن آن، روی آن بنویسیم.
هوكینگ یا تعریف مجدد یک تابع به طور مستقیم در Rainbow انجام میشود. در مورد فایلهای ELF، نام ها و آدرس های توابع با باینری ها به طور هم زمان بارگذاری می شوند و یک دیكشنری داخلی برای نگاشت نام توابع به توابع پایتون وجود دارد که میتوان آن را به Rainbow منتقل کرد. برخی از كدهای هوك متوقف ساز (که هربار موقع اجرای كد فراخوانی می شوند) هنگام ورود یک تابع بررسی میکند که آیا نام آن هم به تابع کاربر اشاره دارد یا نه.
اگر چنین باشد، اجرا به تابع کاربر هدایت میشود و میتواند به تابع اصلی که به عنوان یک مقدمه عمل کند، برگردد.
در صورتی که فایل باینری هیچ اطلاعات سمبلیكی نداشته باشد، اگر آدرس را بدانیم، میتوانیم این کار را به صورت دستی انجام دهیم.
در زیر راه دیگری برای انجام این کار وجود دارد که این است که تمام فراخوانی های رجیستر از آدرس TRNGخوانده شود:
فقط یک هوك خوانده میشود که فقط روی این نشانی خاص فعال است درست قبل از آنكه Unicorn دستورالعمل را اجرا كند، فراخوانی میشود، بنابراین تابع هوك به طور مستقیم در رجیستر نوشته میشود و زمانی که هوك خارج میشود، توسط کد تقلیدی، خوانده خواهد شد.
نحوه انجام كار
نخست، ما باید پس از اینکه کد اجرا شد، یک نشانه یا Trace را برباییم:
یک ناظر بر اساس VisPy در كد ما تعبیهشده است که در rainbow.utils.plot قابل دسترسی است.
اولی چندین نشانه را برمی دارد و به سادگی آنها را با یک رنگ متفاوت نشان میدهد، بسیار شبیه matplotlib عمل می كند، با این تفاوت كه VisPy کارها را سریعتر میکند.
from rainbow.utils.plot.plot import plot
(there might be room for naming
improvement here...)
plot(trace)
ناظر دیگر نمایی بین نشانه دستورالعمل و مقادیر را همگام سازی میکند:
from rainbow.utils.plot import viewer
viewer(disassembly, trace)
با استفاده از این روش، ما میتوانیم دقیقا مشخص کنیم كدام دستورالعمل و به چه مقدار نشت دارد زمانی که چندین اثر از یک تابع را با ورودیهای مختلف جمع میکنیم، میتوانیم از Lascar برای حمله به آن و تلاش برای بازیابی کلید استفاده کنیم. مثال: یک AES برای Cortex - M بهینه شد. بیایید به خروجی sbox AES در دور اول این پیادهسازی، حمله کنیم.
با استفاده از این مثال در github، ما این اقدامات اجرایی را بعد از اضافه کردن مقداری خطا برای واقعی تر شدن آن، به دست میآوریم:
و حالا نتایج CPA روی اولین بازده sbox:
plot(results, highlight=0x00)
highlights one specific curve among
others
یک لبه شفاف در ارتباط با بایت اصلی مورد انتظار وجود دارد: به راحتی قابل شکستن است! این مسئله دور از انتظار نیست چون AES که ما برای اجرای این دمو استفاده کردیم، در مقابل کانالهای جانبی محافظت نمیشود (اگر چه شما میتوانید یکی را در همان github پیدا کنید).
گام های بعدی
ما چند نمونه را در GitHub، برای نشان دادن آنچه که ابزار ما در وضعیتهای مختلف میتواند انجام دهد، ارایه کردیم:
- یک مثال از ردیابی debug ساده، که برخی از اطلاعات اضافهشده را در یک نشانه Rainbow نمایش میدهد
- یک مثال توکار: چگونگی ردیابی یک AES به ویژه برای Cortex M و تجزیه آن با استفاده از Lascar
- یک مثال ساده: متنی که از سال گذشته، Ledger CTF2 Challenge را شكسته است.
هنوز هیچ نمونه تزریق خطا در دسترس نیست، هر چند که ما برخی از آنها را آماده کردهایم ایجاد یک رابط كاربری خوب برای تزریق خطا یکی از کارهای بعدی قبل از انتشار آنها است.
همچنین نمونههای متقاعد کنندهتر از آزمایشهای کانال جانبی وجود دارد که ما به محض دریافت اجازه انتشار، آن را منتشر خواهیم کرد.
این مطلب مفید را از دست ندهید " معرفی Ledger Donjon"