
دروبال 11.4.8 - عالي - عن بُعد - SSRF - اكتشاف oEmbed يقوم بطلبات GET لعنوان URL ثانٍ غير محدد النطاق
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · drupal-oembed-ssrf
الفئة: SSRF الوصول: عن بُعد
نواة Drupal 11.4.8 (61044508) - Drupal
SA-CORE-2026-008 قيّد مضيف مستند الاكتشاف باستخدام media_oembed_discovery_trusted_host_patterns. لا يزال UrlResolver::findUrl يُرجع href الخاص بـ link كما هو. بعد ذلك يقوم ResourceFetcher::fetchResource بتنفيذ GET على ذلك العنوان دون أي فحص للمضيف أو لعنوان IP الخاص. وthumbnail_url في oEmbed من نفس فئة طلب GET. الأنماط الافتراضية فارغة، لذا يكون الاكتشاف معطلاً حتى يقوم المسؤول بتفعيله.
بعد أن يقوم المسؤول بتفعيل الاكتشاف، يمكن لمستخدم قادر على إنشاء وسائط oEmbed أن يوجّه Drupal إلى صفحة مسموح بها يكون فيها href الخاص برابط oEmbed بصيغة JSON هو loopback أو RFC1918 أو metadata.
| المعرّف | لا يوجد CVE بعد |
| الفئة | SSRF (بقايا القفزة الثانية من SA-CORE-2026-008) |
| الوصول | عن بُعد (إنشاء وسائط موثّق، بعد أن يضبط المسؤول مضيفي الاكتشاف) |
| CWE | CWE-918 |
| CVSS | متوسط: 6.1 CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N |
| المنتج | نواة Drupal |
| المتأثر | 11.4.8 (61044508071749629aaf3380aa85971e94df9e84) |
| المصادقة | إنشاء وسائط موثّق، بعد أن يضبط المسؤول مضيفي الاكتشاف. AC:H هو مفتاح المسؤول هذا. |
| الترخيص | GNU Affero GPL v3.0 |
| المختبر | 127.0.0.1 فقط |
فقط بعد أن يضبط المسؤول أنماط المضيفين الموثوقين للاكتشاف. يكفي منشئ وسائط بعد ذلك. لا يمكن لشخص غريب تماماً بلا حساب فعل ذلك في الوضع الافتراضي. هذا SSRF، وليس RCE وليس سرقة جلسة مسؤول.
| الصلاحية | الطريقة / نقطة الوصول | النوع | مُثبت مختبرياً أم مُستنتج |
|---|---|---|---|
| جعل Drupal ينفذ GET على عنوان يختاره المهاجم (loopback في هذا المختبر) | UrlResolver::findUrl على href الخام ثم GET عبر ResourceFetcher::fetchResource | استطلاع (جلب من جهة الخادم) | مُثبت مختبرياً. أعاد http://127.0.0.1:18080/oembed القيمة DRUPAL-OEMBED-SSRF-WITNESS |
| قراءة جسم HTTP لذلك العنوان داخل PHP | نفس طلب GET؛ تحليل JSON/XML كـ oEmbed | استطلاع | مُثبت مختبرياً. كان الشاهد في جسم الاستجابة 200 |
نفس طلب GET لـ thumbnail_url بعد بناء المورد | OEmbed::getLocalThumbnailUri ~417-456 | استطلاع | مُستنتج من الإصدار المثبّت. توقف هذا المختبر عند href المكتشف |
| الوصول إلى RFC1918 / link-local / metadata إذا استطاعت شبكة PHP | طلب GET عبر Guzzle غير مقيّد | استطلاع | مُستنتج. استخدم المختبر loopback، وليس 169.254.169.254 |
مغلق في هذه البقايا: القفزة الأولى عندما تكون الأنماط فارغة (مُثبت مختبرياً)؛ القفزة الأولى عندما لا يطابق مضيف HTML (مُثبت مختبرياً)؛ إنشاء وسائط غير موثّق على Standard بدون دور وسائط؛ RCE؛ سرقة جلسة المسؤول.
ثبّتُ Drupal 11.4.8 بعد SA-CORE-2026-008. القفزة الأولى مقيّدة:
$patterns = \array_map(static fn ($hostPattern) => \sprintf('{%s}i', $hostPattern), Settings::get('media_oembed_discovery_trusted_host_patterns', []));
// ...
if (!$allowed) {
return FALSE;
}
$response = $this->httpClient->get($url);
return $this->findUrl($xpath, 'json') ?: $this->findUrl($xpath, 'xml');
يُرجع findUrl الـ href الخام. ينفذ ResourceFetcher طلب GET عليه مع مهلة ولا شيء آخر:
$result = $xpath->query("//link[@type='application/$format+oembed']");
return $result->length ? $result->item(0)->getAttribute('href') : FALSE;
$response = $this->httpClient->request('GET', $url, [
RequestOptions::TIMEOUT => $this->timeout,
]);
المختبر أداة مطابقة لتلك الدوال في 11.4.8، وليس تثبيتاً حياً لموقع drupal:11.4.8. السطر الأخير يستخدم how=gadget. الأنماط الفارغة لم تجلب. المضيف غير المطابق لم يجلب. مع السماح بـ ^firsthop$، أعاد discoverResourceUrl القيمة http://127.0.0.1:18080/oembed وأعاد طلب GET غير المقيّد الشاهد.
المنعطفات الخاطئة المسجّلة مسبقاً: اعتبار الوضع الافتراضي المعطّل خطأً (إنه بوابة القفزة الأولى المقصودة؛ البقايا هي القفزة الثانية)؛ اعتبار تثبيت Standard الحي هو المرجع (هذه الحزمة هي دوال الإصدار المثبّت)؛ ادعاء RCE لأن Guzzle عمل. مسرحية: reverse shell. المرجع هو الوضع الافتراضي المعطّل زائد المضيف الخاطئ المحجوب زائد شاهد القفزة الثانية.
بقايا نفس الإصدار المثبّت: CKEditor 5 FileIsImage skip.
python3 drupal-oembed-ssrf-Abraxas-Labs.py
أو
cd lab
./run.sh
loopback فقط: HTML القفزة الأولى على http://127.0.0.1:19510. القفزة الثانية هي http://127.0.0.1:18080/oembed داخل شبكة الأداة.
SUCCESS drupal-oembed-ssrf how=gadget pin=11.4.8 first-hop=allowed second-hop=127.0.0.1:18080 default-off=blocked DRUPAL-OEMBED-SSRF-WITNESS
طبّق نفس سياسة المضيف / عنوان IP الخاص على نقطة الوصول المكتشفة وعلى thumbnail_url. لا تجلب href كان مضيفه سيفشل في القفزة الأولى.
61044508071749629aaf3380aa85971e94df9e84)UrlResolver.php · ResourceFetcher.phpGNU Affero GPL v3.0. انظر LICENSE. مختبر loopback فقط. دون أي ضمان.