Insecure Deserialization

Insecure Deserialization

 

أمور يجب عليك معرفتها قبل قراءة هذه المقالة:

-       معرفة بسيطة بلغة جافا (المثال في هذه المقالة مُستند على هذه اللغة )

 

 

السلام عليكم ورحمة الله وبركاته ،

هذه المقالة تناقش ثغرة Insecure Deserialization

 

قبل الخوض في تفاصيل هذه الثغرة، نحن بحاجة لفهم مفهومين مُهمّين في لغات البرمجة:

·      Object Serialization

·      Object Deserialization

 

Object Serialization

هي عملية تحويل الـ Object  إلى Bytes ، ومن ثم هذه الـ Bytes بالإمكان حفظها في ملف ( أي حفظ الحالة الخاصة بهذا الـ Object)، أو في قاعدة بيانات، أو تمريرها عبر الشبكة إلى تطبيق آخر بإستخدام أحد بروتوكولات الشبكة

 

Object Deserialization

هي العملية العكسية للعملية السابقة، أي لدينا بيانات مُمثلة على شكل Bytes يتم قراءتها من ملف، أو قاعدة بيانات، أو قد يتم استقبالها عبر الشبكة عن طريق أحد البروتوكولات مثل بروتوكول الـ HTTP  ومن ثم يتم تحويل هذه الـ Bytes إلى صورتها الأولى الـ Object

 

الصورة التالية تلخص العمليتين:

 

Diagram

Description automatically generated

 

هذا بالنسبة للجانب النظري، نأتي الآن للجانب التطبيقي ونأخذ المثال التالي على هذين المفهومين في لغة جافا

 

Object Serialization in Java

في لغة جافا إذا أردنا تطبيق هذا المفهوم وتحويل الـ Objects  إلى Bytes لتُعالج في طرف آخر، فيجب علينا عمل implements  للـ interface  التالي :

-       Serializable

كما يظهر في الكود التالي، تم تعريف كلاس Item  والذي يقوم بعمل implement  للـ Serializable ( السطر 5  )

 

Text

Description automatically generated

 

الآن بإمكاننا تعريف أي Object من كلاس Item ومن ثم تحويل هذا الـ   Object  إلى Bytes stream  

 

في الكود التالي قمنا بتعريف كلاس Serialize ، وفي دالة الـ main قمنا بتعريف Object من كلاس Item   ( السطر 10 )

 

Text

Description automatically generated

 

السطر 12 : قمنا بتعريف Object من FileOutputStream   لكتابة محتوى الـ s1 ( في صورة Bytes ) في ملف يسمى data.ser

 

السطر 14 : في هذا السطر قمنا بنداء الدالة writeObject وتم تمرير الـ s1 لها، هذه الدالة ستقوم بتحويل الحالة الخاصة بالـ Object  إلى Bytes ( هنا تحدث عملية الـ Serialization )

 

The Java serialized object

بعد عمل Compile  للكود السابق سيكون المخرج لدينا ملف data.ser والذي يحتوي على الـ Object  من كلاس Item  لكن في صورة Bytes

 

 

 

لو قمنا بإستخدام أداة file للإطلاع على نوع ملف data.ser سنجد أن الأداة تطبع لنا الناتج الآتي :

 

 

ولو قمنا بقراءة محتوى ملف data.ser في صورة Hex باستخدام أداة hexdump سنجد أن محتوى الملف يبدأ بهذه القيمة : aced

 

A close up of a keyboard

Description automatically generated

 

ولو أردنا الإطلاع على المقابل لهذه القيمة في التمثيل Base64  سيظهر لنا المُخرج الآتي :

 

 

ماذا نستفيد من هذه المعلومات؟

يكفي أن نعرف إلى الآن أن الـ Java Serialized Object يحمل الـ Signature الآتي :

-       في التمثيل Hex  : aced

-       في التمثيل Base64  : rO0AB

في المقابل، ماذا لو أردنا الإطلاع على محتوى هذا الـ Object لكن بصورة مقروءة ومفهومة لنا أكثر؟

لحُسن الحظ قام أحد الباحثين بتطوير أداة تُمكّننا من قراءة الـ Java Serialized Object بشكل أكثر وضوحًا بدلًا من قراءته بالـ Hex أو الـ Base64 ، وهذه الأداة هي : SerializationDumper

 

الصورة الآتية توضح إستخدام هذه الأداة والمُخرج من قراءة محتوى ملف الـ data.ser

 

Text

Description automatically generated

 

بعد الخوض في مفهوم الـ Serialization  وتحليل الناتج النهائي من هذه العملية ( Serialized Object ) لننتقل الآن للعملية العكسية المقابلة لها ، الـ Deserialization

 

Object Deserialization in Java

في الكود التالي قمنا بتعريف كلاس Deserialize  والذي سنطبق فيه مفهوم الـ Deserialization

 

Text

Description automatically generated

 

السطر 10  :  قمنا بقراءة محتوى ملف data.ser عن طريق الـ FileInputStream  و ObjectInputStream

