CVE-2026-32746 是 GNU InetUtils telnetd 中一个严重的身份验证前缓冲区溢出漏洞,影响 2.7 及更早版本。该漏洞存在于 LINEMODE SLC(设置本地字符)处理程序中,其中的 add_slc() 函数 (telnetd/slc.c) 会将每个 SLC 三元组写入一个固定的 108 字节缓冲区,而没有进行任何边界检查。未经身份验证的攻击者可以在选项协商期间(在任何登录提示之前)发送一个包含 40 个以上三元组的精心构造的 SLC 子选项,从而导致缓冲区溢出,破坏 BSS 段中的指针 slcptr,并在后续的 end_slc() 函数使用该被破坏的指针时触发任意写入操作。
受影响版本
以下版本的 GNU InetUtils telnetd 存在漏洞:
- GNU InetUtils
telnetd 2.7 及更早版本(所有版本)
- 任何源自 BSD SLC 代码库的
telnetd 实现
漏洞工作原理
要理解这个漏洞,首先需要了解一些关于Telnet协议如何协商功能的内容。当客户端和服务器同意使用 LINEMODE 模式时,服务器会发送 SLC 三元组——这些三元组是 3 字节的小消息,用于定义如何处理诸如 interrupt、erase 和 kill 之类的特殊字符。服务器会将 SLC 回复排队到一个名为 slcbuf 的静态缓冲区中。
核心问题在于,add_slc() 函数在写入缓冲区之前从未验证 slcbuf 是否有足够的空间。缓冲区总共 108 字节,子选项头部占用 4 字节,剩余 104 字节可用。每个回复三元组占用 3 字节,因此缓冲区大约可以安全容纳 34 个三元组(104 ÷ 3 ≈ 34)。从第 35 个三元组开始,后续的每次写入都会超出缓冲区范围。
尤其危险的是未识别功能码的行为。GNU InetUtils 定义了 18 个有效的 SLC 功能码(常量为 NSLC = 18)。当服务器收到功能码大于 18 的三元组时,它无法识别该功能码,但仍然会调用 add_slc() 函数将“不支持”的回复加入队列。攻击者只需发送数十个高功能码,服务器就会忠实地尝试响应每一个功能码,每次都导致数据写入缓冲区末尾之外更远的位置。
由于写入位置指针 slcbuf 和溢出数据都 slcptr 位于 BSS 段,溢出操作会破坏 slcptr 自身。当后续的 end_slc() 操作通过这个已被破坏的指针写入子选项结束标记时,它会对攻击者控制的内存地址执行任意写入操作。这至少会导致 telnetd 程序崩溃,如果能够精确控制溢出数据,则可能完全重定向程序执行。
整个攻击过程发生在选项协商期间,这意味着攻击者无需进行任何身份验证。无需用户名,无需密码——只需一个原始的 TCP 连接。
攻击流程
该攻击遵循清晰的步骤:
- 攻击者连接到
telnetd 服务器,接收服务器的初始选项协商提议,并全部接受。
- 攻击者主动发送
WILL LINEMODE 消息以触发服务器的 LINEMODE 处理程序。
- 服务器响应
DO LINEMODE 并开始 SLC 子选项处理。
- 此时,攻击者发送一个精心构造的 SLC 子选项,其中包含 40 到 60 个功能码大于 18 的三元组。
- 每个三元组强制服务器通过
add_slc() 写入 3 个字节,大约 35 个三元组后,104 字节的缓冲区溢出,覆盖了 slcptr。
- 随后,服务器在试图结束子选项时,利用被溢出的
slcptr 值执行 end_slc(),根据溢出内容的不同,导致服务器崩溃或执行任意写入操作。
先决条件
在开始本教程之前,请确保您的计算机上已安装以下软件:
- Docker 和 Docker Compose —— 用于构建隔离的、易受攻击的实验室环境。
- Python 3 —— 运行检测脚本和漏洞利用 PoC 都需要此版本。
- 对 Telnet 协议和二进制漏洞利用概念有基本的了解。
搭建实验室环境
PoC 存储库提供了一个完整的基于 Docker 的实验室,该实验室在 Debian 容器内运行一个易受攻击的 inetutils-telnetd 版本(版本 2.4),由 xinetd 管理并通过 2323 端口暴露。所有操作都与您的主机隔离。
1. 克隆仓库:
git clone https://github.com/jeffaf/cve-2026-32746.git
cd cve-2026-32746
2. 构建并启动存在漏洞的容器:
docker compose up -d
此命令会构建已安装 inetutils-telnetd 的 Docker 镜像,使用包含的配置文件 xinetd-telnet.conf 配置 xinetd 服务,并将其暴露在 localhost:2323。
3. 验证服务运行:
使用以下命令验证其是否正在运行:
docker compose ps
4. 测试连接性:
利用漏洞之前请先测试连接性:
telnet 127.0.0.1 2323
您应该会看到登录提示。按下 Ctrl+] 并输入 quit 以断开连接。
运行检测脚本
该代码库包含 detect.py,一个非破坏性扫描器,它可以在不导致目标系统崩溃的情况下检查其运行的 telnetd 程序是否存在漏洞。这非常适合在授权评估期间安全地识别存在漏洞的主机。
python3 detect.py 127.0.0.1 2323
该脚本会连接服务器,执行基本的选项协商,并检查服务器是否接受 LINEMODE 选项——这是利用此漏洞的先决条件。如果脚本报告 LINEMODE 选项已被接受,则目标服务器很可能存在漏洞。
运行漏洞利用概念验证
警告:此漏洞利用程序会导致 telnetd 进程崩溃。请仅在您自己的 Docker 实验环境或您拥有并已获得明确书面许可的系统上运行此程序进行测试。
基本用法(默认发送 60 个三元组——远远超过约 35 个的溢出阈值):
python3 exploit.py 127.0.0.1 2323
自定义三元组数量 (使用 -n 标志):
# 发送恰好 40 个三元组(刚好越过溢出边界)
python3 exploit.py 127.0.0.1 2323 -n 40
# 发送 80 个三元组,造成更严重的溢出
python3 exploit.py 127.0.0.1 2323 -n 80
调整套接字超时时间 (使用 -t 标志,针对慢速网络):
python3 exploit.py 127.0.0.1 2323 -t 15
预期输出
当漏洞利用成功触发溢出时,您应该会看到类似这样的输出:
============================================================
CVE-2026-32746 - telnetd SLC Buffer Overflow PoC
============================================================
Target: 127.0.0.1:2323
Triplets: 60 (overflow at ~35)
============================================================
[+] Connected to 127.0.0.1:2323
Phase 1: Reading server negotiation...
Received XX bytes of negotiation
Sent XX bytes (negotiation + WILL LINEMODE)
Phase 2: Waiting for LINEMODE activation...
[+] Server accepted LINEMODE (DO LINEMODE received)
Phase 3: Sending malicious SLC suboption
Payload size: XX bytes
SLC triplets: 60
Buffer size: 104 bytes (usable)
Data written: 180 bytes
Overflow: 76 bytes past buffer end
[+] Payload sent
Phase 4: Checking server state...
[+] Connection error: [Errno 104] Connection reset by peer
[+] Buffer overflow triggered - telnetd crashed!
[+] VULNERABLE - CVE-2026-32746 confirmed
确认发生在第 4 阶段——要么是“连接被对等方重置”错误,要么是套接字超时,这意味着 telnetd 崩溃,因为 end_slc() 解引用了损坏的 slcptr。
了解漏洞利用代码
PoC 的运行分为四个阶段,与 Telnet 协议交换直接对应。
- 第一阶段——协商:脚本读取服务器的初始
DO/WILL 选项报价并接受所有报价。它还会主动发送 WILL LINEMODE 消息以触发服务器的 SLC 处理程序,并发送终端类型(xterm)和速度(38400,38400)所需的子选项响应,以防止服务器卡死。
- 第二阶段——LINEMODE 激活:脚本等待服务器回复
DO LINEMODE,确认 LINEMODE 协商已激活且 SLC 处理可用。
- 第三阶段——有效载荷传递:脚本构建一个恶意 SLC 子选项,其中包含配置数量的三元组(默认 60 个)。每个三元组使用大于
NSLC (18) 的功能码,强制服务器通过 add_slc() 返回“不支持”的响应——每个三元组写入 3 个字节。60 个三元组共写入 180 字节,而缓冲区大小为 104 字节,因此溢出 76 字节。
- 第四阶段——崩溃检测:短暂延迟后,脚本尝试从套接字读取数据。连接重置或超时表明守护进程因解引用损坏的
slcptr 而崩溃。
PoC 文件概览
| 文件 |
目的 |
exploit.py |
崩溃/拒绝服务攻击概念验证漏洞利用 |
detect.py |
非破坏性 LINEMODE 漏洞扫描器 |
Dockerfile |
构建存在漏洞的 telnetd 实验室镜像 |
docker-compose.yml |
一键式实验室搭建和拆卸 |
xinetd-telnet.conf |
telnetd 的 xinetd 服务配置 |
进一步:从拒绝服务攻击到远程代码执行
这个概念验证仅演示了崩溃(拒绝服务)。要构建完整的远程代码执行链,还需要大量工作:映射 BSS 布局以找到从 slcbuf 到 slcptr 的精确偏移量,通过损坏的指针控制 end_slc() 写入的值,覆盖 GOT 条目或函数指针以重定向执行,并构建 ROP 链或 shellcode 有效载荷。这并非易事,但并非不可能——这也解释了该漏洞为何能获得 9.8 分的高 CVSS 评分。
清理
测试完成后,请拆除 Docker 实验室:
docker compose down
这将彻底停止并移除容器。主机上不会保留任何内容。
缓解措施
如果您在生产环境中使用 GNU InetUtils telnetd,则应立即采取措施。最有效的缓解措施是完全禁用 telnet 服务并切换到 SSH,后者提供加密和强身份验证的远程访问。如果必须使用 telnet,请使用防火墙规则将访问限制在受信任的 IP 地址范围内,并密切关注 GNU InetUtils 项目的官方补丁。
项目地址
完整的 PoC 代码和实验室环境可在以下地址获取:
https://github.com/jeffaf/cve-2026-32746
对于这类底层安全漏洞的研究与复现,有助于我们更深刻地理解系统安全机制。如果你对漏洞原理分析、渗透测试技术有更多兴趣,欢迎在 云栈社区 与更多安全研究者交流探讨。