
Análisis detallado y exploit PoC para CVE-2025-2825, una omisión de autenticación en CrushFTP. Incluye plantillas de nuclei, escáner multihilo y script de creación de usuarios para pruebas de penetración.
Este documento presenta la investigación de la vulnerabilidad CVE-2025-2825, que afecta al servidor CrushFTP, una solución comercial para la transferencia y almacenamiento de archivos (FTP, SFTP, HTTP/S, interfaces similares a S3, etc.).
El defecto se clasifica como bypass de autenticación, que permite a un atacante remoto no autenticado obtener privilegios de administrador. La explotación exitosa otorga acceso con privilegios crushadmin, visualización y modificación de archivos, gestión de cuentas de usuario y ejecución de operaciones administrativas a través de la interfaz web y la API de CrushFTP.
Versiones afectadas reportadas (según avisos públicos e informes de investigadores):
⚠️ Nota: en algunas publicaciones aparecen duplicados y superposiciones de identificadores CVE (por ejemplo, CVE-2025-31161).
Analizar paso a paso la vulnerabilidad y demostrar el ciclo completo de investigación, que incluye:
Según informes públicos, la vulnerabilidad tiene riesgo crítico:
Son críticas las instancias con las siguientes características:
CrushFTP (cualquier edición con interfaz web).CrushFTP implementa soporte para una API similar a S3. Para la autenticación se utiliza el encabezado Authorization de la forma:
Authorization: AWS4-HMAC-SHA256 Credential=<AccessKey>/<Date>/<Region>/s3/aws4_request, SignedHeaders=<Headers>, Signature=<Signature>
El servidor extrae el AccessKey de Credential y debería verificar la firma. Sin embargo, se cometió un error en el código al manejar el flag lookup_user_pass.
// ServerSessionHTTP.java, método loginCheckHeaderAuth()
if (this.headerLookup.containsKey("AUTHORIZATION") &&
this.headerLookup.getProperty("AUTHORIZATION").trim().startsWith("AWS4-HMAC")) {
boolean lookup_user_pass = true; // ← error crítico
if (s3_username3.indexOf("~") >= 0) {
user_pass = user_name.substring(user_name.indexOf("~") + 1);
user_name = user_name.substring(0, user_name.indexOf("~"));
lookup_user_pass = false;
}
if (this.thisSession.login_user_pass(
lookup_user_pass,
false,
user_name,
lookup_user_pass ? "" : user_pass)) {
// Autenticación exitosa
}
}
El flag lookup_user_pass se pasa directamente como anyPass:
if (anyPass && user.getProperty("username").equalsIgnoreCase(the_user)) {
return user; // autenticación sin verificar contraseña
}
Por lo tanto:
En la versión 11.3.1 y posteriores, los desarrolladores:
s3_auth_lookup_password_supported (por defecto false), que bloquea el escenario vulnerable.lookup_user_pass → anyPass.s3_auth_lookup_password_supported.La explotación de CVE-2025-2825 es bastante simple y no requiere una preparación compleja. El atacante solo necesita enviar una solicitud HTTP especialmente diseñada que contenga dos elementos clave:
Authorization en formato AWS S3, que contenga el nombre de usuario existente correcto (campo Credential con AccessKey/username).CrushAuth en el formato esperado y el parámetro c2f en la URL/cuerpo de la solicitud, cuyos valores se corresponden lógicamente (el formato de la cookie debe coincidir con la estructura esperada por el servidor).Si el servidor es vulnerable (versión en el rango 10.0.0—10.8.3 o 11.0.0—11.3.0 y no se ha aplicado el parche correctivo), esta combinación hace que el manejador de autenticación siga la ruta vulnerable, donde el flag de búsqueda de contraseña (lookup_user_pass) se interpreta como «cualquier contraseña es válida», y el usuario se autentica solo por el nombre sin verificar la contraseña.
Nota importante:
La explotación de esta vulnerabilidad generalmente requiere el envío de dos solicitudes consecutivas. La primera, denominada solicitud de «calentamiento» (warm-up), inicia el proceso de autenticación vulnerable en el servidor. Un signo característico de que el servidor ha entrado en el estado deseado es recibir como respuesta un error
502 Bad Gatewayo simplemente un tiempo de espera agotado (timeout). Inmediatamente después se envía la segunda solicitud, la principal, que realiza la acción útil (por ejemplo, crear un usuario), mientras el servidor se encuentra en el estado vulnerable al ataque.
GET /WebInterface/function/?command=getUserList&serverGroup=MainUsers&c2f=1111 HTTP/1.1
Host: target-server:8080
Cookie: CrushAuth=1743113839553_vD96EZ70ONL6xAd1DAJhXMZYMn1111
Authorization: AWS4-HMAC-SHA256 Credential=crushadmin/
Para la prueba, tomé el laboratorio lanzado recientemente en HTB — Soulmate, donde precisamente se requiere explotar CrushFTP.

