先建立直觉#Telnet 可以想象成一台"对讲机":你说的话和你发出的指挥动作都走同一条无线电波,而且谁都能拿个收音机在旁边听个一字不漏——这就是它"明文"和"带内控制"的本质。为了不让指挥动作(比如"我要改回显规则了")被误当成普通说话内容,Telnet 规定一个特殊代号:凡是看到 0xFF 这个字节,后面跟的就不再是文字,而是"命令"。有了这条规则,一条纯字节流上就能同时跑"聊天内容"和"终端控制指令",而不需要开两条连接。
它解决什么问题#Telnet 诞生于终端机型五花八门的年代:这台机器回车是 CR,那台是 LF,还有机器退格键发的是 DEL。如果让每台客户端去适配所有远端终端,组合爆炸。Telnet 的解法见 1. 工作原理,核心是用一个"标准虚拟终端"做中转,再用"按需协商"叠加高级能力。
工作流程(简化版)#客户端与服务端先完成 TCP 三次握手(端口 23)。双方用 IAC 命令互相"商量"能力:要不要远端回显、要不要传窗口大小、传什么终端类型。协商出字符模式后,你每敲一个键,Telnet 就发一个字节过去,由服务端回显。登录与后续所有命令、输出都以明文字节流传输。想中断就发 IAC IP(Ctrl+C)并借 TCP 紧急指针抢插进去;想退出就发 exit。报文 / 头部长什么样#看这张表前先记住:Telnet 没有固定头部。它是纯字节流协议,控制信息通过 IAC (Interpret As Command, 0xFF/255) 转义嵌入数据流。所以下面"报文"其实是"命令字节表",而不是某个分层头部。
Telnet 建立在三个核心概念之上(RFC 854):
1.1 网络虚拟终端(NVT)#双方不直接理解对方的物理终端,而是各自与一台想象中的标准终端对话:
字符集:7 位 US-ASCII,装在 8 位字节里传输,高位置 0(启用 BINARY 选项后才允许 8 位)。打印机模型:无限宽行、无限长页,收到不认识的控制码应忽略。换行约定:CR LF(0x0D 0x0A) 表示换行;单独的 CR 必须写成 CR NUL(0x0D 0x00)——这条规则是 Telnet 与其他文本协议互操作时的经典坑。必需控制码:NUL、LF、CR、BEL(7)、BS(8)、HT(9)、VT(11)、FF(12)。1.2 协商原则:“商定的选项”#RFC 854 的设计哲学:协议核心保持最小,能力通过选项按需叠加,且遵守两条防死循环规则:
只有在改变状态时才发送请求;已处于目标状态时收到请求不再回应。收到请求必须回应(同意或拒绝),但同意后不得再重复请求。1.3 对称性#客户端与服务端在协议层完全对等,任何一方都能发起协商。实际部署中的角色差异(谁提供 shell)由上层决定。
1.4 典型运行模式#模式协商组合行为半双工行模式(原始默认)无 ECHO、无 SGA,用 GA 交替控制逐行发送,效率高但交互差;现代几乎不用字符模式(character-at-a-time,最常见)服务端 WILL ECHO + 双方 SUPPRESS-GO-AHEAD每敲一个键立即发一个 TCP 包,由服务端回显;vi、Tab 补全等交互功能可用;小包极多行模式(LINEMODE,RFC 1184)双方协商 LINEMODE客户端本地编辑整行,回车后一次性发送;省包但需要客户端支持本地回显行模式客户端 ECHO,服务端不回显老式设备/BBS 常见抓包判断技巧:一次连接里出现大量 1 字节 payload 的 TCP 包 → 字符模式;出现整行文本的包 → 行模式。
2.1 IAC 命令码表(RFC 854)#十进制十六进制名称含义2550xFFIAC命令解释引导符;数据中的 0xFF 需写成 IAC IAC2540xFEDON’T要求对方停止使用某选项2530xFDDO要求对方启用某选项2520xFCWON’T声明自己不会使用某选项2510xFBWILL声明自己将要使用某选项2500xFASB子协商开始(Subnegotiation Begin)2490xF9GAGo Ahead,半双工下交出发送权2480xF8ELErase Line,擦除当前行2470xF7ECErase Character,擦除前一字符2460xF6AYTAre You There,探活(服务端通常回一行提示)2450xF5AOAbort Output,丢弃尚未送达的输出2440xF4IPInterrupt Process,中断进程(对应 Ctrl+C)2430xF3BRKBreak,映射到终端 BREAK 键2420xF2DMData Mark,Synch 的同步标记,配合 TCP 紧急指针2410xF1NOP无操作2400xF0SE子协商结束(Subnegotiation End)2.2 命令格式#形式字节序列说明双字节命令IAC
2
3
4
5
6
7
FF FA 1F 00 50 00 18 FF F0
│ │ │ └─┬─┘ └─┬─┘ │ └── SE 子协商结束
│ │ │ │ └───────── 高16位行数 = 0x0018 = 24
│ │ │ └─────────────── 高16位列数 = 0x0050 = 80
│ │ └──────────────────── 选项 31 (0x1F) = NAWS
│ └─────────────────────── SB 子协商开始
└────────────────────────── IAC
交互时序#一句话看懂这张图:从 TCP 建连 → 选项协商进入字符模式 → 明文登录(连口令都是明文)→ 逐字符交互 → 用 IAC IP + TCP 紧急指针中断 → 退出,全过程没有任何加密。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
sequenceDiagram
autonumber
participant C as 客户端 (telnet)
participant S as 服务端 (telnetd:23)
Note over C,S: ① TCP 建连
C->>S: TCP 三次握手 (23)
Note over C,S: ② 选项协商(进入字符模式)
S->>C: IAC DO TERMINAL-TYPE (FF FD 18)
C->>S: IAC WILL TERMINAL-TYPE (FF FB 18)
S->>C: IAC SB TERMINAL-TYPE SEND IAC SE
C->>S: IAC SB TERMINAL-TYPE IS "xterm" IAC SE
S->>C: IAC DO NAWS (FF FD 1F)
C->>S: IAC WILL NAWS + IAC SB NAWS 80x24 IAC SE
S->>C: IAC WILL SUPPRESS-GO-AHEAD (FF FB 03)
C->>S: IAC DO SUPPRESS-GO-AHEAD (FF FD 03)
S->>C: IAC WILL ECHO (FF FB 01)
C->>S: IAC DO ECHO (FF FD 01)
Note right of C: 此后:客户端不本地回显
逐字符发送,由服务端回显
Note over C,S: ③ 登录(全部明文!)
S->>C: "Ubuntu 22.04 LTS\r\nlogin: "
C->>S: 'a' (1 字节)
S->>C: 'a' (回显)
C->>S: 'l' → 回显 'l' … 逐字符
C->>S: CR LF
S->>C: "Password: "
Note right of S: 服务端此时发 IAC WON'T ECHO
使客户端不回显口令(仅本地不显示)
C->>S: 'p','a','s','s' … (**明文上网,抓包可读**)
C->>S: CR LF
S->>C: "Last login: ...\r\n$ "
Note over C,S: ④ 交互会话
loop 每个按键
C->>S: 单字符
S->>C: 回显 + 命令输出
end
Note over C,S: ⑤ 中断(Ctrl+C)
C->>S: IAC IP (FF F4)
C->>S: IAC DM (FF F2) + TCP URG 紧急指针
S->>C: 丢弃缓冲输出,回到提示符
Note over C,S: ⑥ 结束
C->>S: "exit" CR LF
S->>C: "logout" + TCP FIN
关键机制 / 变体#4.1 协商防死循环规则(RFC 854 的精髓)#这是干什么的:防止双方就同一个选项无限来回确认,把连接变成"乒乓死循环"。
若无约束,A 发 WILL X、B 回 DO X、A 又回 WILL X……会无限循环。RFC 854 规定:
只在状态改变时发请求:若已启用某选项,不再重复发 WILL。收到请求必须应答:DO↔WILL/WON'T,WILL↔DO/DON'T。应答不触发新请求:收到的是对自己请求的应答时,不再回应。拒绝方向不可逆:一方 WON'T,另一方只能 DON'T(无法强迫对方启用)。四元组的语义要点:WILL/WON'T 说的是**“我”要不要做;DO/DON'T 说的是“你”**要不要做。
4.2 ECHO 的三种组合#这是干什么的:决定"你敲的字符由谁显示出来",直接决定输入口令时屏幕为什么是黑的。
组合效果场景服务端 WILL ECHO远端回显,客户端关本地回显Unix 交互 shell(最常见)服务端 WON'T ECHO客户端本地回显输入口令时服务端临时切到此状态(所以你看不到 *)双方都不回显屏幕无显示密码输入的实际状态注意:口令"看不见"只是本地不显示,网络上依然是明文字节。
4.3 Synch 机制(IAC DM + TCP URG)#这是干什么的:当你按 Ctrl+C 想立刻停下程序时,服务端可能还有一屏幕没发完的输出堆在缓冲里——Synch 让"中断命令"能插队到这些数据前面被立刻处理。
用户按 Ctrl+C 时,服务端可能还有大量未发完的输出堆在缓冲里。Telnet 的解法:
客户端发 IAC IP(中断进程);紧接着发 IAC DM,并把 TCP 紧急指针(URG) 指向 DM 字节;服务端 TCP 收到紧急数据后进入"紧急模式",丢弃数据流直到 DM,只处理其中的 Telnet 命令;DM 之后恢复正常处理。这是应用协议少见地直接依赖 TCP 紧急指针的例子。
4.4 为什么 Telnet 不安全(六条)#这是干什么的:说明为什么今天 Telnet 必须被 SSH 取代——它不是"不够好",而是从设计上就毫无保密与认证能力。
风险说明明文口令同网段 ARP 欺骗 / 交换机镜像 / 上游任意节点均可抓取;Wireshark 有 “Follow TCP Stream” 一键还原明文会话内容命令与输出(包括查看的配置、密钥)全部暴露无服务端认证无法确认对端身份,中间人可完整代理并篡改无完整性保护攻击者可注入字节,实现命令注入(TCP 序号已知时的会话劫持)会话劫持经典 hunt/juggernaut 类工具即针对 Telnet 设计环境变量注入NEW-ENVIRON 曾被用于传递 USER/LD_PRELOAD 绕过认证(如 CVE-2011-4862 之外的多起 telnetd 漏洞)历史上 telnetd 还爆出过多个远程预认证溢出漏洞(如 FreeBSD/Heimdal telnetd 的 encrypt_keyid 溢出 CVE-2011-4862),进一步坐实其淘汰命运。
4.5 与 SSH 的对应关系#这是干什么的:帮你把"老的 Telnet 概念"直接映射到"新的 SSH 概念",理解 SSH 其实继承了 Telnet 的远程终端语义。
SSH 保留了 Telnet 的诸多语义并将其结构化:
Telnet 机制SSH 对应TERMINAL-TYPE 子协商CHANNEL_REQUEST "pty-req" 中的 TERM 字段NAWS 窗口大小pty-req 的行列参数 + window-change 请求ECHO / SGA 等终端模式pty-req 的 encoded terminal modes(沿用 Telnet 的模式编号思路)IAC IP 中断信号通过 CHANNEL_REQUEST "signal" 传递明文口令加密通道内的 password 认证方法常见误区#“输入口令时屏幕不显示,说明口令被加密了。” 错。那只是服务端发了 IAC WON'T ECHO 让客户端停止本地回显,是显示层面的事;口令字节在网络上仍是明文,抓包直接可读。“telnet 能连上 = 服务健康。” 错。能连上只证明 TCP 三次握手成功(网络通 + 端口有监听 + 没被拦);应用层服务本身可能已挂。“Telnet 传的是带格式的报文。” 错。Telnet 没有固定头部,是纯字节流,控制靠 IAC 转义;所谓"报文"是 IAC 命令字节序列。“看不懂的乱码是 Telnet 坏了。” 不一定。多半是对端是二进制协议(MySQL/SSH/TLS),被 NVT 当 ASCII 解释;或没协商 BINARY 就传了中文。“NEW-ENVIRON、AUTHENTICATION、ENCRYPTION 选项很常用。” 错。认证与加密扩展实现率极低且有历史漏洞;真正常见的是 ECHO/SGA/TERMINAL-TYPE/NAWS/LINEMODE。速记口诀#无头纯流 IAC 引:Telnet 没有固定头部,是纯字节流,看到 0xFF(IAC) 后面就是命令。WILL 说我 DO 说你:WILL/WON'T 讲自己要不要做,DO/DON'T 要求对方做;配对 WILL↔DO/DON'T、DO↔WILL/WON'T。明文二字定生死:口令、内容全明文、无服务端认证、无完整性——这就是被 SSH 取代的全部理由。CR LF 换行 CR NUL 单回车:NVT 换行约定是经典互操作坑,记住这两对。知识框架# 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
mindmap
root((Telnet 远程终端协议))
基础模型
NVT 网络虚拟终端
7位ASCII
CR LF 换行
CR NUL 单回车
打印机抽象
对称协议
带内控制 IAC 转义
命令体系
IAC 255
WILL 251 WONT 252
DO 253 DONT 254
SB 250 SE 240
IP 244 中断
AO 245 AYT 246
EC 247 EL 248
DM 242 Synch
GA 249
常用选项
0 BINARY
1 ECHO
3 SUPPRESS-GO-AHEAD
24 TERMINAL-TYPE
31 NAWS 窗口大小
34 LINEMODE
39 NEW-ENVIRON
37/38 认证与加密 罕见
运行模式
半双工行模式 GA
字符模式 ECHO+SGA
LINEMODE 行编辑
本地回显模式
协商规则
仅状态改变时请求
收到请求必应答
应答不再触发请求
拒绝方向不可逆
安全问题
口令明文
内容明文
无服务端认证
无完整性保护
会话劫持
telnetd 历史漏洞
应改用 SSH
现代用途
端口连通性探测
手工调试 HTTP/SMTP/POP3
老旧设备带内管理
MUD 文本游戏