السطر 11  : قمنا بتعريف Object  من كلاس Item ومن ثم سيتم حفظ القيمة العائدة من دالة readObject  في هذا الـ object

وبعبارة أخرى: دالة readObject ستقوم بقراءة محتوى ملف  data.ser  ( والذي هو عبارة عن Bytes ) ومن ثم هذه الـ Bytes  سيتم إرجاعها إلى صورتها الأولى Object  ( هنا تحدث عملية الـ Deserialization )

 

الآن نحن نملك المعرفة اللازمة لفهم ثغرة الـ Insecure Deserialization ولماذا تحدث؟

ننتقل لمناقشة تفاصيل هذه الثغرة في الجزء التالي من المقالة

 

Insecure Deserialization

بشكل مُختصر جدًا : يحدث هذا النوع من الثغرات عندما يكون بإمكان المخترق التحكّم والتلاعب بالبيانات التي يتم عمل لها Deserialize

 

لنفصّل أكثر ..

نقصد بالبيانات هنا الـ Object الذي تم حفظ حالته وتحويلها إلى صورة Bytes

فعلى سبيل المثال لو كان لدينا تطبيقين :

-       التطبيق الأول : يقوم بتنفيذ عملية الـ Serialization على الـ Object ومن ثم يقوم بإرسال المُخرَج النهائي عبر الشبكة إلى التطبيق الثاني

-       التطبيق الثاني : يستقبل هذه البيانات ومن ثم يجري عليها عملية الـ Deserialization

-       المشكلة : إذا لم يقم التطبيق الثاني بالتأكد من سلامة البيانات التي يعالجها لتنفيذ عملية الـ Deserialization وكان بإمكان المخترق إعتراض هذه البيانات والتلاعب بها فهنا تحدث ثغرة الـ Insecure Deserialization !

 

الآن لننتقل للجزء الأخير من هذه المقالة،

التدريب على هذه الثغرة وتحليل هذا التطبيق البسيط الذي يحاكي هذه المشكلة.

 

java-deserialize-webapp

بدايةً نقوم بعمل Run للتطبيق كالآتي :

 

 

ومن ثم نستطيع تصفح التطبيق عبر المنفذ التالي :

127.0.0.1:8000

 

Graphical user interface, text, application

Description automatically generated

 

التطبيق سيقوم بإستقبال البيانات التي نمررها له ومن ثم سيقوم بعمل Deserialization لها بدون التأكد من سلامتها،

بإمكاننا إستغلال هذه المشكلة بطرق عدّة، لكن في هذه المقالة سنقوم ببناء إستغلال بسيط جدًا يؤكد لنا أن التطبيق مُصاب بالفعل

 

DNS Resolution Exploit

فكرة الإستغلال :

نقوم بتمرير Serialized Object إلى التطبيق المصاب،

وهذا الـ Serialized Object خلال عملية الـ Deserialization سيتيح لنا تنفيذ الأوامر التي نريدها،

في هذا الاستغلال سنجعل التطبيق المصاب يقوم بعمل DNS query لدومين خاص بنا

 

 

قبل بناء الـ payload  التي سنقوم بإرسالها للتطبيق المصاب، سنقوم باستخدام DNS Proxy

-       الغرض من هذه الخطوة :

إعتراض الـ DNS request  الصادر من التطبيق المصاب، حتى نتأكد بأن الـ payload  التي قمنا بإرسالها تم عمل Run لها بشكل سليم

 

Text

Description automatically generated

 

الآن سنقوم ببناء الـ payload  أو الـ Serialized Object  بإستخدام هذه الأداة  كالآتي :

 

Text

Description automatically generated

 

بعد بناء الـ Serialized Object بإمكاننا الإستعانة بأداة الـ SerializationDumper  التي قمنا بالإطلاع عليها سابقًا لتحليل هذا الـ Object وفهم محتواه ( هذه الخطوة للتحليل فقط، ولاحظ بأني قمت بتمرير raw data  للأداة ولم أقم بتمرير Base64 )

 

 

Text

Description automatically generated

 

الآن نقوم بإرسال الـ payload إلى التطبيق

 

Graphical user interface, text, application

Description automatically generated

 

بعد إرسال الـ payload نلاحظ أن التطبيق يخبرنا بأن عملية الـ Deserialization نجحت

 

Graphical user interface, text, application

Description automatically generated

 

ولو عدنا إلى الـ DNS Proxy  سنجد أن التطبيق المصاب بالفعل قام بعمل DNS query

 

Text

Description automatically generated

 

 

ختامًا، أود الإشارة بأن هذه المقالة تمّت كتابتها خلال دراسة هذه الثغرة والبحث حولها، فكل ما تم ذكره هنا قد يحتمل الخطأ، لكن بالإمكان العودة إلى المراجع التي إستندت عليها هذه المقالة

وإن أصبت فمن توفيق الله وحده، وإن أخطأت فمن نفسي والشيطان

 

مواضيع مُقترحة لفهم هذه الثغرة بتعمق أكثر:

·      Property-Oriented Programming