Un módulo que dejaba descargar parameters.php: qué revisar
En febrero de 2023 Gustavo avisó de que el script de etiquetas de un módulo de transportista dejaba bajar parameters.php, con la contraseña de la base de datos. Explicamos el fallo, por qué el parche que circuló no servía y cómo revisar tus módulos.
En febrero de 2023 Gustavo, de la comunidad, avisó de algo grave: el script de descarga de etiquetas del módulo oficial de una empresa de paquetería muy usada en España aceptaba cualquier ruta y cualquier nombre de fichero. Con una URL bien construida se podía bajar app/config/parameters.php, el fichero con el usuario y la contraseña de la base de datos de la tienda. El fallo quedó registrado como vulnerabilidad pública (CVE-2022-46639): si usas ese módulo, comprueba que tu versión lo corrige. Y el patrón aparece en muchos módulos y conviene saber reconocerlo.
Cómo era el fallo
El módulo tenía un fichero PHP en su carpeta, accesible directamente desde el navegador. Recibía por la URL un parámetro con la ruta y otro con el nombre del fichero, los unía y devolvía ese fichero. No comprobaba quién lo pedía ni qué fichero era. Bastaba con poner el nombre de otro fichero de la tienda y la ruta adecuada.
Es lo que se llama descarga arbitraria de ficheros o path traversal. No hace falta entrar en el back-office ni conocer ninguna contraseña.
Por qué es tan grave
parameters.phptrae el servidor, el usuario y la contraseña de la base de datos, y las claves secretas de la instalación.- Si la base de datos acepta conexiones desde fuera, con eso basta para leer clientes y pedidos o para crear un empleado administrador.
- Aunque no las acepte, el mismo fallo sirve para leer otros ficheros: copias de seguridad olvidadas en el servidor, logs, configuraciones de otros módulos con claves de API.
El parche que circuló, y por qué no bastaba
En el grupo se compartió una versión corregida del script, hecha con ChatGPT. Validaba que el nombre acabase en .pdf y comprobaba la ruta con realpath(), que es la idea correcta. Pero exigía que la ruta real, que es absoluta (del tipo /var/www/…/modules/…), empezase por un texto relativo, /modules/nombre-del-modulo/. Eso nunca se cumple: el parche bloqueaba todo, también las etiquetas buenas.
Otro miembro del grupo lo resumió bien: lo mejor es que ese script no exista y que el PDF se sirva desde el propio módulo, con el empleado identificado. Y Gustavo añadió algo importante: el arreglo lo tiene que publicar quien mantiene el módulo, para que llegue a todas las tiendas. Un parche hecho a mano en tu servidor se pierde con la siguiente actualización.
Cómo es una descarga segura
Si mantienes un módulo que entrega ficheros, la forma segura tiene tres piezas: se sirve desde un controlador del módulo que exige identificación, el fichero se pide por su nombre sin ruta, y la ruta final se valida contra una carpeta fija. Un esquema mínimo:
// En un controlador de administración del módulo (ModuleAdminController),
// que ya exige un empleado identificado. Nunca en un .php suelto.
$base = realpath(_PS_MODULE_DIR_ . 'mimodulo/etiquetas');
$name = basename((string) Tools::getValue('etiqueta'));
if ($base === false || !preg_match('/^[A-Za-z0-9_-]+\.pdf$/', $name)) {
exit;
}
$file = realpath($base . DIRECTORY_SEPARATOR . $name);
if ($file === false || strpos($file, $base . DIRECTORY_SEPARATOR) !== 0) {
exit;
}
header('Content-Type: application/pdf');
readfile($file);Lo importante: basename() quita cualquier ruta que venga en el nombre, y la comparación final se hace entre dos rutas absolutas. Pruébalo antes en una copia de la tienda.
Qué revisar en tu tienda
- Actualiza los módulos de transportistas y de etiquetas a su última versión, descargada de su origen oficial.
- Busca scripts sueltos que lean ficheros a partir de la URL. Desde la raíz de la tienda, por SSH:
No todo lo que salga es un fallo, pero cada resultado merece una mirada.grep -rlE 'readfile|file_get_contents|fopen' modules/ | xargs grep -lE '\$_(GET|REQUEST|POST)' - Limita la ejecución directa de PHP dentro de
modules/a lo que de verdad la necesite. Los módulos bien hechos funcionan a través de controladores. - Si un script así ha estado expuesto, da por filtrada la contraseña de la base de datos: cámbiala en el panel del hosting y en
parameters.php, revisa los empleados del back-office y busca en los logs del servidor peticiones a ese script con nombres de fichero raros.
Ese mismo mes, INCIBE publicó avisos de vulnerabilidades en otro módulo de PrestaShop, y su desarrollador respondió que una ya estaba corregida y la otra saldría en la versión siguiente. Es lo normal: los fallos aparecen; lo que marca la diferencia es actualizar rápido.
Si quieres que revisemos los módulos de tu tienda, en Rekire lo hacemos dentro de nuestros bonos de horas.
Esto salió en @PrestashopEsp, la mayor comunidad PrestaShop de España en Telegram. Ver la conversación