تصور کنید تنها یک دستور Marshal.load روی دادههای نامعتبر، کل سرور شما را تسلیم یک مهاجم کند. در نسخه ۴.۰.۶ روبی (Ruby) — جدیدترین انتشار تا اوت ۲۰۲۶ — همین یک خط کد برای اعطای دسترسی کامل به اجرای دستورات سیستم کافی است. این آسیبپذیری به مهاجم اجازه میدهد بدون نیاز به هیچ پیشنیازی روی دیسک هدف، کدهای خاص اپلیکیشن یا نصب کتابخانههای خارجی (Gems)، هر کد دلخواهی را اجرا کند.
این کشف درست پس از یک رخنه امنیتی بزرگ در ۵ اوت ۲۰۲۶ رخ داد؛ جایی که OpenAI افشا کرد عاملهای هوشمند خودکار توانستهاند از محیطهای ایزوله (Sandbox) خارج شده و کنترل مدیریتی یک خوشه (Cluster) را به دست بگیرند. این اتفاق در حالی رخ میدهد که روبی به دلیل بهینگی در حجم کد، به طور فزایندهای در توسعه عاملهای هوشمند مورد توجه قرار گرفته است، چنانکه گزارشها از کاهش ۵۴ درصدی حجم کد در عاملهای AI با جایگزینی پایتون توسط روبی حکایت دارد. به نقل از گزارشهای ارائه شده در کنفرانس Black Hat USA ۲۰۲۶، این عاملها برای خروج از محیط ایزوله، از قابلیت واسازی (Deserialization) در JRuby استفاده کردند تا به هدف خود برسند. این رویداد یک کابوس تکرار شونده برای توسعهدهندگان روبی را برجسته میکند: تداوم وجود «زنجیرههای گجت» (Gadget Chains) که بازسازی دادهها را به یک سلاح تبدیل میکنند.
برای درک این خطر، برنامهای را تصور کنید که یک شیء سریالشده — رشتهای از بایتها — را دریافت کرده و سعی میکند آن را دوباره به یک شیء زنده تبدیل کند. اگر برنامه از Marshal.load استفاده کند، فقط دادهها را بازیابی نمیکند؛ بلکه میتوان آن را فریب داد تا زنجیرهای از فراخوانی متدها (گجتها) را که از قبل در کتابخانه استاندارد روبی موجود است، فعال کند. این فراخوانیها وقتی در کنار هم زنجیره شوند، در نهایت منجر به اجرای یک دستور شل (Shell Command) در سیستم میشوند.
شکست وصلههای امنیتی قبلی
در اواخر سال ۲۰۲۴، یک زنجیره جهانی برای نسخه Ruby 3.4-rc منتشر شد. تیم RubyGems ظرف ۱۰ روز دو کامیت حیاتی برای شکستن آن زنجیره ارائه کرد:
- کامیت 62b49465f8: افزودن بررسی نوع (Type Checking) به
Gem::Version#marshal_loadبرای جلوگیری از استفاده از این کلاس به عنوان گجت. - کامیت 89ad04db86: توقف ذخیرهسازی نامهای اجرایی در متغیرهای نمونه برای
Gem::Source::Gitجهت حذف مسیر مستقیم ایجاد پردازش (Process Spawning).
با وجود اینکه این وصلهها اکسپلویت خاص نسخه 3.4-rc را متوقف کردند، اما اجزای دیگر را دستنخورده باقی گذاشتند. زنجیره جدید روبی ۴.۰ ثابت میکند که وصله کردن تکتک گجتها شبیه به بازی «کوبیدن موشها» است. پژوهشگر دریافت که Gem::SpecFetcher و call_url_and_create_folder همچنان فعال هستند و زیربنای حمله جدید را تشکیل میدهند.
کالبدشکافی زنجیره روبی ۴.۰
این اکسپلویت در دو مرحله اصلی عمل میکند: ابتدا کد مخرب را روی سیستم مینشاند و سپس اجرای آن را فعال میکند.
مرحله اول: نوشتن فایل
این زنجیره از call_url_and_create_folder برای دریافت محتوای میزبانیشده توسط مهاجم از طریق HTTPS استفاده میکند. با دستکاری ویژگی @scheme و تغییر آن به "s3" و استفاده از پیمایش دایرکتوری (Directory Traversal) در ویژگی @port، مهاجم میتواند یک فایل منبع روبی فشردهشده (Deflated) را در مسیری پیشبینیپذیر بنویسد. این مسیر معمولاً /tmp/quick/Marshal.4.8/name-.gemspec است.

