
دليل خطوة بخطوة لاستغلال ثغرة RCE في إلغاء تسلسل Fastjson (CVE-2017-18349)، مع تغطية تحديد سطح الهجوم، وبصمة النظام، وحقن JNDI، والحصول على قشرة عكسية في بيئة مختبر Docker.
لنبدأ بمعرفة ما يعمل في البيئة. سأدرج جميع الحاويات النشطة:
docker ps

الضحية يعرض منفذاً واحداً فقط: 8090
حالياً، لا أزال غير واضح تماماً بشأن الهدف. من نتائج docker ps، ينشر النظام خدمة واحدة ملحوظة فقط خارجياً على المنفذ 8090، وهي مرتبطة بالخدمة الداخلية للحاوية. هذا هو سطح الهجوم الرئيسي الذي يجب تحليله.
⇒ سأستخدم Curl مباشرة لاستكشاف المزيد من المعلومات
curl -i 192.168.3.137:8090/

تحليل الاستجابة:
Content-Type: application/json;charset=UTF-8.{"age": 25, "name": "Bob"}.⇒ تفكير: عند الوصول إلى المنفذ 8090، يعيد الخادم بيانات JSON. يشير هذا إلى أن نقطة النهاية لا تخدم مجرد صفحة ويب ثابتة، بل يوجد خلفية تقوم بمعالجة الطلبات وتسلسل البيانات إلى JSON لإعادتها إلى العميل. من نتائج docker ps، يظهر الأمر المُشغَّل داخل الحاوية مؤشرات على أنه تطبيق Java، لذا فإن الاتجاه التالي للفحص هو التعرف على محللات JSON الشائعة في Java.
في Java، تتصرف مكتبات JSON الشهيرة مثل Jackson وGson وFastjson بشكل مختلف عند مواجهة مدخلات غير معتادة. لذلك، يمكننا استخدام تقنية التعرف على البصمات المبنية على الأخطاء (Error-based Fingerprinting). فالخطأ المرتجع قد يكشف أحياناً بشكل مباشر عن المكتبة أو آلية المعالجة الداخلية. ومن بينها، تُعد Fastjson هدفاً يحتاج إلى تحقق مبكر لأن الإصدارات القديمة كانت تحتوي على ثغرات حرجة متعددة تتعلق بإلغاء التسلسل AutoType Deserialization.
هنا، لا أؤكد فوراً أن الخلفية تستخدم Fastjson. أختار Fastjson كأول اتجاه للفحص فقط لأنه يملك بصمة واضحة من خلال مفتاح @type، وإذا كان بالفعل إصداراً قديماً من Fastjson، فإن قدرة الاستغلال قد تتجاوز بكثير خطأ تحليل قياسي، وربما تصل إلى تنفيذ أوامر عن بُعد (RCE).
يمتلك Fastjson خاصية مفيدة جداً للتعرف على البصمة: فهو يتعرف على مفتاح @type الخاص. إذا كانت الخلفية تستخدم Fastjson وكان نص الطلب المُرسل إلى عملية إلغاء التسلسل يدعم AutoType، فقد يحاول المحلل تفسير قيمة @type كاسم فئة Java.
لذلك، أرسل حمولة تحتوي على @type يشير إلى فئة غير موجودة. الهدف من هذه الخطوة ليس الاستغلال الفوري، بل ملاحظة ما إذا كانت الخلفية تتفاعل مع @type.
curl -i -X POST -H "Content-Type: application/json" \
-d '{"@type":"com.non.existent.Class"}' \
http://192.168.3.137:8090/

إذا كانت الخلفية تستخدم محلل JSON قياسياً ولا تهتم بـ @type، فقد يتم تجاهل هذا الحقل أو معاملته كمفتاح عادي في JSON. لكن هنا، تتفاعل الخلفية بسلوك مرتبط بالنوع (type not match)، مما يعني أن الطلب دخل في سير عمل معالجة تعيين الفئات/الأنواع.
رسالة "type not match" هي توقيع مميز غالباً ما يُصادف عندما يعالج Fastjson @type ولكن الفئة المحددة لا تتطابق مع نوع البيانات المتوقع من نقطة النهاية، أو أن الفئة غير موجودة/غير مسموح بإلغاء تسلسلها.
⇒ تفكير: الخلفية توزن بالفعل نص JSON لطلب POST، وحقل @type غير مُتجاهَل، والمحلل يمتلك آلية معالجة بيانات وصفية للأنواع، والخطأ المرتجع يطابق سلوك Alibaba Fastjson. لذلك يمكننا الاستنتاج بثقة عالية أن الخلفية تستخدم Alibaba Fastjson.**
بعد خطوة التعرف على البصمة، لا يمكنني الاستنتاج فوراً أن النظام قابل للاستغلال. استخدام الخلفية لـ Fastjson يثبت فقط أن طلب JSON يدخل في سير معالجة @type.
لتنفيذ استغلال RCE، يجب التحقق من التالي:
⇒ تفكير: خطأ type not match يُظهر أن الخلفية تتفاعل مع @type، لكن الحمولة الحالية تستخدم فقط فئة مزيفة لتفعيل خطأ. للاستغلال الفعلي، نحتاج إلى استبدال تلك الفئة المزيفة بفئة حقيقية موجودة في Java/JDK وقادرة على إنشاء سلوكيات صادرة مثل JNDI lookup.
لتحديد الإصدار، أفحص مباشرة داخل الحاوية/التطبيق.

