
مُحلل البايت كود للعثور على سلاسل أدوات إلغاء التسلسل في تطبيقات جافا
================
يقوم هذا المشروع بفحص مكتبات جافا ومسارات الكلاس (classpaths) بحثًا عن سلاسل الأدوات (gadget chains). تُستخدم سلاسل الأدوات لبناء استغلالات لثغرات إلغاء التسلسل (deserialization). من خلال اكتشاف سلاسل الأدوات المحتملة تلقائيًا في مسار الكلاس الخاص بالتطبيق، يمكن لمختبر الاختراق بناء الاستغلالات بسرعة، ويمكن لمهندسي أمن التطبيقات تقييم تأثير ثغرة إلغاء التسلسل وتحديد أولويات معالجتها.
تم تقديم هذا المشروع في Black Hat USA 2018. تعرف على المزيد عنه هناك! (الروابط قيد الإعداد)
تنبيه: هذا المشروع في مرحلة ألفا في أفضل الأحوال. يحتاج إلى إضافة اختبارات وتوثيق. لا تتردد في المساعدة بإضافة أي منهما!
بافتراض أن لديك JDK مثبتًا على نظامك، يجب أن تتمكن من تشغيل ./gradlew shadowJar. بعد ذلك يمكنك تشغيل التطبيق باستخدام java -jar build/libs/gadget-inspector-all.jar <args>.
يقبل هذا التطبيق كوسيط (وسائط) إما مسارًا إلى ملف war (في هذه الحالة سيتم فك الحزمة واستخدام جميع كلاساتها ومكتباتها كمسار كلاس) أو أي عدد من ملفات jar.
لاحظ أن التحليل يمكن أن يكون مكثفًا في استخدام الذاكرة (وحتى الآن لم يتم تحسين مفتش الأدوات على الإطلاق ليكون أقل استهلاكًا للذاكرة). بالنسبة للمكتبات الصغيرة، ربما تحتاج إلى تخصيص 2 جيجابايت على الأقل من حجم الكومة (أي باستخدام العلم -Xmx2G). بالنسبة للتطبيقات الأكبر، سترغب في استخدام أكبر قدر ممكن من الذاكرة.
ستمر مجموعة الأدوات بعدة مراحل من فحص مسار الكلاس لبناء مجموعات بيانات لاستخدامها في المراحل اللاحقة. تُكتب مجموعات البيانات هذه إلى ملفات بامتداد .dat ويمكن التخلص منها بعد تشغيلك (تُكتب في الغالب حتى يمكن تخطي المراحل السابقة أثناء التطوير).
بعد انتهاء التحليل، سيتم كتابة الملف gadget-chains.txt.
فيما يلي مثال من تشغيله ضد commons-collections-3.2.1.jar، على سبيل المثال باستخدام:
wget http://central.maven.org/maven2/commons-collections/commons-collections/3.2.1/commons-collections-3.2.1.jar
java -Xmx2G -jar build/libs/gadget-inspector-all.jar commons-collections-3.2.1.jar
في gadget-chains.txt توجد السلسلة التالية:
com/sun/corba/se/spi/orbutil/proxy/CompositeInvocationHandlerImpl.invoke(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object; (-1)
com/sun/corba/se/spi/orbutil/proxy/CompositeInvocationHandlerImpl.invoke(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object; (0)
org/apache/commons/collections/map/DefaultedMap.get(Ljava/lang/Object;)Ljava/lang/Object; (0)
org/apache/commons/collections/functors/InvokerTransformer.transform(Ljava/lang/Object;)Ljava/lang/Object; (0)
java/lang/reflect/Method.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; (0)
نقطة الدخول لهذه السلسلة هي تطبيق لفئة JDK InvocationHandler. باستخدام نفس الحيلة كما في سلسلة الأدوات الأصلية لـ commons-collections، يمكن الوصول إلى أي تطبيق قابل للتسلسل لهذه الفئة في سلسلة الأدوات، لذلك تبدأ السلسلة المكتشفة هنا. تستدعي هذه الطريقة classToInvocationHandler.get(). تشير سلسلة الأدوات المكتشفة إلى أن classToInvocationHandler يمكن تسلسلها كـ DefaultedMap بحيث يقفز هذا الاستدعاء إلى DefaultedMap.get(). الخطوة التالية في السلسلة تستدعي value.transform() من هذه الطريقة. يمكن تسلسل المعامل value في هذه الفئة كـ InvokerTransformer. داخل طريقة transform لهذه الفئة، نرى أننا نستدعي cls.getMethodName(iMethodName, ...).invoke(...). لقد حدد مفتش الأدوات أن iMethodName يمكن التحكم فيه من قبل المهاجم كعضو مسلسل، وبالتالي يمكن للمهاجم تنفيذ طريقة عشوائية على الفئة.
هذه السلسلة هي اللبنة الأساسية لسلسلة الأدوات الكاملة لـ commons-collections التي اكتشفها Frohoff. في الحالة المذكورة أعلاه، صادف أن مفتش الأدوات اكتشف الدخول عبر CompositeInvocationHandlerImpl و DefaultedMap بدلاً من AnnotationInvocationHandler و LazyMap، لكنها متطابقة إلى حد كبير.
إذا كنت تبحث عن المزيد من الأمثلة عن نوع السلاسل التي يمكن لهذه الأداة العثور عليها، فالمكتبات التالية تحتوي أيضًا على بعض النتائج المثيرة للاهتمام:
لا تنس أنه يمكنك أيضًا توجيه مفتش الأدوات إلى تطبيق كامل (معبأ كـ JAR أو WAR). على سبيل المثال، عند تحليل war لتطبيق Zksample2 نحصل على سلسلة الأدوات التالية:
net/sf/jasperreports/charts/design/JRDesignPieDataset.readObject(Ljava/io/ObjectInputStream;)V (1)
org/apache/commons/collections/FastArrayList.add(Ljava/lang/Object;)Z (0)
java/util/ArrayList.clone()Ljava/lang/Object; (0)
org/jfree/data/KeyToGroupMap.clone()Ljava/lang/Object; (0)
org/jfree/data/KeyToGroupMap.clone(Ljava/lang/Object;)Ljava/lang/Object; (0)
java/lang/reflect/Method.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; (0)
كما ترى، يستخدم هذا العديد من المكتبات المختلفة الموجودة في التطبيق لبناء السلسلة.
س: إذا عثر مفتش الأدوات على سلسلة أدوات، هل يمكن بناء استغلال منها؟
ج: ليس دائمًا. يستخدم التحليل بعض الافتراضات المبسطة ويمكن أن يبلغ عن نتائج إيجابية خاطئة (سلاسل أدوات غير موجودة فعليًا). كمثال بسيط، لا يحاول حل إمكانية إشباع الشروط الفرعية. وبالتالي سيبلغ عن ما يلي كسلسلة أدوات:
public class MySerializableClass implements Serializable {
public void readObject(ObjectInputStream ois) {
if (false) System.exit(0);
ois.defaultReadObject();
}
}
علاوة على ذلك، لدى مفتش الأدوات شروطًا واسعة جدًا لتلك الوظائف التي يعتبرها مثيرة للاهتمام. على سبيل المثال، يعتبر الانعكاس (reflection) مثيرًا للاهتمام (أي استدعاءات Method.invoke() حيث يمكن للمهاجم التحكم في الطريقة)، ولكن غالبًا ما تعني الافتراضات المُغفلة أن المهاجم يمكنه التأثير على الطريقة المستدعاة ولكن ليس لديه سيطرة كاملة. على سبيل المثال، قد يتمكن المهاجم من استدعاء طريقة "getError()" في أي فئة، ولكن ليس أي اسم طريقة آخر.
س: إذا لم يتم العثور على أي سلاسل أدوات، فهل يعني ذلك أن تطبيقي آمن من الاستغلال؟
ج: لا! لأحد الأسباب، لدى مفتش الأدوات مجموعة ضيقة جدًا من وظائف "الحوض" (sink) التي يعتبرها ذات تأثيرات جانبية "مثيرة للاهتمام". هذا بالتأكيد لا يعني أنه لا توجد سلوكيات أخرى مثيرة للاهتمام أو خطيرة غير موجودة في القائمة.
علاوة على ذلك، هناك عدد من القيود على التحليل الثابت (static analysis) التي تعني أن مفتش الأدوات سيكون له دائمًا نقاط عمياء. كمثال، سيفتقد مفتش الأدوات حاليًا ما يلي لأنه لا يتتبع استدعاءات الانعكاس:
public class MySerializableClass implements Serializable {
public void readObject(ObjectInputStream ois) {
System.class.getMethod("exit", int.class).invoke(null, 0);
}
}