تحلیل و اکسپلویت آسیبپذیری Padding Oracle
در این مقاله، به یکی از کلاسیکترین و در عین حال قدرتمندترین آسیبپذیریهای حوزه رمزنگاری یعنی Padding Oracle میپردازیم. این حمله به مهاجم اجازه میدهد تا با ارسال پیامهای دستکاری شده به یک سرور و تحلیل پاسخهای خطای آن، بتواند دادههای رمزگذاری شده را بدون دسترسی به کلید رمزگشایی، به صورت بایت به بایت رمزگشایی کند. این راهنما به صورت گام به گام شما را با مفاهیم رمزنگاری بلوکی، مکانیزم حمله و روشهای پیشگیری آشنا میکند.
مفاهیم پایه: پیشنیازهای درک حمله
قبل از ورود به جزئیات فنی آسیبپذیری، باید با چند مفهوم کلیدی در دنیای رمزنگاری آشنا شویم.
رمزنگاری متقارن و سایفرهای بلوکی (Block Ciphers):
در رمزنگاری متقارن، از یک کلید یکسان برای رمزگذاری و رمزگشایی دادهها استفاده میشود. سایفرهای بلوکی مانند AES، دادهها را به بلوکهایی با اندازه ثابت (مثلاً ۱۶ بایت برای AES) تقسیم کرده و هر بلوک را به صورت جداگانه رمزگذاری میکنند.
حالت رمزگذاری CBC (Cipher Block Chaining):
برای اینکه بلوکهای یکسان در متن اصلی، خروجی رمز شده متفاوتی داشته باشند، از «حالتهای عملیاتی» (Modes of Operation) استفاده میشود. حالت CBC یکی از محبوبترین حالتهاست. در این حالت، قبل از رمزگذاری هر بلوک از متن اصلی، آن را با بلوک رمز شده قبلی XOR میکنند. این زنجیره باعث میشود که هر بلوک رمز شده به تمام بلوکهای قبلی وابسته باشد.
پدینگ (Padding) و استاندارد PKCS#7:
از آنجایی که سایفرهای بلوکی روی بلوکهایی با اندازه ثابت کار میکنند، اگر آخرین بلوک متن اصلی کامل نباشد، باید آن را با بایتهای اضافی پر کرد تا به اندازه مورد نیاز برسد. این فرآیند پدینگ نام دارد. استاندارد رایج PKCS#7 به این صورت عمل میکند: اگر N بایت برای کامل شدن بلوک نیاز باشد، N بایت با مقدار عددی N به انتهای داده اضافه میشود.
- مثال ۱: اگر بلوک ۱۶ بایتی باشد و آخرین بلوک ۱۳ بایت داده داشته باشد، ۳ بایت برای پر کردن آن لازم است. بنابراین پدینگ به صورت
03 03 03
اضافه میشود. - مثال ۲: اگر آخرین بلوک کامل باشد (۱۶ بایت)، یک بلوک کامل پدینگ با مقدار
10 10 10 ... 10
(به تعداد ۱۶ بار) اضافه میشود تا گیرنده بتواند بین داده واقعی و پدینگ تمایز قائل شود.
حالا بریم سراغ آسیبپذیری Padding Oracle
ریشه این آسیبپذیری در نحوه مدیریت خطا توسط سرور هنگام رمزگشایی دادهها نهفته است.
آسیب پذیری Padding Oracle: چگونه رخ میدهد؟
یک "اوراکل" (Oracle) در زمینه امنیت، سیستمی است که اطلاعاتی را به بیرون درز میدهد. در این حمله، اوراکل ما همان سرور است. وقتی سرور یک متن رمز شده را دریافت و رمزگشایی میکند، آخرین مرحله بررسی صحت پدینگ است. مشکل زمانی رخ میدهد که سرور برای دو حالت خطای مختلف، پاسخهای متفاوتی برمیگرداند:
- خطای پدینگ نامعتبر (Invalid Padding): مثلاً پدینگ با
02 05 09
تمام شده که بیمعناست. - خطای رمزگشایی موفق اما داده نامعتبر (Valid Padding, but invalid data): پدینگ معتبر است (مثلاً
03 03 03
) اما محتوای رمزگشایی شده از نظر منطق برنامه معنایی ندارد.
این تفاوت در پاسخها (که میتواند یک پیام خطای متفاوت، یک کد وضعیت HTTP متفاوت یا حتی تفاوت زمانی در پاسخدهی باشد) به مهاجم اجازه میدهد تا بفهمد آیا حدسی که زده منجر به پدینگ معتبر شده است یا خیر.
شرایط وقوع حمله
- استفاده از سایفر بلوکی در حالت CBC: این حمله مختص حالت CBC (و حالتهای مشابه) است.
- درز اطلاعات درباره وضعیت پدینگ: برنامه باید به نحوی بین خطای "پدینگ نامعتبر" و سایر خطاها تمایز قائل شود.
- قابلیت ارسال متن رمز شده دلخواه: مهاجم باید بتواند متن رمز شده را دستکاری کرده و برای سرور ارسال کند.
راهنمای عملی اکسپلویت (Walkthrough)
در این بخش، منطق گام به گام حمله برای رمزگشایی یک بایت از داده را تشریح میکنیم. فرض کنید دو بلوک ۱۶ بایتی از متن رمز شده با نامهای C1 (بلوک اول) و C2 (بلوک دوم) را در اختیار داریم و میخواهیم بلوک متن اصلی متناظر با C2 یعنی P2 را رمزگشایی کنیم.
هدف: رمزگشایی آخرین بایت از بلوک P2
ما میخواهیم بایت آخر P2 را پیدا کنیم. فرآیند به شکل زیر است:
- ایجاد یک بلوک C1 دستکاری شده ('C1): یک کپی از C1 میسازیم. ۱۵ بایت اول آن را با مقادیر دلخواه (مثلاً صفر) پر میکنیم. بایت شانزدهم (آخرین بایت) را با یک مقدار حدسی
G
(از 0 تا 255) جایگزین میکنیم. - ارسال به اوراکل: متن رمز شده جدید که از
'C1
وC2
تشکیل شده را به سرور ارسال میکنیم. - تحلیل پاسخ سرور: سرور ابتدا C2 را با کلید مخفی خود رمزگشایی میکند تا به یک مقدار میانی (Intermediate Value) به نام I2 برسد. سپس برای به دست آوردن متن اصلی، آن را با بلوک رمز شده قبلی (که حالا
'C1
است) XOR میکند:'P2 = I2 XOR 'C1
. - یافتن حدس درست: سرور در انتها پدینگ
'P2
را بررسی میکند. ما به تکرار مرحله ۱ و ۲ با مقادیر مختلف برایG
ادامه میدهیم تا زمانی که سرور خطای "پدینگ نامعتبر" را ندهد. این یعنی حدس ما باعث شده آخرین بایت'P2
برابر با0x01
شود که یک پدینگ معتبر است. - محاسبه بایت میانی: در این لحظه میدانیم:
I2_last_byte XOR G = 0x01
. با یک محاسبه ساده، بایت میانی را پیدا میکنیم:I2_last_byte = G XOR 0x01
. - محاسبه بایت اصلی: حالا که بایت میانی را داریم، میتوانیم بایت اصلی را محاسبه کنیم:
P2_last_byte = I2_last_byte XOR C1_last_byte
(توجه کنید که از بایت اصلی C1 استفاده میکنیم، نه C1 دستکاری شده).
این فرآیند برای بایت یکی مانده به آخر تکرار میشود، با این تفاوت که این بار هدف ما ایجاد پدینگ معتبر 0x02 0x02
است. این کار را تا رمزگشایی کامل بلوک ادامه میدهیم.

راهکارهای پیشگیری و امنسازی
مقابله با این حمله نیازمند رویکردهای دقیق در پیادهسازی رمزنگاری است:
- استفاده از رمزنگاری اصالتسنجی شده (AEAD): این بهترین راهکار است. حالتهایی مانند AES-GCM یا ChaCha20-Poly1305 رمزگذاری را با یک کد احراز هویت پیام (MAC) ترکیب میکنند. هرگونه دستکاری در متن رمز شده قبل از مرحله رمزگشایی شناسایی و رد میشود و این حمله را به طور کامل خنثی میکند.
- پیادهسازی Encrypt-then-MAC: اگر نمیتوانید از حالتهای AEAD استفاده کنید، ابتدا داده را رمزگذاری کرده و سپس یک کد HMAC روی متن رمز شده محاسبه و ضمیمه کنید. در سمت گیرنده، ابتدا صحت HMAC را بررسی کنید و تنها در صورت معتبر بودن، اقدام به رمزگشایی نمایید.
- عدم درز اطلاعات از طریق خطاها: تمام خطاهای مربوط به رمزگشایی (چه پدینگ نامعتبر، چه MAC نامعتبر و...) باید یک پیام خطای عمومی و یکسان به کاربر برگردانند تا مهاجم نتواند بین آنها تمایز قائل شود.
منابع برای مطالعه بیشتر
برای درک عمیقتر مفاهیم مرتبط با این آسیبپذیری، مطالعه منابع زیر به شدت توصیه میشود:
سلب مسئولیت: این مقاله صرفاً با اهداف آموزشی و پژوهشی تهیه شده است. هرگونه سوءاستفاده از این اطلاعات در سیستمهای واقعی غیرقانونی و غیراخلاقی است و مسئولیت آن بر عهده فرد خاطی خواهد بود.