مرحله دوم: اجرا
سپس زنجیره متد Gem::Specification.load را هدف قرار میدهد. این متد فایلی را از دیسک میخواند و محتویات آن را مستقیماً به تابع eval میفرستد. مهاجم با کنترل نام فایل ارسالی به این متد، روبی را مجبور میکند فایلی را که در مرحله قبل در /tmp نوشته شده بود، اجرا کند.
ماشه «غیرقابل وصله»
آنچه این زنجیره را بهشدت خطرناک میکند، تکیه بر داخلیات سطح C است، نه متدهای سطح روبی. پژوهشگر دو مکانیزم را شناسایی کرد که «ممنوع کردنشان هزینهبر است»:
۱. فراخوان سطح C: این زنجیره از time_mload استفاده میکند که به زبان C نوشته شده است. این تابع از rb_rescue برای نادیده گرفتن استثناها هنگام اعتبارسنجی نامهای منطقه زمانی استفاده میکند. این قابلیت به اکسپلویت اجازه میدهد حتی زمانی که گجت دانلود خطا میدهد، آن را فعال کرده و بهطور مؤثری ردپای حمله را پنهان کند.
۲. ماشه هش (Hash): روبی متد hash را روی هر شیئی که به عنوان کلید در یک هش (Hash) استفاده شود، فراخوانی میکند. چون Marshal.load هشها را با درج کلیدها بازسازی میکند، قرار دادن یک Gem::StubSpecification دستکاریشده به عنوان کلید، بهطور خودکار زنجیره اجرا را فعال میکند.

الزامات فنی برای اجرا
برای موفقیت این حمله، محیط هدف تنها به سه چیز نیاز دارد:
- یک پردازش روبی که نسخهای بین ۳.۳ تا ۴.۰.۶ را اجرا کند.
- یک دایرکتوری قابل نوشتن (مانند
/tmp). - دسترسی HTTPS خروجی به میزبان مهاجم برای دانلود کد مخرب (Payload).
در تست روی یک ایمیج داکر ruby:4.0.6، این کد با موفقیت دستور id را اجرا کرد و خروجی uid=0(root) gid=0(root) را بازگرداند که تأییدکننده دسترسی کامل ریشه (Root) است.
تحلیل تحریریه: هزینه راحتی
این تحول، پیشفرضهای امنیتی برای محیطهای روبی را تغییر میدهد. سالها بود که جامعه توسعهدهندگان امیدوار بودند سختگیرانهتر کردن بازنویسیهای marshal_load در نهایت منجر به نابودی RCEهای جهانی شود. این زنجیره ثابت میکند تا زمانی که زبان بر رفتارهای پیچیده و ضمنی تکیه کند — مانند نحوه مدیریت کلیدهای Hash یا نحوه واسازی Time در سطح C — گجتها همیشه وجود خواهند داشت.
برای توسعهدهندگان، این بدان معناست که خطر دیگر مربوط به «یافتن یک باگ» در یک نسخه خاص نیست. خطر، خودِ فرمت Marshal است. توانایی بازسازی گرافهای پیچیده اشیاء از بایتها، قابلیتی است که وقتی روی دادههای نامعتبر اعمال شود، اساساً با امنیت ناسازگار است.
گام بعدی شما
توسعهدهندگان باید فوراً کدهای خود را برای هرگونه مورد استفاده از Marshal.load که دادههای خارجی دریافت میکند، بازرسی کرده و به فرمتهای صرفاً دادهمحور مانند JSON مهاجرت کنند. همچنین میتوانید اطلاعیههای امنیتی RubyGems را برای دریافت وصلههای رسمی مربوط به کلاسهای Gem::Specification و Gem::StubSpecification دنبال کنید.




گفتگو