
Drupal 11.4.8 - Hoch - Remote - SSRF - oEmbed-Discovery führt GET auf eine nicht eingegrenzte Second-Hop-URL aus
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · drupal-oembed-ssrf
Klasse: SSRF Reichweite: Remote
Drupal core 11.4.8 (61044508) - Drupal
SA-CORE-2026-008 hat den Host des Discovery-Dokuments mit media_oembed_discovery_trusted_host_patterns abgesichert. UrlResolver::findUrl gibt weiterhin das rohe link-href zurück. ResourceFetcher::fetchResource führt dann ein GET auf diese URL aus, ohne Host- oder Private-IP-Prüfung. oEmbed thumbnail_url ist dieselbe Art von GET. Die Standardmuster sind leer, daher ist Discovery deaktiviert, bis ein Administrator sie aktiviert.
Nachdem ein Administrator Discovery aktiviert hat, kann ein Benutzer, der oEmbed-Medien erstellen kann, Drupal auf eine allowlistete Seite zeigen lassen, deren JSON-oEmbed-Link-href auf Loopback, RFC1918 oder Metadaten zeigt.
| ID | noch keine CVE |
| Klasse | SSRF (Second-Hop-Überbleibsel von SA-CORE-2026-008) |
| Reichweite | Remote (authentifiziertes Media-Create, nachdem ein Administrator Discovery-Hosts festgelegt hat) |
| CWE | CWE-918 |
| CVSS | Medium: 6.1 CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N |
| Produkt | Drupal core |
| Betroffen | 11.4.8 (61044508071749629aaf3380aa85971e94df9e84) |
| Auth | authentifiziertes Media-Create, nachdem ein Administrator Discovery-Hosts festgelegt hat. AC:H ist dieser Admin-Toggle. |
| Lizenz | GNU Affero GPL v3.0 |
| Lab | nur 127.0.0.1 |
Nur nachdem ein Administrator Discovery-Trusted-Host-Muster festgelegt hat. Danach reicht ein Media-Creator aus. Ein völlig Fremder ohne Konto kann dies im Standardfall nicht tun. Dies ist SSRF, kein RCE und kein Admin-Login.
| Privileg | Methode / Sink | Art | Lab-bewiesen oder abgeleitet |
|---|---|---|---|
| Drupal ein vom Angreifer gewähltes URL abrufen lassen (Loopback in diesem Lab) | UrlResolver::findUrl rohes href, dann ResourceFetcher::fetchResource GET | Recon (serverseitiger Abruf) | Lab-bewiesen. http://127.0.0.1:18080/oembed gab DRUPAL-OEMBED-SSRF-WITNESS zurück |
| Den HTTP-Body dieser URL in PHP einlesen | Dasselbe GET; JSON/XML als oEmbed geparst | Recon | Lab-bewiesen. Der Witness war im 200-Body |
Dasselbe GET für thumbnail_url, nachdem eine Ressource erstellt wurde | OEmbed::getLocalThumbnailUri ~417-456 | Recon | Abgeleitet aus dem Pin. Dieses Lab endete beim entdeckten href |
| RFC1918 / Link-Local / Metadaten erreichen, wenn der PHP-netns dies kann | Unscoped Guzzle GET | Recon | Abgeleitet. Das Lab verwendete Loopback, nicht 169.254.169.254 |
Geschlossen bei diesem Überbleibsel: erster Hop, wenn Muster leer sind (lab-bewiesen); erster Hop, wenn der HTML-Host nicht übereinstimmt (lab-bewiesen); unauthentifiziertes Media-Create auf Standard ohne Media-Rolle; RCE; Admin-Session-Diebstahl.
Ich habe Drupal 11.4.8 nach SA-CORE-2026-008 gepinnt. Der erste Hop ist abgesichert:
$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 gibt das rohe href zurück. ResourceFetcher führt ein GET darauf aus, mit einem Timeout und sonst nichts:
$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,
]);
Das Lab ist ein originalgetreues Gadget dieser 11.4.8-Funktionen, keine Live-Installation einer drupal:11.4.8-Seite. Die letzte Zeile verwendet how=gadget. Leere Muster haben nicht abgerufen. Ein nicht übereinstimmender Host hat nicht abgerufen. Mit erlaubtem ^firsthop$ gab discoverResourceUrl http://127.0.0.1:18080/oembed zurück, und das unscoped GET gab den Witness zurück.
Bereits dokumentierte Irrwege: Default-off als Fehlschlag zu behandeln (es ist das beabsichtigte First-Hop-Gate; das Überbleibsel ist Hop zwei); eine Live-Standard-Installation als Orakel zu bezeichnen (dieses Paket sind die Pin-Funktionen); RCE zu behaupten, weil Guzzle lief. Theater: eine Reverse Shell. Das Orakel ist Default-off plus Wrong-Host-Blocked plus der Second-Hop-Witness.
Gleiche Pin-Überbleibsel: CKEditor 5 FileIsImage skip.
python3 drupal-oembed-ssrf-Abraxas-Labs.py
oder
cd lab
./run.sh
Nur Loopback: First-Hop-HTML auf http://127.0.0.1:19510. Der zweite Hop ist http://127.0.0.1:18080/oembed innerhalb des Gadget-netns.
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
Wenden Sie dieselbe Host-/Private-IP-Richtlinie auf den entdeckten Endpunkt und auf thumbnail_url an. Rufen Sie kein href ab, dessen Host den ersten Hop nicht bestanden hätte.
61044508071749629aaf3380aa85971e94df9e84)UrlResolver.php · ResourceFetcher.phpGNU Affero GPL v3.0. Siehe LICENSE. Nur Loopback-Lab. Keine Gewährleistung.