Gracias a esta vulnerabilidad, se puede agregar un nuevo usuario con derechos de administrador mediante el comando setUserItem. Para ello, ejecute new_user.py:
python3 new_user.py --target_host http://ftp.soulmate.htb/ --port 80 --target_user crushadmin --new_user literide --password literide
Análisis del encabezado Authorization: Cuando el servidor ve un encabezado de autorización en formato similar a S3 (AWS4-HMAC...), extrae del campo Credential el identificador del cliente (AccessKey / username). En esta etapa, el servidor obtiene una cadena que considera el nombre de usuario; este valor identificativo se utiliza posteriormente en la lógica de autenticación.
El flag lookup_user_pass y su rol:
En el código hay un flag booleano lookup_user_pass que debería indicar de dónde obtener la contraseña durante la verificación:
Transmisión del flag a lo largo de la cadena de llamadas:
Ruta aproximada: ServerSessionHTTP.loginCheckHeaderAuth() → Session.login_user_pass(...) → UserTools.ut.verify_user(...). Al inicio, el flag define el comportamiento, y en verify_user lleva a un retorno temprano del objeto de usuario encontrado sin comparar la contraseña, si el nombre coincide. Esto proporciona la evasión de la verificación de autenticación: el servidor «reconoce» al usuario por su nombre y lo considera autenticado.
Elementos acompañantes (cookie / c2f): En los análisis públicos se indicó que el manejador espera un formato correcto de cookie/parámetros con el fin de emparejar la solicitud con la sesión/contexto. Sin embargo, el defecto clave es el error lógico en el manejo de ; los otros elementos solo ayudan a que la solicitud pase por las ramas de procesamiento estándar.
Causa clave
Credential, llevó a que la presencia de un nombre de usuario correcto fuera suficiente para obtener los datos de autenticación del usuario sin verificar la contraseña.Plantilla pasiva:
Dado que en la mayoría de los servicios web no es posible determinar la versión exacta de CrushFTP, esta plantilla simplemente verifica si el servicio utiliza CrushFTP.
Es mejor usarla en combinación con la plantilla activa
Plantilla activa:
La plantilla activa verifica si es posible el comando getUserList.

Script multiproceso
El script funciona de manera similar a la plantilla activa, pero es mucho más rápido y admite la posibilidad de verificar varios hosts a la vez.
python3 scan.py -t http://ftp.soulmate.htb/ -p 80 -u crushadmin

Para reducir los riesgos asociados con CVE-2025-31161, se recomienda tomar las siguientes medidas:
Actualización inmediata:
Aplicación de Workaround (si no es posible actualizar):
s3_auth_lookup_password_supported en false. Esto desactivará la lógica de autenticación vulnerable sin actualizar todo el producto.Medidas de compensación de riesgos:
AWS4-HMAC-SHA256 en el encabezado Authorization, especialmente si no se utiliza la integración S3.Authorization anómalos hacia endpoints no destinados a la API S3.lookup_user_pass