بعد تحديد أن التطبيق مُعبأ كملف /usr/src/fastjsondemo.jar، أتابع بتحليل عميق لبنية هذه الحزمة للبحث عن مكتبة معالجة JSON. يكشف فحص بنية دليل BOOT-INF/lib/ عن الملف fastjson-1.2.24.jar (الشكل X).
استخدام الإصدار 1.2.24 تحديداً — أول وأشهر إصدار متأثر بثغرة إلغاء التسلسل دون أي آليات دفاع autoType — يسمح لنا بتأكيد أن النظام معرض لثغرة CVE-2017-18349.
العثور على fastjson-1.2.24.jar يؤكد أن التطبيق يستخدم إصداراً قديماً جداً من Fastjson، ينتمي إلى المجموعة المتأثرة بخلل AutoType Deserialization. في هذا الإصدار، لم تكن آلية التحكم في AutoType مشددة كما في الإصدارات اللاحقة، لذا فيما يتعلق بشروط المكتبة، فإن النظام قابل للاستغلال عبر فئات gadget مثل JdbcRowSetImpl.
ومع ذلك، فإن قابلية الاستغلال الفعلية لا تزال تعتمد على كيفية استدعاء نقطة النهاية لـ Fastjson. إذا كان التطبيق يحلل JSON إلى فئة ثابتة، فإن وضع حمولة @type في الكائن الجذر قد يؤدي إلى خطأ "type not match". لذلك، بعد تحديد الإصدار، يجب مواصلة تحليل JVM وفئة gadget وسلوك استدعاء LDAP للتأكد مما إذا كانت سلسلة الاستغلال تصل فعلياً إلى JNDI lookup.
1. تحليل حواجز JVM
بالإضافة إلى إصدار Fastjson، فإن إصدار Java هو أيضاً عامل حاسم. أفحص JVM داخل الحاوية:
java -version

هذه معلومة حرجة لأن سلاسل استغلال Fastjson تعتمد عادةً على حقن JNDI (JNDI Injection). الإصدارات الأحدث من Java قامت بحظر تحميل الفئات من قواعد الأكواد الخارجية عبر LDAP/RMI افتراضياً. ومع ذلك، فإن Java 8u102 هو إصدار قديم لا يمتلك هذه الآليات الحاجبة بعد.
لذلك، إذا تمكن المهاجم من تفعيل JNDI lookup، فإن JVM الخاص بالضحية لديه القدرة على تنزيل الفئة من خادم HTTP خارجي وتحميلها في بيئة التشغيل.
بعد تحديد Fastjson و JVM القديمين، الخطوة التالية هي العثور على فئة موجودة في JDK يمكنها إنتاج سلوك خطير عند إلغاء تسلسلها.
com.sun.rowset.JdbcRowSetImpl هي فئة gadget مناسبة لأن هذه الفئة موجودة في JDK وتمتلك خاصية dataSourceName. عندما يتم تعيين dataSourceName بقيمة بصيغة عنوان LDAP URL، يمكن استغلال الكائن لتفعيل JNDI lookup صادر.
⇒ تفكير: لا أحتاج إلى رفع كود مباشرة إلى الخادم. بدلاً من ذلك، أستفيد من فئة موجودة داخل JVM لإجبار الضحية على الاتصال بخادم LDAP يتحكم فيه المهاجم.
بعد تأسيس الشروط اللازمة المتعلقة بالمكتبة و JVM، أحتاج إلى التحقق مما إذا كانت الحمولة تجبر الضحية فعلياً على الاتصال خارجياً. هذه خطوة حرجة للتمييز بين:
إذا استقبل خادم LDAP أو المستمع اتصالاً من الضحية، فهذا يثبت أن الحمولة وصلت بنجاح إلى خطوة JNDI lookup. إذا لم يكن هناك استدعاء عائد وأعاد الخادم type not match، فهذا يشير إلى أن الحمولة الحالية لا تتطابق مع سير إلغاء التسلسل في نقطة النهاية. في هذه الحالة، يجب تعديل الحمولة لتطابق بنية الكائن المحددة التي تحللها نقطة النهاية، أو استخدام تجاوزات/فئات gadget بديلة.
من الخطوات أعلاه، يمكن تلخيص سلسلة شروط النظام على النحو التالي:
@type تشير إلى أن الخلفية تعالج آلية البيانات الوصفية للأنواع، بما يطابق سلوك Fastjson.fastjson-1.2.24.jar.com.sun.rowset.JdbcRowSetImpl موجودة في JDK ويمكن استغلالها لتفعيل JNDI lookup من خلال خاصية dataSourceName.⇒ تفكير الاستغلال: